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 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") 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) 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') # 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) 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() ) self.search_button.grid(row=0, column=2) self.search_frame.pack(side='top') # 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) 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()) ) self.download_button.grid(row=0, column=2) self.download_frame.pack(side='bottom') 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() 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") 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("", self.play_selected_music) self.music_tree.pack(fill='both', expand=True) 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"])) def search_and_display(self): query = self.search_entry.get() self.set_status(f"searching {query} on youtube...") 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() 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") def prompt_user_for_details(self,url, filename): if filename is None: filename='' 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(), "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