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

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("<Double-1>", 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