From 6f0ca29327b9321f04d9d1ccbff9df543291d4f6 Mon Sep 17 00:00:00 2001 From: VALLONGOL Date: Mon, 15 Sep 2025 11:06:17 +0200 Subject: [PATCH] add format, title --- downloaderyoutube/core/core.py | 21 +++++++++------- downloaderyoutube/gui/gui.py | 46 ++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/downloaderyoutube/core/core.py b/downloaderyoutube/core/core.py index 2ade40d..1cc8c1c 100644 --- a/downloaderyoutube/core/core.py +++ b/downloaderyoutube/core/core.py @@ -1,4 +1,3 @@ - import logging import traceback from threading import Thread @@ -36,7 +35,7 @@ class Downloader: def __init__(self): self.progress_callback: Optional[Callable[[int], None]] = None self.completion_callback: Optional[Callable[[Optional[str]], None]] = None - self.formats_callback: Optional[Callable[[Optional[List[VideoFormat]]], None]] = None + self.formats_callback: Optional[Callable[[Optional[Dict[str, Any]], Optional[List[VideoFormat]]], None]] = None def _progress_hook(self, d: Dict[str, Any]): if d["status"] == "downloading": @@ -48,16 +47,21 @@ class Downloader: logger.info("yt-dlp finished downloading.") def _get_formats_task(self, url: str): - """Task to fetch video formats in a thread.""" + """Task to fetch video formats and info in a thread.""" try: logger.info(f"Fetching formats for URL: {url}") ydl_opts = {"noplaylist": True} with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(url, download=False) + video_info = { + "title": info.get("title", "N/A"), + "uploader": info.get("uploader", "N/A"), + "duration_string": info.get("duration_string", "N/A"), + } + formats = [] for f in info.get("formats", []): - # We are interested in mp4 files that have video if f.get("vcodec", "none") != "none" and f.get("ext") == "mp4": note = "Progressive" if f.get("acodec", "none") != "none" else "Video Only" formats.append(VideoFormat( @@ -68,21 +72,20 @@ class Downloader: note=note )) - # Sort formats: progressive first, then by resolution formats.sort(key=lambda x: (x.note != "Progressive", -int(x.resolution.replace("p", "")) if x.resolution.replace("p", "").isdigit() else 0)) logger.info(f"Found {len(formats)} suitable formats.") if self.formats_callback: - self.formats_callback(formats) + self.formats_callback(video_info, formats) except Exception as e: error_message = f"Failed to fetch formats: {e}" logger.error(error_message) logger.debug(traceback.format_exc()) if self.formats_callback: - self.formats_callback(None) # Indicate failure + self.formats_callback(None, None) # Indicate failure - def get_video_formats(self, url: str, formats_callback: Callable[[Optional[List[VideoFormat]]], None]): + def get_video_formats(self, url: str, formats_callback: Callable[[Optional[Dict[str, Any]], Optional[List[VideoFormat]]], None]): """Starts the format fetching process in a new thread.""" self.formats_callback = formats_callback thread = Thread(target=self._get_formats_task, args=(url,), daemon=True) @@ -128,4 +131,4 @@ class Downloader: thread = Thread( target=self._download_task, args=(url, download_path, format_id), daemon=True ) - thread.start() + thread.start() \ No newline at end of file diff --git a/downloaderyoutube/gui/gui.py b/downloaderyoutube/gui/gui.py index 3e3dae2..f97d984 100644 --- a/downloaderyoutube/gui/gui.py +++ b/downloaderyoutube/gui/gui.py @@ -1,8 +1,9 @@ + import logging import tkinter as tk from tkinter import ttk, filedialog, messagebox from tkinter.scrolledtext import ScrolledText -from typing import Optional, List +from typing import Optional, List, Dict, Any from downloaderyoutube.core.core import Downloader, VideoFormat from downloaderyoutube.utils.logger import add_tkinter_handler, get_logger @@ -35,8 +36,13 @@ class App(tk.Frame): self.download_path: Optional[str] = None self.available_formats: List[VideoFormat] = [] + # StringVars for video info labels + self.title_var = tk.StringVar(value="Titolo: N/A") + self.uploader_var = tk.StringVar(value="Autore: N/A") + self.duration_var = tk.StringVar(value="Durata: N/A") + self.master.title("YouTube Downloader") - self.master.geometry("800x600") + self.master.geometry("800x650") # Increased height for new info panel self.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) @@ -57,6 +63,14 @@ class App(tk.Frame): ) self.analyze_button.pack(side=tk.LEFT, padx=(5, 0)) + # --- Video Info Panel --- + info_frame = ttk.LabelFrame(self, text="Informazioni Video") + info_frame.pack(fill=tk.X, pady=5, padx=2) + + ttk.Label(info_frame, textvariable=self.title_var).pack(anchor="w", padx=5) + ttk.Label(info_frame, textvariable=self.uploader_var).pack(anchor="w", padx=5) + ttk.Label(info_frame, textvariable=self.duration_var).pack(anchor="w", padx=5) + # --- Path Frame --- path_frame = ttk.Frame(self) path_frame.pack(fill=tk.X, pady=5) @@ -120,25 +134,35 @@ class App(tk.Frame): self.analyze_button.config(state="disabled") self.download_button.config(state="disabled") self.format_combobox.set("Analisi in corso...") + self.title_var.set("Titolo: Analisi in corso...") + self.uploader_var.set("Autore: Analisi in corso...") + self.duration_var.set("Durata: Analisi in corso...") self.downloader.get_video_formats(url, self._on_formats_received) - def _on_formats_received(self, formats: Optional[List[VideoFormat]]): - # This is called from a different thread, so we schedule GUI updates - self.master.after(0, self._update_formats_combobox, formats) + def _on_formats_received(self, video_info: Optional[Dict[str, Any]], formats: Optional[List[VideoFormat]]): + self.master.after(0, self._update_ui_after_analysis, video_info, formats) - def _update_formats_combobox(self, formats: Optional[List[VideoFormat]]): + def _update_ui_after_analysis(self, video_info: Optional[Dict[str, Any]], formats: Optional[List[VideoFormat]]): self.analyze_button.config(state="normal") - if formats: - logger.info("Successfully fetched formats. Populating combobox.") + if video_info and formats: + logger.info("Successfully fetched video info and formats.") + self.title_var.set(f"Titolo: {video_info['title']}") + self.uploader_var.set(f"Autore: {video_info['uploader']}") + self.duration_var.set(f"Durata: {video_info['duration_string']}") + self.available_formats = formats self.format_combobox["values"] = [str(f) for f in formats] self.format_combobox.current(0) + self.format_combobox.config(state="readonly") self.download_button.config(state="normal") else: - logger.error("Failed to fetch video formats.") - messagebox.showerror("Error", "Could not retrieve video formats. Check the URL and logs.") + logger.error("Failed to fetch video info or formats.") + messagebox.showerror("Error", "Could not retrieve video information. Check the URL and logs.") self.format_combobox.set("Analisi fallita.") self.format_combobox["values"] = [] + self.title_var.set("Titolo: N/A") + self.uploader_var.set("Autore: N/A") + self.duration_var.set("Durata: N/A") def start_download(self): url = self.url_entry.get() @@ -180,4 +204,4 @@ class App(tk.Frame): if error_message: messagebox.showerror("Download Failed", error_message) else: - messagebox.showinfo("Success", "Video downloaded successfully!") \ No newline at end of file + messagebox.showinfo("Success", "Video downloaded successfully!")