This commit is contained in:
2026-03-19 13:08:15 -07:00
parent 5cbc2c09df
commit cc9c1850a8
7 changed files with 340 additions and 55 deletions

View File

@@ -776,12 +776,14 @@ class YtDlpTool:
if not format_str or not isinstance(format_str, str):
return None
s = format_str.strip().lower()
raw = format_str.strip()
s = raw.lower()
if not s:
return None
# Strip trailing 'p' if present (e.g. 720p -> 720)
if s.endswith('p'):
explicit_height = s.endswith('p')
if explicit_height:
s = s[:-1]
# Heuristic: 240/360/480/720/1080/1440/2160 are common height inputs
@@ -802,13 +804,9 @@ class YtDlpTool:
# Format 480 ... none in common lists.
# Format 720 ... none.
# So if it looks like a standard resolution, treat as height constraint.
if val in {144, 240, 360, 480, 540, 720, 1080, 1440, 2160, 2880, 4320}:
return f"bestvideo[height<={val}]+bestaudio/best[height<={val}]"
# If user types something like 500, we can also treat as height constraint if > 100
if val >= 100 and val not in {133, 134, 135, 136, 137, 160, 242, 243, 244, 247, 248, 278, 394, 395, 396, 397, 398, 399}:
return f"bestvideo[height<={val}]+bestaudio/best[height<={val}]"
common_heights = {144, 240, 360, 480, 540, 720, 1080, 1440, 2160, 2880, 4320}
if explicit_height or val in common_heights:
return f"bestvideo[height<={val}]+bestaudio/best[height<={val}]"
return None
@@ -981,7 +979,7 @@ class YtDlpTool:
# Add browser cookies support "just in case" if no file found (best effort)
_add_browser_cookies_if_available(base_options)
# YouTube hardening: prefer browser cookies + mobile/web clients when available
# YouTube hardening: prefer browser cookies when available.
try:
netloc = urlparse(opts.url).netloc.lower()
except Exception:
@@ -999,18 +997,6 @@ class YtDlpTool:
base_options.pop("cookiefile", None)
debug("[ytdlp] Using browser cookies for YouTube; ignoring cookiefile")
extractor_args = base_options.get("extractor_args")
if not isinstance(extractor_args, dict):
extractor_args = {}
youtube_args = extractor_args.get("youtube")
if not isinstance(youtube_args, dict):
youtube_args = {}
if "player_client" not in youtube_args:
youtube_args["player_client"] = ["android", "web"]
debug("[ytdlp] Using YouTube player_client override: android, web")
extractor_args["youtube"] = youtube_args
base_options["extractor_args"] = extractor_args
# Special handling for format keywords explicitly passed in via options
if opts.ytdl_format == "audio":
try:
@@ -1988,23 +1974,12 @@ def download_media(opts: DownloadOptions, *, config: Optional[Dict[str, Any]] =
retry_attempted = True
try:
if not opts.quiet:
debug("yt-dlp hit HTTP 403; retrying with browser cookies + android/web player client")
debug("yt-dlp hit HTTP 403; retrying with browser cookies")
fallback_options = dict(ytdl_options)
fallback_options.pop("cookiefile", None)
_add_browser_cookies_if_available(fallback_options)
extractor_args = fallback_options.get("extractor_args")
if not isinstance(extractor_args, dict):
extractor_args = {}
youtube_args = extractor_args.get("youtube")
if not isinstance(youtube_args, dict):
youtube_args = {}
if "player_client" not in youtube_args:
youtube_args["player_client"] = ["android", "web"]
extractor_args["youtube"] = youtube_args
fallback_options["extractor_args"] = extractor_args
debug(
"[ytdlp] retry options: "
f"cookiefile={fallback_options.get('cookiefile')}, cookiesfrombrowser={fallback_options.get('cookiesfrombrowser')}, "