remove yt-dlp, fix captions PO Token issue, fix 429 retry logic
- Remove yt-dlp entirely (modules, routes, settings, dependency) Was blocking page loads by running synchronously in gevent - Fix captions: use Android client caption URLs (no PO Token needed) instead of web timedtext URLs that YouTube now blocks - Fix 429 retry: fail immediately without Tor (same IP = pointless retry) Was causing ~27s delays with exponential backoff - Accept ytdlp_enabled as legacy setting to avoid warning on startup
This commit is contained in:
@@ -180,8 +180,34 @@ def make_caption_src(info, lang, auto=False, trans_lang=None):
|
||||
label += ' (Automatic)'
|
||||
if trans_lang:
|
||||
label += ' -> ' + trans_lang
|
||||
|
||||
# Try to use Android caption URL directly (no PO Token needed)
|
||||
caption_url = None
|
||||
for track in info.get('_android_caption_tracks', []):
|
||||
track_lang = track.get('languageCode', '')
|
||||
track_kind = track.get('kind', '')
|
||||
if track_lang == lang and (
|
||||
(auto and track_kind == 'asr') or
|
||||
(not auto and track_kind != 'asr')
|
||||
):
|
||||
caption_url = track.get('baseUrl')
|
||||
break
|
||||
|
||||
if caption_url:
|
||||
# Add format
|
||||
if '&fmt=' in caption_url:
|
||||
caption_url = re.sub(r'&fmt=[^&]*', '&fmt=vtt', caption_url)
|
||||
else:
|
||||
caption_url += '&fmt=vtt'
|
||||
if trans_lang:
|
||||
caption_url += '&tlang=' + trans_lang
|
||||
url = util.prefix_url(caption_url)
|
||||
else:
|
||||
# Fallback to old method
|
||||
url = util.prefix_url(yt_data_extract.get_caption_url(info, lang, 'vtt', auto, trans_lang))
|
||||
|
||||
return {
|
||||
'url': util.prefix_url(yt_data_extract.get_caption_url(info, lang, 'vtt', auto, trans_lang)),
|
||||
'url': url,
|
||||
'label': label,
|
||||
'srclang': trans_lang[0:2] if trans_lang else lang[0:2],
|
||||
'on': False,
|
||||
@@ -387,6 +413,19 @@ def extract_info(video_id, use_invidious, playlist_id=None, index=None):
|
||||
info = tasks[0].value or {}
|
||||
player_response = tasks[1].value or {}
|
||||
|
||||
# Save android_vr caption tracks (no PO Token needed for these URLs)
|
||||
if isinstance(player_response, str):
|
||||
try:
|
||||
pr_data = json.loads(player_response)
|
||||
except Exception:
|
||||
pr_data = {}
|
||||
else:
|
||||
pr_data = player_response or {}
|
||||
android_caption_tracks = yt_data_extract.deep_get(
|
||||
pr_data, 'captions', 'playerCaptionsTracklistRenderer',
|
||||
'captionTracks', default=[])
|
||||
info['_android_caption_tracks'] = android_caption_tracks
|
||||
|
||||
yt_data_extract.update_with_new_urls(info, player_response)
|
||||
|
||||
# Fallback to 'ios' if no valid URLs are found
|
||||
@@ -696,30 +735,6 @@ def get_watch_page(video_id=None):
|
||||
pair_sources = source_info['pair_sources']
|
||||
uni_idx, pair_idx = source_info['uni_idx'], source_info['pair_idx']
|
||||
|
||||
# Extract audio tracks using yt-dlp for multi-language support
|
||||
audio_tracks = []
|
||||
try:
|
||||
from youtube import ytdlp_integration
|
||||
logger.info(f'Extracting audio tracks for video: {video_id}')
|
||||
ytdlp_info = ytdlp_integration.extract_video_info_ytdlp(video_id)
|
||||
audio_tracks = ytdlp_info.get('audio_tracks', [])
|
||||
|
||||
if audio_tracks:
|
||||
logger.info(f'✓ Found {len(audio_tracks)} audio tracks:')
|
||||
for i, track in enumerate(audio_tracks[:10], 1): # Log first 10
|
||||
logger.info(f' [{i}] {track["language_name"]} ({track["language"]}) - '
|
||||
f'bitrate: {track.get("audio_bitrate", "N/A")}k, '
|
||||
f'codec: {track.get("acodec", "N/A")}, '
|
||||
f'format_id: {track.get("format_id", "N/A")}')
|
||||
if len(audio_tracks) > 10:
|
||||
logger.info(f' ... and {len(audio_tracks) - 10} more')
|
||||
else:
|
||||
logger.warning(f'No audio tracks found for video {video_id}')
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Failed to extract audio tracks: {e}', exc_info=True)
|
||||
audio_tracks = []
|
||||
|
||||
pair_quality = yt_data_extract.deep_get(pair_sources, pair_idx, 'quality')
|
||||
uni_quality = yt_data_extract.deep_get(uni_sources, uni_idx, 'quality')
|
||||
|
||||
@@ -843,9 +858,7 @@ def get_watch_page(video_id=None):
|
||||
'playlist': info['playlist'],
|
||||
'related': info['related_videos'],
|
||||
'playability_error': info['playability_error'],
|
||||
'audio_tracks': audio_tracks,
|
||||
},
|
||||
audio_tracks = audio_tracks,
|
||||
font_family = youtube.font_choices[settings.font], # for embed page
|
||||
**source_info,
|
||||
using_pair_sources = using_pair_sources,
|
||||
@@ -854,16 +867,13 @@ def get_watch_page(video_id=None):
|
||||
|
||||
@yt_app.route('/api/<path:dummy>')
|
||||
def get_captions(dummy):
|
||||
url = 'https://www.youtube.com' + request.full_path
|
||||
try:
|
||||
result = util.fetch_url('https://www.youtube.com' + request.full_path)
|
||||
result = util.fetch_url(url, headers=util.mobile_ua)
|
||||
result = result.replace(b"align:start position:0%", b"")
|
||||
return result
|
||||
except util.FetchError as e:
|
||||
# Return empty captions gracefully instead of error page
|
||||
logger.warning(f'Failed to fetch captions: {e}')
|
||||
return flask.Response(b'WEBVTT\n\n', mimetype='text/vtt', status=200)
|
||||
return flask.Response(result, mimetype='text/vtt')
|
||||
except Exception as e:
|
||||
logger.error(f'Unexpected error fetching captions: {e}')
|
||||
logger.debug(f'Caption fetch failed: {e}')
|
||||
return flask.Response(b'WEBVTT\n\n', mimetype='text/vtt', status=200)
|
||||
|
||||
|
||||
@@ -929,18 +939,3 @@ def get_transcript(caption_path):
|
||||
|
||||
return flask.Response(result.encode('utf-8'),
|
||||
mimetype='text/plain;charset=UTF-8')
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# yt-dlp Integration Routes
|
||||
# ============================================================================
|
||||
|
||||
@yt_app.route('/ytl-api/video-with-audio/<video_id>')
|
||||
def proxy_video_with_audio(video_id):
|
||||
"""
|
||||
Proxy para servir video con audio específico usando yt-dlp
|
||||
"""
|
||||
from youtube import ytdlp_proxy
|
||||
audio_lang = request.args.get('lang', 'en')
|
||||
max_quality = int(request.args.get('quality', 720))
|
||||
return ytdlp_proxy.stream_video_with_audio(video_id, audio_lang, max_quality)
|
||||
|
||||
Reference in New Issue
Block a user