mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 14:45:14 +00:00 
			
		
		
		
	[youtube] End live-from-start properly when stream ends with 403
				
					
				
			Closes #2089
This commit is contained in:
		| @@ -433,6 +433,7 @@ class FragmentFD(FileDownloader): | |||||||
|  |  | ||||||
|         def download_fragment(fragment, ctx): |         def download_fragment(fragment, ctx): | ||||||
|             frag_index = ctx['fragment_index'] = fragment['frag_index'] |             frag_index = ctx['fragment_index'] = fragment['frag_index'] | ||||||
|  |             ctx['last_error'] = None | ||||||
|             if not interrupt_trigger[0]: |             if not interrupt_trigger[0]: | ||||||
|                 return False, frag_index |                 return False, frag_index | ||||||
|             headers = info_dict.get('http_headers', {}).copy() |             headers = info_dict.get('http_headers', {}).copy() | ||||||
| @@ -455,6 +456,7 @@ class FragmentFD(FileDownloader): | |||||||
|                     # See https://github.com/ytdl-org/youtube-dl/issues/10165, |                     # See https://github.com/ytdl-org/youtube-dl/issues/10165, | ||||||
|                     # https://github.com/ytdl-org/youtube-dl/issues/10448). |                     # https://github.com/ytdl-org/youtube-dl/issues/10448). | ||||||
|                     count += 1 |                     count += 1 | ||||||
|  |                     ctx['last_error'] = err | ||||||
|                     if count <= fragment_retries: |                     if count <= fragment_retries: | ||||||
|                         self.report_retry_fragment(err, frag_index, count, fragment_retries) |                         self.report_retry_fragment(err, frag_index, count, fragment_retries) | ||||||
|                 except DownloadError: |                 except DownloadError: | ||||||
|   | |||||||
| @@ -1777,16 +1777,15 @@ class YoutubeIE(YoutubeBaseInfoExtractor): | |||||||
|         self._player_cache = {} |         self._player_cache = {} | ||||||
|  |  | ||||||
|     def _prepare_live_from_start_formats(self, formats, video_id, live_start_time, url, webpage_url, smuggled_data): |     def _prepare_live_from_start_formats(self, formats, video_id, live_start_time, url, webpage_url, smuggled_data): | ||||||
|         EXPIRATION_DURATION = 18_000 |  | ||||||
|         lock = threading.Lock() |         lock = threading.Lock() | ||||||
|  |  | ||||||
|         is_live = True |         is_live = True | ||||||
|         expiration_time = time.time() + EXPIRATION_DURATION |         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): |         def refetch_manifest(format_id, delay): | ||||||
|             nonlocal formats, expiration_time, is_live |             nonlocal formats, start_time, is_live | ||||||
|             if time.time() <= expiration_time: |             if time.time() <= start_time + delay: | ||||||
|                 return |                 return | ||||||
|  |  | ||||||
|             _, _, prs, player_url = self._download_player_responses(url, smuggled_data, video_id, webpage_url) |             _, _, prs, player_url = self._download_player_responses(url, smuggled_data, video_id, webpage_url) | ||||||
| @@ -1796,19 +1795,22 @@ class YoutubeIE(YoutubeBaseInfoExtractor): | |||||||
|                 prs, (..., 'microformat', 'playerMicroformatRenderer'), |                 prs, (..., 'microformat', 'playerMicroformatRenderer'), | ||||||
|                 expected_type=dict, default=[]) |                 expected_type=dict, default=[]) | ||||||
|             _, is_live, _, formats = self._list_formats(video_id, microformats, video_details, prs, player_url) |             _, is_live, _, formats = self._list_formats(video_id, microformats, video_details, prs, player_url) | ||||||
|             expiration_time = time.time() + EXPIRATION_DURATION |             start_time = time.time() | ||||||
|  |  | ||||||
|         def mpd_feed(format_id): |         def mpd_feed(format_id, delay): | ||||||
|             """ |             """ | ||||||
|             @returns (manifest_url, manifest_stream_number, is_live) or None |             @returns (manifest_url, manifest_stream_number, is_live) or None | ||||||
|             """ |             """ | ||||||
|             with lock: |             with lock: | ||||||
|                 refetch_manifest(format_id) |                 refetch_manifest(format_id, delay) | ||||||
|  |  | ||||||
|             f = next((f for f in formats if f['format_id'] == format_id), None) |             f = next((f for f in formats if f['format_id'] == format_id), None) | ||||||
|             if not f: |             if not f: | ||||||
|                 self.report_warning( |                 if not is_live: | ||||||
|                     f'Cannot find refreshed manifest for format {format_id}{bug_reports_message()}') |                     self.to_screen(f'{video_id}: Video is no longer live') | ||||||
|  |                 else: | ||||||
|  |                     self.report_warning( | ||||||
|  |                         f'Cannot find refreshed manifest for format {format_id}{bug_reports_message()}') | ||||||
|                 return None |                 return None | ||||||
|             return f['manifest_url'], f['manifest_stream_number'], is_live |             return f['manifest_url'], f['manifest_stream_number'], is_live | ||||||
|  |  | ||||||
| @@ -1839,9 +1841,15 @@ class YoutubeIE(YoutubeBaseInfoExtractor): | |||||||
|             nonlocal mpd_url, stream_number, is_live, no_fragment_score, fragments, fragment_base_url |             nonlocal mpd_url, stream_number, is_live, no_fragment_score, fragments, fragment_base_url | ||||||
|             # Obtain from MPD's maximum seq value |             # Obtain from MPD's maximum seq value | ||||||
|             old_mpd_url = mpd_url |             old_mpd_url = mpd_url | ||||||
|             mpd_url, stream_number, is_live = mpd_feed(format_id) or (mpd_url, stream_number, False) |             last_error = ctx.pop('last_error', None) | ||||||
|             if old_mpd_url == mpd_url and not refresh_sequence: |             expire_fast = last_error and isinstance(last_error, compat_HTTPError) and last_error.code == 403 | ||||||
|                 return True, last_seq |             mpd_url, stream_number, is_live = (mpd_feed(format_id, 5 if expire_fast else 18000) | ||||||
|  |                                                or (mpd_url, stream_number, False)) | ||||||
|  |             if not refresh_sequence: | ||||||
|  |                 if expire_fast and not is_live: | ||||||
|  |                     return False, last_seq | ||||||
|  |                 elif old_mpd_url == mpd_url: | ||||||
|  |                     return True, last_seq | ||||||
|             try: |             try: | ||||||
|                 fmts, _ = self._extract_mpd_formats_and_subtitles( |                 fmts, _ = self._extract_mpd_formats_and_subtitles( | ||||||
|                     mpd_url, None, note=False, errnote=False, fatal=False) |                     mpd_url, None, note=False, errnote=False, fatal=False) | ||||||
| @@ -1875,8 +1883,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor): | |||||||
|                     last_segment_url = None |                     last_segment_url = None | ||||||
|                     continue |                     continue | ||||||
|             else: |             else: | ||||||
|                 should_retry, last_seq = _extract_sequence_from_mpd(True) |                 should_continue, last_seq = _extract_sequence_from_mpd(True) | ||||||
|                 if not should_retry: |                 if not should_continue: | ||||||
|                     continue |                     continue | ||||||
|  |  | ||||||
|             if known_idx > last_seq: |             if known_idx > last_seq: | ||||||
| @@ -1893,9 +1901,8 @@ class YoutubeIE(YoutubeBaseInfoExtractor): | |||||||
|             try: |             try: | ||||||
|                 for idx in range(known_idx, last_seq): |                 for idx in range(known_idx, last_seq): | ||||||
|                     # do not update sequence here or you'll get skipped some part of it |                     # do not update sequence here or you'll get skipped some part of it | ||||||
|                     should_retry, _ = _extract_sequence_from_mpd(False) |                     should_continue, _ = _extract_sequence_from_mpd(False) | ||||||
|                     if not should_retry: |                     if not should_continue: | ||||||
|                         # retry when it gets weird state |  | ||||||
|                         known_idx = idx - 1 |                         known_idx = idx - 1 | ||||||
|                         raise ExtractorError('breaking out of outer loop') |                         raise ExtractorError('breaking out of outer loop') | ||||||
|                     last_segment_url = urljoin(fragment_base_url, 'sq/%d' % idx) |                     last_segment_url = urljoin(fragment_base_url, 'sq/%d' % idx) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 pukkandan
					pukkandan