mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2026-03-23 18:22:09 +01:00
[ie/youtube] Fix --live-from-start support (#16254)
Closes #16237 Authored by: bashonly
This commit is contained in:
@@ -1939,7 +1939,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
formats = [f for f in formats if f.get('is_from_start')]
|
formats = [f for f in formats if f.get('is_from_start')]
|
||||||
|
|
||||||
def refetch_manifest(format_id, delay):
|
def refetch_manifest(itag, client_name, delay):
|
||||||
nonlocal formats, start_time, is_live
|
nonlocal formats, start_time, is_live
|
||||||
if time.time() <= start_time + delay:
|
if time.time() <= start_time + delay:
|
||||||
return
|
return
|
||||||
@@ -1954,20 +1954,20 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
is_live = live_status == 'is_live'
|
is_live = live_status == 'is_live'
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
def mpd_feed(format_id, delay):
|
def mpd_feed(itag, client_name, delay):
|
||||||
"""
|
"""
|
||||||
@returns (manifest_url, manifest_stream_number, is_live) or None
|
@returns (manifest_url, manifest_stream_number, is_live) or None
|
||||||
"""
|
"""
|
||||||
for retry in self.RetryManager(fatal=False):
|
for retry in self.RetryManager(fatal=False):
|
||||||
with lock:
|
with lock:
|
||||||
refetch_manifest(format_id, delay)
|
refetch_manifest(itag, client_name, delay)
|
||||||
|
|
||||||
f = next((f for f in formats if f['format_id'] == format_id), None)
|
f = next((f for f in formats if f.get('_itag') == itag and f.get('_client') == client_name), None)
|
||||||
if not f:
|
if not f:
|
||||||
if not is_live:
|
if not is_live:
|
||||||
retry.error = f'{video_id}: Video is no longer live'
|
retry.error = f'{video_id}: Video is no longer live'
|
||||||
else:
|
else:
|
||||||
retry.error = f'Cannot find refreshed manifest for format {format_id}{bug_reports_message()}'
|
retry.error = f'Cannot find refreshed manifest for format {itag}{bug_reports_message()}'
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Formats from ended premieres will be missing a manifest_url
|
# Formats from ended premieres will be missing a manifest_url
|
||||||
@@ -1980,7 +1980,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
|
|
||||||
for f in formats:
|
for f in formats:
|
||||||
f['is_live'] = is_live
|
f['is_live'] = is_live
|
||||||
gen = functools.partial(self._live_dash_fragments, video_id, f['format_id'],
|
gen = functools.partial(self._live_dash_fragments, video_id, f['_itag'], f['_client'],
|
||||||
live_start_time, mpd_feed, not is_live and f.copy())
|
live_start_time, mpd_feed, not is_live and f.copy())
|
||||||
if is_live:
|
if is_live:
|
||||||
f['fragments'] = gen
|
f['fragments'] = gen
|
||||||
@@ -1989,7 +1989,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
f['fragments'] = LazyList(gen({}))
|
f['fragments'] = LazyList(gen({}))
|
||||||
del f['is_from_start']
|
del f['is_from_start']
|
||||||
|
|
||||||
def _live_dash_fragments(self, video_id, format_id, live_start_time, mpd_feed, manifestless_orig_fmt, ctx):
|
def _live_dash_fragments(self, video_id, itag, client_name, live_start_time, mpd_feed, manifestless_orig_fmt, ctx):
|
||||||
FETCH_SPAN, MAX_DURATION = 5, 432000
|
FETCH_SPAN, MAX_DURATION = 5, 432000
|
||||||
|
|
||||||
mpd_url, stream_number, is_live = None, None, True
|
mpd_url, stream_number, is_live = None, None, True
|
||||||
@@ -2013,7 +2013,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
old_mpd_url = mpd_url
|
old_mpd_url = mpd_url
|
||||||
last_error = ctx.pop('last_error', None)
|
last_error = ctx.pop('last_error', None)
|
||||||
expire_fast = immediate or (last_error and isinstance(last_error, HTTPError) and last_error.status == 403)
|
expire_fast = immediate or (last_error and isinstance(last_error, HTTPError) and last_error.status == 403)
|
||||||
mpd_url, stream_number, is_live = (mpd_feed(format_id, 5 if expire_fast else 18000)
|
mpd_url, stream_number, is_live = (mpd_feed(itag, client_name, 5 if expire_fast else 18000)
|
||||||
or (mpd_url, stream_number, False))
|
or (mpd_url, stream_number, False))
|
||||||
if not refresh_sequence:
|
if not refresh_sequence:
|
||||||
if expire_fast and not is_live:
|
if expire_fast and not is_live:
|
||||||
@@ -2039,7 +2039,7 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
_last_seq = int(re.search(r'(?:/|^)sq/(\d+)', fragments[-1]['path']).group(1))
|
_last_seq = int(re.search(r'(?:/|^)sq/(\d+)', fragments[-1]['path']).group(1))
|
||||||
return True, _last_seq
|
return True, _last_seq
|
||||||
|
|
||||||
self.write_debug(f'[{video_id}] Generating fragments for format {format_id}')
|
self.write_debug(f'[{video_id}] Generating fragments for format {itag}')
|
||||||
while is_live:
|
while is_live:
|
||||||
fetch_time = time.time()
|
fetch_time = time.time()
|
||||||
if no_fragment_score > 30:
|
if no_fragment_score > 30:
|
||||||
@@ -3747,11 +3747,15 @@ class YoutubeIE(YoutubeBaseInfoExtractor):
|
|||||||
sub[STREAMING_DATA_CLIENT_NAME] = client_name
|
sub[STREAMING_DATA_CLIENT_NAME] = client_name
|
||||||
subtitles = self._merge_subtitles(subs, subtitles) # Prioritize HLS subs over DASH
|
subtitles = self._merge_subtitles(subs, subtitles) # Prioritize HLS subs over DASH
|
||||||
for f in formats:
|
for f in formats:
|
||||||
if process_manifest_format(f, 'dash', client_name, f['format_id'], require_po_token and not po_token):
|
# Save original itag value as format_id because process_manifest_format mutates f
|
||||||
|
format_id = f['format_id']
|
||||||
|
if process_manifest_format(f, 'dash', client_name, format_id, require_po_token and not po_token):
|
||||||
f['filesize'] = int_or_none(self._search_regex(
|
f['filesize'] = int_or_none(self._search_regex(
|
||||||
r'/clen/(\d+)', f.get('fragment_base_url') or f['url'], 'file size', default=None))
|
r'/clen/(\d+)', f.get('fragment_base_url') or f['url'], 'file size', default=None))
|
||||||
if needs_live_processing:
|
if needs_live_processing:
|
||||||
f['is_from_start'] = True
|
f['is_from_start'] = True
|
||||||
|
f['_itag'] = format_id
|
||||||
|
f['_client'] = client_name
|
||||||
yield f
|
yield f
|
||||||
yield subtitles
|
yield subtitles
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user