mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 14:45:14 +00:00 
			
		
		
		
	[dash,youtube] Download live from start to end (#888)
* Add option `--live-from-start` to enable downloading live videos from start * Add key `is_from_start` in formats to identify formats (of live videos) that downloads from start * [dash] Create protocol `http_dash_segments_generator` that allows a function to be passed instead of fragments * [fragment] Allow multiple live dash formats to download simultaneously * [youtube] Implement fragment re-fetching for the live dash formats * [youtube] Re-extract dash manifest every 5 hours (manifest expires in 6hrs) * [postprocessor/ffmpeg] Add `FFmpegFixupDuplicateMoovPP` to fixup duplicated moov atoms Known issue: Ctrl+C doesn't work on Windows when downloading multiple formats Closes #1521 Authored by: nao20010128nao, pukkandan
This commit is contained in:
		 The Hatsune Daishi
					The Hatsune Daishi
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							c031b0414c
						
					
				
				
					commit
					adbc4ec4bb
				
			| @@ -1,4 +1,5 @@ | ||||
| from __future__ import unicode_literals | ||||
| import time | ||||
|  | ||||
| from ..downloader import get_suitable_downloader | ||||
| from .fragment import FragmentFD | ||||
| @@ -15,27 +16,53 @@ class DashSegmentsFD(FragmentFD): | ||||
|     FD_NAME = 'dashsegments' | ||||
|  | ||||
|     def real_download(self, filename, info_dict): | ||||
|         if info_dict.get('is_live'): | ||||
|         if info_dict.get('is_live') and set(info_dict['protocol'].split('+')) != {'http_dash_segments_generator'}: | ||||
|             self.report_error('Live DASH videos are not supported') | ||||
|  | ||||
|         fragment_base_url = info_dict.get('fragment_base_url') | ||||
|         fragments = info_dict['fragments'][:1] if self.params.get( | ||||
|             'test', False) else info_dict['fragments'] | ||||
|  | ||||
|         real_start = time.time() | ||||
|         real_downloader = get_suitable_downloader( | ||||
|             info_dict, self.params, None, protocol='dash_frag_urls', to_stdout=(filename == '-')) | ||||
|  | ||||
|         ctx = { | ||||
|             'filename': filename, | ||||
|             'total_frags': len(fragments), | ||||
|         } | ||||
|         requested_formats = [{**info_dict, **fmt} for fmt in info_dict.get('requested_formats', [])] | ||||
|         args = [] | ||||
|         for fmt in requested_formats or [info_dict]: | ||||
|             try: | ||||
|                 fragment_count = 1 if self.params.get('test') else len(fmt['fragments']) | ||||
|             except TypeError: | ||||
|                 fragment_count = None | ||||
|             ctx = { | ||||
|                 'filename': fmt.get('filepath') or filename, | ||||
|                 'live': 'is_from_start' if fmt.get('is_from_start') else fmt.get('is_live'), | ||||
|                 'total_frags': fragment_count, | ||||
|             } | ||||
|  | ||||
|         if real_downloader: | ||||
|             self._prepare_external_frag_download(ctx) | ||||
|         else: | ||||
|             self._prepare_and_start_frag_download(ctx, info_dict) | ||||
|             if real_downloader: | ||||
|                 self._prepare_external_frag_download(ctx) | ||||
|             else: | ||||
|                 self._prepare_and_start_frag_download(ctx, fmt) | ||||
|             ctx['start'] = real_start | ||||
|  | ||||
|             fragments_to_download = self._get_fragments(fmt, ctx) | ||||
|  | ||||
|             if real_downloader: | ||||
|                 self.to_screen( | ||||
|                     '[%s] Fragment downloads will be delegated to %s' % (self.FD_NAME, real_downloader.get_basename())) | ||||
|                 info_dict['fragments'] = fragments_to_download | ||||
|                 fd = real_downloader(self.ydl, self.params) | ||||
|                 return fd.real_download(filename, info_dict) | ||||
|  | ||||
|             args.append([ctx, fragments_to_download, fmt]) | ||||
|  | ||||
|         return self.download_and_append_fragments_multiple(*args) | ||||
|  | ||||
|     def _resolve_fragments(self, fragments, ctx): | ||||
|         fragments = fragments(ctx) if callable(fragments) else fragments | ||||
|         return [next(fragments)] if self.params.get('test') else fragments | ||||
|  | ||||
|     def _get_fragments(self, fmt, ctx): | ||||
|         fragment_base_url = fmt.get('fragment_base_url') | ||||
|         fragments = self._resolve_fragments(fmt['fragments'], ctx) | ||||
|  | ||||
|         fragments_to_download = [] | ||||
|         frag_index = 0 | ||||
|         for i, fragment in enumerate(fragments): | ||||
|             frag_index += 1 | ||||
| @@ -46,17 +73,8 @@ class DashSegmentsFD(FragmentFD): | ||||
|                 assert fragment_base_url | ||||
|                 fragment_url = urljoin(fragment_base_url, fragment['path']) | ||||
|  | ||||
|             fragments_to_download.append({ | ||||
|             yield { | ||||
|                 'frag_index': frag_index, | ||||
|                 'index': i, | ||||
|                 'url': fragment_url, | ||||
|             }) | ||||
|  | ||||
|         if real_downloader: | ||||
|             self.to_screen( | ||||
|                 '[%s] Fragment downloads will be delegated to %s' % (self.FD_NAME, real_downloader.get_basename())) | ||||
|             info_dict['fragments'] = fragments_to_download | ||||
|             fd = real_downloader(self.ydl, self.params) | ||||
|             return fd.real_download(filename, info_dict) | ||||
|  | ||||
|         return self.download_and_append_fragments(ctx, fragments_to_download, info_dict) | ||||
|             } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user