mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 14:45:14 +00:00 
			
		
		
		
	Merge branch 'arbitrary-merges' of https://github.com/fstirlitz/youtube-dlc
This commit is contained in:
		| @@ -1217,11 +1217,13 @@ class YoutubeDL(object): | ||||
|                         group = _parse_format_selection(tokens, inside_group=True) | ||||
|                         current_selector = FormatSelector(GROUP, group, []) | ||||
|                     elif string == '+': | ||||
|                         video_selector = current_selector | ||||
|                         audio_selector = _parse_format_selection(tokens, inside_merge=True) | ||||
|                         if not video_selector or not audio_selector: | ||||
|                             raise syntax_error('"+" must be between two format selectors', start) | ||||
|                         current_selector = FormatSelector(MERGE, (video_selector, audio_selector), []) | ||||
|                         if not current_selector: | ||||
|                             raise syntax_error('Unexpected "+"', start) | ||||
|                         selector_1 = current_selector | ||||
|                         selector_2 = _parse_format_selection(tokens, inside_merge=True) | ||||
|                         if not selector_2: | ||||
|                             raise syntax_error('Expected a selector', start) | ||||
|                         current_selector = FormatSelector(MERGE, (selector_1, selector_2), []) | ||||
|                     else: | ||||
|                         raise syntax_error('Operator not recognized: "{0}"'.format(string), start) | ||||
|                 elif type == tokenize.ENDMARKER: | ||||
| @@ -1306,47 +1308,59 @@ class YoutubeDL(object): | ||||
|                         if matches: | ||||
|                             yield matches[-1] | ||||
|             elif selector.type == MERGE: | ||||
|                 def _merge(formats_info): | ||||
|                     format_1, format_2 = [f['format_id'] for f in formats_info] | ||||
|                     # The first format must contain the video and the | ||||
|                     # second the audio | ||||
|                     if formats_info[0].get('vcodec') == 'none': | ||||
|                         self.report_error('The first format must ' | ||||
|                                           'contain the video, try using ' | ||||
|                                           '"-f %s+%s"' % (format_2, format_1)) | ||||
|                         return | ||||
|                     # Formats must be opposite (video+audio) | ||||
|                     if formats_info[0].get('acodec') == 'none' and formats_info[1].get('acodec') == 'none': | ||||
|                         self.report_error( | ||||
|                             'Both formats %s and %s are video-only, you must specify "-f video+audio"' | ||||
|                             % (format_1, format_2)) | ||||
|                         return | ||||
|                     output_ext = ( | ||||
|                         formats_info[0]['ext'] | ||||
|                         if self.params.get('merge_output_format') is None | ||||
|                         else self.params['merge_output_format']) | ||||
|                     return { | ||||
|                 def _merge(formats_pair): | ||||
|                     format_1, format_2 = formats_pair | ||||
|  | ||||
|                     formats_info = [] | ||||
|                     formats_info.extend(format_1.get('requested_formats', (format_1,))) | ||||
|                     formats_info.extend(format_2.get('requested_formats', (format_2,))) | ||||
|  | ||||
|                     video_fmts = [fmt_info for fmt_info in formats_info if fmt_info.get('vcodec') != 'none'] | ||||
|                     audio_fmts = [fmt_info for fmt_info in formats_info if fmt_info.get('acodec') != 'none'] | ||||
|  | ||||
|                     the_only_video = video_fmts[0] if len(video_fmts) == 1 else None | ||||
|                     the_only_audio = audio_fmts[0] if len(audio_fmts) == 1 else None | ||||
|  | ||||
|                     output_ext = self.params.get('merge_output_format') | ||||
|                     if not output_ext: | ||||
|                         if the_only_video: | ||||
|                             output_ext = the_only_video['ext'] | ||||
|                         elif the_only_audio and not video_fmts: | ||||
|                             output_ext = the_only_audio['ext'] | ||||
|                         else: | ||||
|                             output_ext = 'mkv' | ||||
|  | ||||
|                     new_dict = { | ||||
|                         'requested_formats': formats_info, | ||||
|                         'format': '%s+%s' % (formats_info[0].get('format'), | ||||
|                                              formats_info[1].get('format')), | ||||
|                         'format_id': '%s+%s' % (formats_info[0].get('format_id'), | ||||
|                                                 formats_info[1].get('format_id')), | ||||
|                         'width': formats_info[0].get('width'), | ||||
|                         'height': formats_info[0].get('height'), | ||||
|                         'resolution': formats_info[0].get('resolution'), | ||||
|                         'fps': formats_info[0].get('fps'), | ||||
|                         'vcodec': formats_info[0].get('vcodec'), | ||||
|                         'vbr': formats_info[0].get('vbr'), | ||||
|                         'stretched_ratio': formats_info[0].get('stretched_ratio'), | ||||
|                         'acodec': formats_info[1].get('acodec'), | ||||
|                         'abr': formats_info[1].get('abr'), | ||||
|                         'format': '+'.join(fmt_info.get('format') for fmt_info in formats_info), | ||||
|                         'format_id': '+'.join(fmt_info.get('format_id') for fmt_info in formats_info), | ||||
|                         'ext': output_ext, | ||||
|                     } | ||||
|                 video_selector, audio_selector = map(_build_selector_function, selector.selector) | ||||
|  | ||||
|                     if the_only_video: | ||||
|                         new_dict.update({ | ||||
|                             'width': the_only_video.get('width'), | ||||
|                             'height': the_only_video.get('height'), | ||||
|                             'resolution': the_only_video.get('resolution'), | ||||
|                             'fps': the_only_video.get('fps'), | ||||
|                             'vcodec': the_only_video.get('vcodec'), | ||||
|                             'vbr': the_only_video.get('vbr'), | ||||
|                             'stretched_ratio': the_only_video.get('stretched_ratio'), | ||||
|                         }) | ||||
|  | ||||
|                     if the_only_audio: | ||||
|                         new_dict.update({ | ||||
|                             'acodec': the_only_audio.get('acodec'), | ||||
|                             'abr': the_only_audio.get('abr'), | ||||
|                         }) | ||||
|  | ||||
|                     return new_dict | ||||
|  | ||||
|                 selector_1, selector_2 = map(_build_selector_function, selector.selector) | ||||
|  | ||||
|                 def selector_function(ctx): | ||||
|                     for pair in itertools.product( | ||||
|                             video_selector(copy.deepcopy(ctx)), audio_selector(copy.deepcopy(ctx))): | ||||
|                             selector_1(copy.deepcopy(ctx)), selector_2(copy.deepcopy(ctx))): | ||||
|                         yield _merge(pair) | ||||
|  | ||||
|             filters = [self._build_format_filter(f) for f in selector.filters] | ||||
| @@ -1899,17 +1913,21 @@ class YoutubeDL(object): | ||||
|                         postprocessors = [merger] | ||||
|  | ||||
|                     def compatible_formats(formats): | ||||
|                         video, audio = formats | ||||
|                         # TODO: some formats actually allow this (mkv, webm, ogg, mp4), but not all of them. | ||||
|                         video_formats = [format for format in formats if format.get('vcodec') != 'none'] | ||||
|                         audio_formats = [format for format in formats if format.get('acodec') != 'none'] | ||||
|                         if len(video_formats) > 2 or len(audio_formats) > 2: | ||||
|                             return False | ||||
|  | ||||
|                         # Check extension | ||||
|                         video_ext, audio_ext = video.get('ext'), audio.get('ext') | ||||
|                         if video_ext and audio_ext: | ||||
|                             COMPATIBLE_EXTS = ( | ||||
|                                 ('mp3', 'mp4', 'm4a', 'm4p', 'm4b', 'm4r', 'm4v', 'ismv', 'isma'), | ||||
|                                 ('webm') | ||||
|                             ) | ||||
|                             for exts in COMPATIBLE_EXTS: | ||||
|                                 if video_ext in exts and audio_ext in exts: | ||||
|                                     return True | ||||
|                         exts = set(format.get('ext') for format in formats) | ||||
|                         COMPATIBLE_EXTS = ( | ||||
|                             set(('mp3', 'mp4', 'm4a', 'm4p', 'm4b', 'm4r', 'm4v', 'ismv', 'isma')), | ||||
|                             set(('webm',)), | ||||
|                         ) | ||||
|                         for ext_sets in COMPATIBLE_EXTS: | ||||
|                             if ext_sets.issuperset(exts): | ||||
|                                 return True | ||||
|                         # TODO: Check acodec/vcodec | ||||
|                         return False | ||||
|  | ||||
| @@ -2088,7 +2106,7 @@ class YoutubeDL(object): | ||||
|             except PostProcessingError as e: | ||||
|                 self.report_error(e.msg) | ||||
|             if files_to_delete and not self.params.get('keepvideo', False): | ||||
|                 for old_filename in files_to_delete: | ||||
|                 for old_filename in set(files_to_delete): | ||||
|                     self.to_screen('Deleting original file %s (pass -k to keep)' % old_filename) | ||||
|                     try: | ||||
|                         os.remove(encodeFilename(old_filename)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Tom-Oliver Heidel
					Tom-Oliver Heidel