Fix YouTube downloads failing with "Requested format not available"

Root cause: two issues compounding.

1. extractor_args with player_client: ['android', 'web'] + skip: ['hls', 'dash']
   stripped all real audio formats. Android client returns HLS/DASH streams,
   skip removes them, leaving only storyboard thumbnails. bestaudio then fails
   because there's nothing valid to select.

2. Browser cookies (cookiesfrombrowser) cause authenticated YouTube sessions
   to return restricted format data for some videos. Same video works fine
   without cookies.

Fix:
- Removed all hardcoded player_client and skip overrides from 4 locations
  (download opts, connection check, search, retry). Let yt-dlp use its own
  defaults which are updated with each release.
- Retry strategy: attempt 1 uses cookies (respects user setting), attempt 2
  drops cookies (fixes auth-restricted formats), attempt 3 uses format 'best'
  as last resort.
- Updated user_agent to Chrome 131.
This commit is contained in:
Broque Thomas 2026-03-26 19:07:50 -07:00
parent de5e3f6b3f
commit 6a41f5c0d7

View file

@ -148,14 +148,7 @@ class YouTubeClient:
'preferredquality': '320',
}],
'progress_hooks': [self._progress_hook], # Track download progress
# Bot detection bypass options
'extractor_args': {
'youtube': {
'player_client': ['android', 'web'], # Try multiple clients
'skip': ['hls', 'dash'], # Skip problematic formats
}
},
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
'age_limit': None, # Don't skip age-restricted
}
@ -226,14 +219,7 @@ class YouTubeClient:
'quiet': True,
'no_warnings': True,
'extract_flat': True, # Don't download, just extract info
# Bot detection bypass
'extractor_args': {
'youtube': {
'player_client': ['android', 'web'],
'skip': ['hls', 'dash'],
}
},
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
@ -597,14 +583,7 @@ class YouTubeClient:
'no_warnings': True,
'extract_flat': True, # Fast mode: Don't fetch formats (massive speedup)
'default_search': 'ytsearch',
# Bot detection bypass (same as download options)
'extractor_args': {
'youtube': {
'player_client': ['android', 'web'],
'skip': ['hls', 'dash'],
}
},
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
}
# Add cookie support for search (avoids bot detection)
@ -956,19 +935,22 @@ class YouTubeClient:
download_opts['format'] = 'bestaudio/best'
download_opts['noplaylist'] = True
# On retry, try different player client
# On retry, try different strategies
if attempt == 1:
logger.info(f"🔄 Retry {attempt + 1}/{max_retries} with different player client")
download_opts['extractor_args'] = {
'youtube': {
'player_client': ['web'], # Try web-only on retry
'skip': ['hls', 'dash'],
# Drop browser cookies — authenticated sessions sometimes get restricted formats
if 'cookiesfrombrowser' in download_opts:
logger.info(f"🔄 Retry {attempt + 1}/{max_retries} without browser cookies")
download_opts.pop('cookiesfrombrowser', None)
else:
logger.info(f"🔄 Retry {attempt + 1}/{max_retries} with web_creator client")
download_opts['extractor_args'] = {
'youtube': { 'player_client': ['web_creator'] }
}
}
elif attempt >= 2:
logger.info(f"🔄 Retry {attempt + 1}/{max_retries} with 'best' format (video fallback)")
download_opts['format'] = 'best' # Fallback to best available (including video)
download_opts.pop('extractor_args', None) # Reset extractor args
download_opts['format'] = 'best'
download_opts.pop('cookiesfrombrowser', None)
download_opts.pop('extractor_args', None)
# Perform download