aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom-Oliver Heidel <blackjack4494@web.de>2020-09-14 13:04:24 +0200
committerTom-Oliver Heidel <blackjack4494@web.de>2020-09-14 13:04:24 +0200
commitacdb1a4ec627c6ddd976b69c25ebf87fd983ee67 (patch)
treef00ef2eade2e7e4a4ad5f223784d5fcaa450af65
parent1985f657e5df8529444d7f3b6726b07bae202506 (diff)
parentd03cfdce1bce28284fa0f168d5d278caacd2fa0b (diff)
downloadhypervideo-pre-acdb1a4ec627c6ddd976b69c25ebf87fd983ee67.tar.lz
hypervideo-pre-acdb1a4ec627c6ddd976b69c25ebf87fd983ee67.tar.xz
hypervideo-pre-acdb1a4ec627c6ddd976b69c25ebf87fd983ee67.zip
Merge branch 'arbitrary-merges' of https://github.com/fstirlitz/youtube-dlc
-rw-r--r--youtube_dlc/YoutubeDL.py120
-rw-r--r--youtube_dlc/extractor/dispeak.py1
-rw-r--r--youtube_dlc/postprocessor/ffmpeg.py9
3 files changed, 77 insertions, 53 deletions
diff --git a/youtube_dlc/YoutubeDL.py b/youtube_dlc/YoutubeDL.py
index 4cec2298c..1e2070f8c 100644
--- a/youtube_dlc/YoutubeDL.py
+++ b/youtube_dlc/YoutubeDL.py
@@ -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))
diff --git a/youtube_dlc/extractor/dispeak.py b/youtube_dlc/extractor/dispeak.py
index c345e0274..22bdc5635 100644
--- a/youtube_dlc/extractor/dispeak.py
+++ b/youtube_dlc/extractor/dispeak.py
@@ -93,6 +93,7 @@ class DigitallySpeakingIE(InfoExtractor):
'quality': -2,
'preference': -2,
'format_id': 'slides',
+ 'acodec': 'none',
})
speaker_video_path = xpath_text(metadata, './speakerVideo', fatal=True)
formats.append({
diff --git a/youtube_dlc/postprocessor/ffmpeg.py b/youtube_dlc/postprocessor/ffmpeg.py
index dbc736c50..5d66a69a6 100644
--- a/youtube_dlc/postprocessor/ffmpeg.py
+++ b/youtube_dlc/postprocessor/ffmpeg.py
@@ -476,7 +476,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp')
in_filenames = [filename]
- options = []
+ options = ['-map', '0']
if info['ext'] == 'm4a':
options.extend(['-vn', '-acodec', 'copy'])
@@ -518,7 +518,12 @@ class FFmpegMergerPP(FFmpegPostProcessor):
def run(self, info):
filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp')
- args = ['-c', 'copy', '-map', '0:v:0', '-map', '1:a:0']
+ args = ['-c', 'copy']
+ for (i, fmt) in enumerate(info['requested_formats']):
+ if fmt.get('acodec') != 'none':
+ args.extend(['-map', '%u:a:0' % (i)])
+ if fmt.get('vcodec') != 'none':
+ args.extend(['-map', '%u:v:0' % (i)])
self._downloader.to_screen('[ffmpeg] Merging formats into "%s"' % filename)
self.run_ffmpeg_multiple_files(info['__files_to_merge'], temp_filename, args)
os.rename(encodeFilename(temp_filename), encodeFilename(filename))