add format, title

This commit is contained in:
VALLONGOL 2025-09-15 11:06:17 +02:00
parent e3fbb24ef4
commit 6f0ca29327
2 changed files with 47 additions and 20 deletions

View File

@ -1,4 +1,3 @@
import logging import logging
import traceback import traceback
from threading import Thread from threading import Thread
@ -36,7 +35,7 @@ class Downloader:
def __init__(self): def __init__(self):
self.progress_callback: Optional[Callable[[int], None]] = None self.progress_callback: Optional[Callable[[int], None]] = None
self.completion_callback: Optional[Callable[[Optional[str]], 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]): def _progress_hook(self, d: Dict[str, Any]):
if d["status"] == "downloading": if d["status"] == "downloading":
@ -48,16 +47,21 @@ class Downloader:
logger.info("yt-dlp finished downloading.") logger.info("yt-dlp finished downloading.")
def _get_formats_task(self, url: str): 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: try:
logger.info(f"Fetching formats for URL: {url}") logger.info(f"Fetching formats for URL: {url}")
ydl_opts = {"noplaylist": True} ydl_opts = {"noplaylist": True}
with yt_dlp.YoutubeDL(ydl_opts) as ydl: with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=False) 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 = [] formats = []
for f in info.get("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": if f.get("vcodec", "none") != "none" and f.get("ext") == "mp4":
note = "Progressive" if f.get("acodec", "none") != "none" else "Video Only" note = "Progressive" if f.get("acodec", "none") != "none" else "Video Only"
formats.append(VideoFormat( formats.append(VideoFormat(
@ -68,21 +72,20 @@ class Downloader:
note=note 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)) 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.") logger.info(f"Found {len(formats)} suitable formats.")
if self.formats_callback: if self.formats_callback:
self.formats_callback(formats) self.formats_callback(video_info, formats)
except Exception as e: except Exception as e:
error_message = f"Failed to fetch formats: {e}" error_message = f"Failed to fetch formats: {e}"
logger.error(error_message) logger.error(error_message)
logger.debug(traceback.format_exc()) logger.debug(traceback.format_exc())
if self.formats_callback: 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.""" """Starts the format fetching process in a new thread."""
self.formats_callback = formats_callback self.formats_callback = formats_callback
thread = Thread(target=self._get_formats_task, args=(url,), daemon=True) thread = Thread(target=self._get_formats_task, args=(url,), daemon=True)
@ -128,4 +131,4 @@ class Downloader:
thread = Thread( thread = Thread(
target=self._download_task, args=(url, download_path, format_id), daemon=True target=self._download_task, args=(url, download_path, format_id), daemon=True
) )
thread.start() thread.start()

View File

@ -1,8 +1,9 @@
import logging import logging
import tkinter as tk import tkinter as tk
from tkinter import ttk, filedialog, messagebox from tkinter import ttk, filedialog, messagebox
from tkinter.scrolledtext import ScrolledText 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.core.core import Downloader, VideoFormat
from downloaderyoutube.utils.logger import add_tkinter_handler, get_logger 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.download_path: Optional[str] = None
self.available_formats: List[VideoFormat] = [] 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.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) 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)) 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 ---
path_frame = ttk.Frame(self) path_frame = ttk.Frame(self)
path_frame.pack(fill=tk.X, pady=5) path_frame.pack(fill=tk.X, pady=5)
@ -120,25 +134,35 @@ class App(tk.Frame):
self.analyze_button.config(state="disabled") self.analyze_button.config(state="disabled")
self.download_button.config(state="disabled") self.download_button.config(state="disabled")
self.format_combobox.set("Analisi in corso...") 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) self.downloader.get_video_formats(url, self._on_formats_received)
def _on_formats_received(self, formats: Optional[List[VideoFormat]]): def _on_formats_received(self, video_info: Optional[Dict[str, Any]], formats: Optional[List[VideoFormat]]):
# This is called from a different thread, so we schedule GUI updates self.master.after(0, self._update_ui_after_analysis, video_info, formats)
self.master.after(0, self._update_formats_combobox, 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") self.analyze_button.config(state="normal")
if formats: if video_info and formats:
logger.info("Successfully fetched formats. Populating combobox.") 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.available_formats = formats
self.format_combobox["values"] = [str(f) for f in formats] self.format_combobox["values"] = [str(f) for f in formats]
self.format_combobox.current(0) self.format_combobox.current(0)
self.format_combobox.config(state="readonly")
self.download_button.config(state="normal") self.download_button.config(state="normal")
else: else:
logger.error("Failed to fetch video formats.") logger.error("Failed to fetch video info or formats.")
messagebox.showerror("Error", "Could not retrieve video formats. Check the URL and logs.") messagebox.showerror("Error", "Could not retrieve video information. Check the URL and logs.")
self.format_combobox.set("Analisi fallita.") self.format_combobox.set("Analisi fallita.")
self.format_combobox["values"] = [] 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): def start_download(self):
url = self.url_entry.get() url = self.url_entry.get()
@ -180,4 +204,4 @@ class App(tk.Frame):
if error_message: if error_message:
messagebox.showerror("Download Failed", error_message) messagebox.showerror("Download Failed", error_message)
else: else:
messagebox.showinfo("Success", "Video downloaded successfully!") messagebox.showinfo("Success", "Video downloaded successfully!")