From 69f5fe45b98ef3ecb8e5ac69ebebdce7733a3ae4 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Tue, 20 Dec 2022 00:41:45 +0530 Subject: [FFmpegVideoConvertor] Add `gif` to `--recode-video` --- yt_dlp/postprocessor/ffmpeg.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 67890fc31..069066e0c 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -538,7 +538,10 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor): class FFmpegVideoConvertorPP(FFmpegPostProcessor): - SUPPORTED_EXTS = (*MEDIA_EXTENSIONS.common_video, *sorted(MEDIA_EXTENSIONS.common_audio + ('aac', 'vorbis'))) + SUPPORTED_EXTS = ( + *sorted((*MEDIA_EXTENSIONS.common_video, 'gif')), + *sorted((*MEDIA_EXTENSIONS.common_audio, 'aac', 'vorbis')), + ) FORMAT_RE = create_mapping_re(SUPPORTED_EXTS) _ACTION = 'converting' -- cgit v1.2.3 From 8e40b9d1ec132ae1bcac50b3ee520ece46ac9c55 Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 1 Jan 2023 04:29:22 +0000 Subject: Improve plugin architecture (#5553) to make plugins easier to develop and use: * Plugins are now loaded as namespace packages. * Plugins can be loaded in any distribution of yt-dlp (binary, pip, source, etc.). * Plugin packages can be installed and managed via pip, or dropped into any of the documented locations. * Users do not need to edit any code files to install plugins. * Backwards-compatible with previous plugin architecture. As a side-effect, yt-dlp will now search in a few more locations for config files. Closes https://github.com/yt-dlp/yt-dlp/issues/1389 Authored by: flashdagger, coletdjnz, pukkandan, Grub4K Co-authored-by: Marcel Co-authored-by: pukkandan Co-authored-by: Simon Sawicki --- yt_dlp/postprocessor/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/__init__.py b/yt_dlp/postprocessor/__init__.py index f168be46a..bfe9df733 100644 --- a/yt_dlp/postprocessor/__init__.py +++ b/yt_dlp/postprocessor/__init__.py @@ -33,14 +33,15 @@ from .movefilesafterdownload import MoveFilesAfterDownloadPP from .sponskrub import SponSkrubPP from .sponsorblock import SponsorBlockPP from .xattrpp import XAttrMetadataPP -from ..utils import load_plugins +from ..plugins import load_plugins -_PLUGIN_CLASSES = load_plugins('postprocessor', 'PP', globals()) +_PLUGIN_CLASSES = load_plugins('postprocessor', 'PP') def get_postprocessor(key): return globals()[key + 'PP'] +globals().update(_PLUGIN_CLASSES) __all__ = [name for name in globals().keys() if name.endswith('PP')] __all__.extend(('PostProcessor', 'FFmpegPostProcessor')) -- cgit v1.2.3 From 08e29b9f1f0b6e5fe1c1e87bf8169bfd7ac91d57 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Mon, 2 Jan 2023 19:39:03 +0530 Subject: [cleanup] Misc Closes #5576, closes #5887 --- yt_dlp/postprocessor/ffmpeg.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 069066e0c..9b70d749f 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -407,7 +407,7 @@ class FFmpegPostProcessor(PostProcessor): """ concat_file = f'{out_file}.concat' self.write_debug(f'Writing concat spec to {concat_file}') - with open(concat_file, 'wt', encoding='utf-8') as f: + with open(concat_file, 'w', encoding='utf-8') as f: f.writelines(self._concat_spec(in_files, concat_opts)) out_flags = list(self.stream_copy_opts(ext=determine_ext(out_file))) @@ -711,7 +711,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor): @staticmethod def _get_chapter_opts(chapters, metadata_filename): - with open(metadata_filename, 'wt', encoding='utf-8') as f: + with open(metadata_filename, 'w', encoding='utf-8') as f: def ffmpeg_escape(text): return re.sub(r'([\\=;#\n])', r'\\\1', text) @@ -981,7 +981,7 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor): with open(dfxp_file, 'rb') as f: srt_data = dfxp2srt(f.read()) - with open(srt_file, 'wt', encoding='utf-8') as f: + with open(srt_file, 'w', encoding='utf-8') as f: f.write(srt_data) old_file = srt_file -- cgit v1.2.3 From d80ca5deaa46db6e498399bb04a72a4c10ee8e22 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Tue, 3 Jan 2023 08:05:45 +0530 Subject: [utils] `mimetype2ext`: weba is not standard Fix bug in fbb73833067ba742459729809679a62f34b3e41e, 2647c933b8ed22f95dd8e9866c4db031867a1bc8 Closes #5935 --- yt_dlp/postprocessor/ffmpeg.py | 1 + 1 file changed, 1 insertion(+) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 9b70d749f..5acd75376 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -44,6 +44,7 @@ EXT_TO_OUT_FORMATS = { 'ts': 'mpegts', 'wma': 'asf', 'wmv': 'asf', + 'weba': 'webm', 'vtt': 'webvtt', } ACODECS = { -- cgit v1.2.3 From f737fb16d8234408c85bc189ccc926fea000515b Mon Sep 17 00:00:00 2001 From: Chris Caruso Date: Fri, 17 Feb 2023 00:06:15 -0800 Subject: [ExtractAudio] Handle outtmpl without ext (#6005) Authored by: carusocr Closes #5968 --- yt_dlp/postprocessor/ffmpeg.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 5acd75376..123a95a3a 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -508,8 +508,7 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor): if acodec != 'copy': more_opts = self._quality_args(acodec) - # not os.path.splitext, since the latter does not work on unicode in all setups - temp_path = new_path = f'{path.rpartition(".")[0]}.{extension}' + temp_path = new_path = replace_extension(path, extension, information['ext']) if new_path == path: if acodec == 'copy': -- cgit v1.2.3 From a5387729696a5b33f53f60ef06f48e45663b12dd Mon Sep 17 00:00:00 2001 From: pukkandan Date: Fri, 17 Feb 2023 17:52:22 +0530 Subject: [cleanup] Misc Closes #5897 --- yt_dlp/postprocessor/metadataparser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/metadataparser.py b/yt_dlp/postprocessor/metadataparser.py index f574f2330..1d6054294 100644 --- a/yt_dlp/postprocessor/metadataparser.py +++ b/yt_dlp/postprocessor/metadataparser.py @@ -1,7 +1,7 @@ import re from .common import PostProcessor -from ..utils import Namespace, filter_dict +from ..utils import Namespace, filter_dict, function_with_repr class MetadataParserPP(PostProcessor): @@ -60,6 +60,7 @@ class MetadataParserPP(PostProcessor): f(info) return [], info + @function_with_repr def interpretter(self, inp, out): def f(info): data_to_parse = self._downloader.evaluate_outtmpl(template, info) @@ -76,6 +77,7 @@ class MetadataParserPP(PostProcessor): out_re = re.compile(self.format_to_regex(out)) return f + @function_with_repr def replacer(self, field, search, replace): def f(info): val = info.get(field) -- cgit v1.2.3 From 01ddec7e661bf90dc4c34e6924eb9d7629886cef Mon Sep 17 00:00:00 2001 From: bashonly <88596187+bashonly@users.noreply.github.com> Date: Wed, 8 Mar 2023 07:10:19 -0600 Subject: [postprocessor] Fix chapters if duration is not extracted (#6037) Authored by: bashonly --- yt_dlp/postprocessor/ffmpeg.py | 7 +++++++ yt_dlp/postprocessor/modify_chapters.py | 1 + 2 files changed, 8 insertions(+) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 123a95a3a..0e8f4c70b 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -302,6 +302,11 @@ class FFmpegPostProcessor(PostProcessor): None) return num, len(streams) + def _fixup_chapters(self, info): + last_chapter = traverse_obj(info, ('chapters', -1)) + if last_chapter and not last_chapter.get('end_time'): + last_chapter['end_time'] = self._get_real_video_duration(info['filepath']) + def _get_real_video_duration(self, filepath, fatal=True): try: duration = float_or_none( @@ -678,6 +683,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor): @PostProcessor._restrict_to(images=False) def run(self, info): + self._fixup_chapters(info) filename, metadata_filename = info['filepath'], None files_to_delete, options = [], [] if self._add_chapters and info.get('chapters'): @@ -1040,6 +1046,7 @@ class FFmpegSplitChaptersPP(FFmpegPostProcessor): @PostProcessor._restrict_to(images=False) def run(self, info): + self._fixup_chapters(info) chapters = info.get('chapters') or [] if not chapters: self.to_screen('Chapter information is unavailable') diff --git a/yt_dlp/postprocessor/modify_chapters.py b/yt_dlp/postprocessor/modify_chapters.py index a745b4524..f5219868c 100644 --- a/yt_dlp/postprocessor/modify_chapters.py +++ b/yt_dlp/postprocessor/modify_chapters.py @@ -23,6 +23,7 @@ class ModifyChaptersPP(FFmpegPostProcessor): @PostProcessor._restrict_to(images=False) def run(self, info): + self._fixup_chapters(info) # Chapters must be preserved intact when downloading multiple formats of the same video. chapters, sponsor_chapters = self._mark_chapters_to_remove( copy.deepcopy(info.get('chapters')) or [], -- cgit v1.2.3 From 0f0875ed555514f32522a0f30554fb08825d5124 Mon Sep 17 00:00:00 2001 From: Lesmiscore Date: Tue, 28 Mar 2023 01:17:42 +0900 Subject: [postprocessor/EmbedThumbnail,postprocessor/FFmpegMetadata] Fix error on attaching thumbnails and info json for mkv/mka (#6647) Authored by: Lesmiscore Current yt-dlp code never hit this bug, but would hit once filename sanitization gets better --- yt_dlp/postprocessor/embedthumbnail.py | 2 +- yt_dlp/postprocessor/ffmpeg.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/embedthumbnail.py b/yt_dlp/postprocessor/embedthumbnail.py index b02d9d499..88a767132 100644 --- a/yt_dlp/postprocessor/embedthumbnail.py +++ b/yt_dlp/postprocessor/embedthumbnail.py @@ -107,7 +107,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor): options.extend(['-map', '-0:%d' % old_stream]) new_stream -= 1 options.extend([ - '-attach', thumbnail_filename, + '-attach', self._ffmpeg_filename_argument(thumbnail_filename), '-metadata:s:%d' % new_stream, 'mimetype=%s' % mimetype, '-metadata:s:%d' % new_stream, 'filename=cover.%s' % thumbnail_ext]) diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 0e8f4c70b..63fc9ace6 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -809,7 +809,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor): new_stream -= 1 yield ( - '-attach', infofn, + '-attach', self._ffmpeg_filename_argument(infofn), f'-metadata:s:{new_stream}', 'mimetype=application/json', f'-metadata:s:{new_stream}', 'filename=info.json', ) -- cgit v1.2.3 From 3f7e2bd80e3c5d8a1682f20a1b245fcd974f295d Mon Sep 17 00:00:00 2001 From: bashonly <88596187+bashonly@users.noreply.github.com> Date: Thu, 13 Apr 2023 14:21:09 -0500 Subject: [FFmpegFixupM3u8PP] Check audio codec before fixup (#6778) Closes #6673 Authored by: bashonly --- yt_dlp/postprocessor/ffmpeg.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 63fc9ace6..323f4303c 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -898,8 +898,11 @@ class FFmpegFixupM3u8PP(FFmpegFixupPostProcessor): @PostProcessor._restrict_to(images=False) def run(self, info): if all(self._needs_fixup(info)): + args = ['-f', 'mp4'] + if self.get_audio_codec(info['filepath']) == 'aac': + args.extend(['-bsf:a', 'aac_adtstoasc']) self._fixup('Fixing MPEG-TS in MP4 container', info['filepath'], [ - *self.stream_copy_opts(), '-f', 'mp4', '-bsf:a', 'aac_adtstoasc']) + *self.stream_copy_opts(), *args]) return [], info -- cgit v1.2.3 From 13ff78095372fd98900a32572cf817994c07ccb5 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Wed, 14 Jun 2023 19:09:53 +0530 Subject: [postprocessor] Print newline for `--progress-template` Closes #7193 --- yt_dlp/postprocessor/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/common.py b/yt_dlp/postprocessor/common.py index 537792b07..08b0fe1ff 100644 --- a/yt_dlp/postprocessor/common.py +++ b/yt_dlp/postprocessor/common.py @@ -187,7 +187,7 @@ class PostProcessor(metaclass=PostProcessorMetaClass): tmpl = progress_template.get('postprocess') if tmpl: self._downloader.to_screen( - self._downloader.evaluate_outtmpl(tmpl, progress_dict), skip_eol=True, quiet=False) + self._downloader.evaluate_outtmpl(tmpl, progress_dict), quiet=False) self._downloader.to_console_title(self._downloader.evaluate_outtmpl( progress_template.get('postprocess-title') or 'yt-dlp %(progress._default_template)s', -- cgit v1.2.3 From 8a4cd12c8f8e93292e3e95200b9d17a3af39624c Mon Sep 17 00:00:00 2001 From: Neurognostic Date: Thu, 13 Jul 2023 16:39:21 -0400 Subject: [pp/EmbedThumbnail] Support `m4v` (#7583) Authored by: Neurognostic --- yt_dlp/postprocessor/embedthumbnail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/embedthumbnail.py b/yt_dlp/postprocessor/embedthumbnail.py index 88a767132..d7be0b398 100644 --- a/yt_dlp/postprocessor/embedthumbnail.py +++ b/yt_dlp/postprocessor/embedthumbnail.py @@ -114,7 +114,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor): self._report_run('ffmpeg', filename) self.run_ffmpeg(filename, temp_filename, options) - elif info['ext'] in ['m4a', 'mp4', 'mov']: + elif info['ext'] in ['m4a', 'mp4', 'm4v', 'mov']: prefer_atomicparsley = 'embed-thumbnail-atomicparsley' in self.get_param('compat_opts', []) # Method 1: Use mutagen if not mutagen or prefer_atomicparsley: @@ -213,7 +213,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor): temp_filename = filename else: - raise EmbedThumbnailPPError('Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/mov') + raise EmbedThumbnailPPError('Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/m4v/mov') if success and temp_filename != filename: os.replace(temp_filename, filename) -- cgit v1.2.3 From 3d2623a898196640f7cc0fc8b70118ff19e6925d Mon Sep 17 00:00:00 2001 From: coletdjnz Date: Sun, 9 Jul 2023 13:23:02 +0530 Subject: [compat, networking] Deprecate old functions (#2861) Authored by: coletdjnz, pukkandan --- yt_dlp/postprocessor/common.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'yt_dlp/postprocessor') diff --git a/yt_dlp/postprocessor/common.py b/yt_dlp/postprocessor/common.py index 08b0fe1ff..8cef86c43 100644 --- a/yt_dlp/postprocessor/common.py +++ b/yt_dlp/postprocessor/common.py @@ -1,16 +1,15 @@ import functools import json import os -import urllib.error +from ..networking import Request +from ..networking.exceptions import HTTPError, network_exceptions from ..utils import ( PostProcessingError, RetryManager, _configuration_args, deprecation_warning, encodeFilename, - network_exceptions, - sanitized_Request, ) @@ -203,13 +202,13 @@ class PostProcessor(metaclass=PostProcessorMetaClass): self.write_debug(f'{self.PP_NAME} query: {url}') for retry in RetryManager(self.get_param('extractor_retries', 3), self._retry_download): try: - rsp = self._downloader.urlopen(sanitized_Request(url)) + rsp = self._downloader.urlopen(Request(url)) except network_exceptions as e: - if isinstance(e, urllib.error.HTTPError) and e.code in expected_http_errors: + if isinstance(e, HTTPError) and e.status in expected_http_errors: return None retry.error = PostProcessingError(f'Unable to communicate with {self.PP_NAME} API: {e}') continue - return json.loads(rsp.read().decode(rsp.info().get_param('charset') or 'utf-8')) + return json.loads(rsp.read().decode(rsp.headers.get_param('charset') or 'utf-8')) class AudioConversionError(PostProcessingError): # Deprecated -- cgit v1.2.3