aboutsummaryrefslogtreecommitdiffstats
path: root/yt_dlp/postprocessor/ffmpeg.py
diff options
context:
space:
mode:
Diffstat (limited to 'yt_dlp/postprocessor/ffmpeg.py')
-rw-r--r--yt_dlp/postprocessor/ffmpeg.py45
1 files changed, 45 insertions, 0 deletions
diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py
index 43c1b276d..213de0ecf 100644
--- a/yt_dlp/postprocessor/ffmpeg.py
+++ b/yt_dlp/postprocessor/ffmpeg.py
@@ -1123,3 +1123,48 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor):
if not has_thumbnail:
self.to_screen('There aren\'t any thumbnails to convert')
return files_to_delete, info
+
+
+class FFmpegConcatPP(FFmpegPostProcessor):
+ def __init__(self, downloader, only_multi_video=False):
+ self._only_multi_video = only_multi_video
+ super().__init__(downloader)
+
+ def concat_files(self, in_files, out_file):
+ if len(in_files) == 1:
+ os.replace(in_files[0], out_file)
+ return
+
+ codecs = [traverse_obj(self.get_metadata_object(file), ('streams', ..., 'codec_name')) for file in in_files]
+ if len(set(map(tuple, codecs))) > 1:
+ raise PostProcessingError(
+ 'The files have different streams/codecs and cannot be concatenated. '
+ 'Either select different formats or --recode-video them to a common format')
+ super().concat_files(in_files, out_file)
+
+ @PostProcessor._restrict_to(images=False)
+ def run(self, info):
+ if not info.get('entries') or self._only_multi_video and info['_type'] != 'multi_video':
+ return [], info
+ elif None in info['entries']:
+ raise PostProcessingError('Aborting concatenation because some downloads failed')
+ elif any(len(entry) > 1 for entry in traverse_obj(info, ('entries', ..., 'requested_downloads')) or []):
+ raise PostProcessingError('Concatenation is not supported when downloading multiple separate formats')
+
+ in_files = traverse_obj(info, ('entries', ..., 'requested_downloads', 0, 'filepath'))
+ if not in_files:
+ self.to_screen('There are no files to concatenate')
+ return [], info
+
+ ie_copy = self._downloader._playlist_infodict(info)
+ exts = [traverse_obj(entry, ('requested_downloads', 0, 'ext'), 'ext') for entry in info['entries']]
+ ie_copy['ext'] = exts[0] if len(set(exts)) == 1 else 'mkv'
+ out_file = self._downloader.prepare_filename(ie_copy, 'pl_video')
+
+ self.concat_files(in_files, out_file)
+
+ info['requested_downloads'] = [{
+ 'filepath': out_file,
+ 'ext': ie_copy['ext'],
+ }]
+ return in_files, info