From 39a117f08bbd21f159ea5b0248da15ee6e338d09 Mon Sep 17 00:00:00 2001 From: luciano Date: Wed, 19 Aug 2026 15:30:46 +0200 Subject: [PATCH] feat: cookies-from-browser per bypass HTTP 403 YouTube (v1.10.1) Alcuni video YouTube restituiscono 403 anche con yt-dlp aggiornato. Fix: nuova opzione Impostazioni "Cookies da browser" con dropdown (chrome/safari/firefox/edge/brave). Priorita': file cookies.txt esistente -> --cookies-from-browser -> nessuno. Bonus: - core/paths.py::_bundle_dirs() ora include /bundle_bin/ anche in dev, cosi' python main.py usa lo stesso yt-dlp del build invece di Homebrew (spesso obsoleto) - Helper _cookie_args() in downloader.py per non ripetere la logica su tutti i punti dove serve --cookies --- api/bridge.py | 1 + core/config.py | 3 ++- core/downloader.py | 44 ++++++++++++++++++++++++++++++-------------- core/paths.py | 7 +++++++ webui/index.html | 18 ++++++++++++++++++ webui/js/app.js | 2 ++ 6 files changed, 60 insertions(+), 15 deletions(-) diff --git a/api/bridge.py b/api/bridge.py index 56ef704..2843974 100644 --- a/api/bridge.py +++ b/api/bridge.py @@ -170,6 +170,7 @@ class Api: "bitrate": payload.get("bitrate", "320K"), "hq_threshold": threshold, "cookies_path": (payload.get("cookies_path") or "").strip(), + "cookies_browser": (payload.get("cookies_browser") or "").strip().lower(), "output_dir": (payload.get("output_dir") or "").strip(), "theme": payload.get("theme", "dark"), }) diff --git a/core/config.py b/core/config.py index e74b559..fcb8dd8 100644 --- a/core/config.py +++ b/core/config.py @@ -5,7 +5,7 @@ import os import sys from pathlib import Path -VERSION = "v1.10.0" +VERSION = "v1.10.1" APP_NAME = "MusicTools" @@ -68,6 +68,7 @@ DEFAULTS = { "bitrate": "320K", "hq_threshold": 310, "cookies_path": str(_project_dir / "cookies.txt"), + "cookies_browser": "", # "" | chrome | safari | firefox | edge | brave "output_dir": str(_project_dir / "MUSICA"), "theme": "dark", # ---- Beatport ---- diff --git a/core/downloader.py b/core/downloader.py index 0aa1a1f..2f3ded0 100644 --- a/core/downloader.py +++ b/core/downloader.py @@ -12,6 +12,29 @@ from typing import Callable, Optional from core.paths import find_ytdlp, find_ffmpeg_dir, subprocess_flags +_ALLOWED_BROWSERS = {"chrome", "safari", "firefox", "edge", "brave", "chromium", "opera", "vivaldi"} + + +def _cookie_args(cookies_path: Optional[str]) -> list: + """Ritorna gli argomenti yt-dlp per i cookies. + + Priorità: file cookies_path se esiste → altrimenti --cookies-from-browser + se `cookies_browser` è settato in config → altrimenti niente. + """ + if cookies_path and Path(cookies_path).exists(): + return ["--cookies", cookies_path] + # Fallback: legge il browser dalla config al volo (evita di cambiare + # firma di tutte le funzioni download_*) + try: + from core.config import load_config + browser = (load_config().get("cookies_browser") or "").strip().lower() + except Exception: + browser = "" + if browser in _ALLOWED_BROWSERS: + return ["--cookies-from-browser", browser] + return [] + + # Flag globale per interruzione _stop_event = threading.Event() _current_process: Optional[subprocess.Popen] = None @@ -99,8 +122,7 @@ def _search_youtube(query: str, cookies_path: Optional[str] = None) -> tuple[str "--no-warnings", "--flat-playlist", ] - if cookies_path and Path(cookies_path).exists(): - cmd.extend(["--cookies", cookies_path]) + cmd.extend(_cookie_args(cookies_path)) result = subprocess.run(cmd, capture_output=True, text=True, timeout=30, **subprocess_flags()) if result.returncode != 0: @@ -216,8 +238,7 @@ def download_playlist( ffmpeg_dir = find_ffmpeg_dir() if ffmpeg_dir: cmd.extend(["--ffmpeg-location", ffmpeg_dir]) - if cookies_path and Path(cookies_path).exists(): - cmd.extend(["--cookies", cookies_path]) + cmd.extend(_cookie_args(cookies_path)) try: with _process_lock: @@ -300,8 +321,7 @@ def download_direct_url( "--no-warnings", url, ] - if cookies_path and Path(cookies_path).exists(): - probe_cmd.extend(["--cookies", cookies_path]) + probe_cmd.extend(_cookie_args(cookies_path)) try: result = subprocess.run(probe_cmd, capture_output=True, text=True, timeout=60, **subprocess_flags()) @@ -375,8 +395,7 @@ def download_direct_url( ffmpeg_dir = find_ffmpeg_dir() if ffmpeg_dir: cmd.extend(["--ffmpeg-location", ffmpeg_dir]) - if cookies_path and Path(cookies_path).exists(): - cmd.extend(["--cookies", cookies_path]) + cmd.extend(_cookie_args(cookies_path)) try: with _process_lock: @@ -511,8 +530,7 @@ def download_urls( ffmpeg_dir = find_ffmpeg_dir() if ffmpeg_dir: cmd.extend(["--ffmpeg-location", ffmpeg_dir]) - if cookies_path and Path(cookies_path).exists(): - cmd.extend(["--cookies", cookies_path]) + cmd.extend(_cookie_args(cookies_path)) try: with _process_lock: @@ -608,8 +626,7 @@ def download_video( probe_cmd = [ ytdlp, "--dump-json", "--flat-playlist", "--no-download", "--no-warnings", url, ] - if cookies_path and Path(cookies_path).exists(): - probe_cmd.extend(["--cookies", cookies_path]) + probe_cmd.extend(_cookie_args(cookies_path)) try: result = subprocess.run(probe_cmd, capture_output=True, text=True, timeout=60, **subprocess_flags()) @@ -684,8 +701,7 @@ def download_video( ffmpeg_dir = find_ffmpeg_dir() if ffmpeg_dir: cmd.extend(["--ffmpeg-location", ffmpeg_dir]) - if cookies_path and Path(cookies_path).exists(): - cmd.extend(["--cookies", cookies_path]) + cmd.extend(_cookie_args(cookies_path)) try: with _process_lock: diff --git a/core/paths.py b/core/paths.py index bd066a0..86ed30c 100644 --- a/core/paths.py +++ b/core/paths.py @@ -45,6 +45,13 @@ def _bundle_dirs() -> list[Path]: sub_macos = frameworks / sub / "Contents" / "MacOS" if sub_macos.exists(): dirs.append(sub_macos) + else: + # Dev: cerca in /bundle_bin/ così `python main.py` + # usa gli stessi binari del bundle (aggiornati via build_*.py) + # invece di Homebrew/PATH che possono essere obsoleti. + project_bundle = Path(__file__).resolve().parent.parent / "bundle_bin" + if project_bundle.exists(): + dirs.append(project_bundle) return dirs diff --git a/webui/index.html b/webui/index.html index 914614d..30fd24b 100644 --- a/webui/index.html +++ b/webui/index.html @@ -563,6 +563,24 @@ +
+ +
+ +
+
+ ⓘ +
Alcuni video YouTube (musica protetta, region-lock, età) danno HTTP 403 senza cookies autenticati. Selezionando un browser, l'app legge i cookies dal tuo profilo — richiede che tu sia loggato su YouTube in quel browser. Se hai anche cookies.txt sopra, ha priorità il file.
+
+
+
diff --git a/webui/js/app.js b/webui/js/app.js index f0d3fb5..8be3ebd 100644 --- a/webui/js/app.js +++ b/webui/js/app.js @@ -485,6 +485,7 @@ async function init() { $("#bitrateSelect").value = state.config.bitrate || "320K"; $("#hqThresholdInput").value = state.config.hq_threshold || 310; $("#cookiesInput").value = state.config.cookies_path || ""; + if ($("#cookiesBrowserSelect")) $("#cookiesBrowserSelect").value = state.config.cookies_browser || ""; $("#outputInput").value = state.config.output_dir || ""; $("#themeSelect").value = state.config.theme || "dark"; applyTheme(state.config.theme); @@ -1293,6 +1294,7 @@ $("#saveBtn").addEventListener("click", async () => { bitrate: $("#bitrateSelect").value, hq_threshold: parseInt($("#hqThresholdInput").value, 10) || 310, cookies_path: $("#cookiesInput").value, + cookies_browser: $("#cookiesBrowserSelect") ? $("#cookiesBrowserSelect").value : "", output_dir: $("#outputInput").value, theme: $("#themeSelect").value, };