You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
6.7 KiB
Python

11 months ago
import tkinter as tk
from tkinter import ttk
import tkinter.simpledialog as sd
import time
import os
import pygame
from config import name, ui_size,colors, youtube_prefix, audio_codec
11 months ago
from utils import search_youtube, download_audio
class UIEngine:
def __init__(self, db):
self.db = db
self.root = tk.Tk()
self.root.title(name)
self.root.geometry(ui_size)
self.status_label = tk.Label(self.root, text="ready")
11 months ago
self.status_label.pack()
self.notebook = ttk.Notebook(self.root)
self.notebook.pack(fill='both', expand=True)
self.create_search_tab()
self.create_database_tab(db)
pygame.init()
def set_status(self, status):
self.status_label.config(text=status)
self.root.update()
def add_to_db(self, entry):
self.db.add_entry(entry)
11 months ago
def run(self):
self.root.mainloop()
def create_search_tab(self):
search_tab = ttk.Frame(self.notebook)
self.notebook.add(search_tab, text='search & download')
11 months ago
# search_frame
self.search_frame = ttk.Frame(search_tab)
self.search_label = tk.Label(self.search_frame, text="search youtube videos:")
self.search_label.grid(row=0, column=0)
11 months ago
self.search_entry = tk.Entry(self.search_frame)
self.search_entry.grid(row=0, column=1)
self.search_button = tk.Button(
self.search_frame,
text="Search",
background=colors['SearchButton'],
command=lambda: self.search_and_display()
)
11 months ago
self.search_button.grid(row=0, column=2)
self.search_frame.pack(side='top')
11 months ago
# results frame
self.results_frame = ttk.Frame(search_tab)
self.results_frame.pack()
# download frame
self.download_frame = ttk.Frame(search_tab)
self.download_label = tk.Label(self.download_frame, text="...or directly enter a youtube URL to download:")
self.download_label.grid(row=0, column=0)
11 months ago
self.download_entry = tk.Entry(self.download_frame)
self.download_entry.grid(row=0,column=1)
self.download_button = tk.Button(
self.download_frame,
text="Download",
background=colors['DownloadButton'],
command=lambda: self.handle_download(self.download_entry.get())
)
11 months ago
self.download_button.grid(row=0, column=2)
self.download_frame.pack(side='bottom')
11 months ago
def play_selected_music(self, event):
item = self.music_tree.selection()[0]
filename = f"{self.db.base_path}/audios/{self.music_tree.item(item, 'values')[2]}.{audio_codec}"
if pygame.mixer.music.get_busy() and pygame.mixer.music.get_pos() > 0:
pygame.mixer.music.stop()
else:
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
11 months ago
def create_database_tab(self, db):
self.database_tab = ttk.Frame(self.notebook)
self.notebook.add(self.database_tab, text='available music')
self.music_tree = ttk.Treeview(self.database_tab, columns=("title", "artist", "filename", "tags", "timestamp"))
self.music_tree.heading("#0", text="ID")
self.music_tree.heading("title", text="Title")
self.music_tree.heading("artist", text="Artist")
self.music_tree.heading("filename", text="Filename")
self.music_tree.heading("tags", text="Tags")
self.music_tree.heading("timestamp", text="Timestamp")
11 months ago
for entry in db.get_all_entries():
self.music_tree.insert("", "end", text=entry["id"], values=(entry["title"], entry["artist"], entry["filename"], ", ".join(entry["tags"]), entry["timestamp"]))
self.music_tree.bind("<Double-1>", self.play_selected_music)
self.music_tree.pack(fill='both', expand=True)
11 months ago
def update_database_tab(self, entry):
tree = self.notebook.winfo_children()[1].winfo_children()[0] # Access the treeview in the database tab
tree.insert("", "end", text=entry["id"], values=(entry["title"], entry["artist"], entry["filename"], ", ".join(entry["tags"]), entry["timestamp"]))
11 months ago
def search_and_display(self):
query = self.search_entry.get()
self.set_status(f"searching {query} on youtube...")
11 months ago
for widget in self.results_frame.winfo_children():
widget.destroy()
results = search_youtube(query)
result_label = tk.Label(self.results_frame, text="choose from the list and click to download:")
result_label.pack()
11 months ago
for i, result in enumerate(results):
text = result['title']
state = 'active'
if not self.db.downloadable(result['webpage_url'], result['title']):
text = f'celaigia : {text}'
state = 'disabled'
result_button = tk.Button(
self.results_frame,
text=text,
background=colors['DownloadButton'],
command=lambda url=result['webpage_url'], filename=result['title']: self.handle_download(url, filename)
)
result_button.pack()
result_button.configure(state=state)
self.set_status("ready")
def handle_download(self, url, filename=None):
local_path = f"{self.db.base_path}/audios/{filename}.{audio_codec}"
self.set_status(f"downloading to {local_path} ...")
success = download_audio(url, self.db.base_path)
if success:
self.set_status("download completed, waiting for user prompt and then adding to db")
try:
entry = self.prompt_user_for_details(url, filename)
self.add_to_db(entry)
self.update_database_tab(entry)
for widget in self.results_frame.winfo_children():
if widget['text'] == entry['filename']:
widget['text'] = f"celaigia : {widget['text']}"
widget.configure(state='disabled')
except:
if os.path.exists(local_path):
os.remove(local_path)
self.set_status("ready")
11 months ago
def prompt_user_for_details(self,url, filename):
if filename is None:
filename=''
11 months ago
title = sd.askstring("Enter Title", "Enter Title:", initialvalue=filename)
artist = sd.askstring("Enter Artist", "Enter Artist:")
tags = sd.askstring("Enter Tags", "Enter Tags (comma separated):")
entry = {
"id": url.split(youtube_prefix)[-1].strip(),
11 months ago
"title": title.strip(),
"artist": artist.strip(),
"filename": filename.strip(),
"tags": [tag.strip() for tag in tags.split(",")] if tags else [],
"timestamp": time.time()
}
return entry