From 198c3e4faf61bb4732612156334ec6c60cbbf9b4 Mon Sep 17 00:00:00 2001 From: Egor Halimonenko Date: Thu, 2 Jan 2025 17:18:55 +0300 Subject: [PATCH] [embedthumbnail] add new cli option '--force-convert-thumbnails' --- README.md | 2 ++ yt_dlp/__init__.py | 1 + yt_dlp/options.py | 5 +++++ yt_dlp/postprocessor/embedthumbnail.py | 2 +- yt_dlp/postprocessor/ffmpeg.py | 26 ++++++++++++++++++++------ 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1c628d025..a288b77e8 100644 --- a/README.md +++ b/README.md @@ -1006,6 +1006,8 @@ If you fork the project on GitHub, you can run your fork's [build workflow](.git syntax as "--remux-video". Use "--convert- thumbnails none" to disable conversion (default) + --force-convert-thumbnails Convert the thumbnails to another format even + if it's already in this format --split-chapters Split video into multiple files based on internal chapters. The "chapter:" prefix can be used with "--paths" and "--output" to set diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 20111175b..10bc4d017 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -638,6 +638,7 @@ def get_postprocessors(opts): yield { 'key': 'FFmpegThumbnailsConvertor', 'format': opts.convertthumbnails, + 'force_convert_thumbnails': opts.force_convert_thumbnails, 'when': 'before_dl', } if opts.extractaudio: diff --git a/yt_dlp/options.py b/yt_dlp/options.py index 06b65e0ea..1c7a0ec09 100644 --- a/yt_dlp/options.py +++ b/yt_dlp/options.py @@ -1748,6 +1748,11 @@ def create_parser(): f'(currently supported: {", ".join(sorted(FFmpegThumbnailsConvertorPP.SUPPORTED_EXTS))}). ' 'You can specify multiple rules using similar syntax as "--remux-video". ' 'Use "--convert-thumbnails none" to disable conversion (default)')) + postproc.add_option( + '--force-convert-thumbnails', + dest='force_convert_thumbnails', action='store_true', default=False, + help=( + 'Convert the thumbnails to another format even if it\'s already in this format')) postproc.add_option( '--split-chapters', '--split-tracks', dest='split_chapters', action='store_true', default=False, diff --git a/yt_dlp/postprocessor/embedthumbnail.py b/yt_dlp/postprocessor/embedthumbnail.py index d8ba220ca..621a22bf2 100644 --- a/yt_dlp/postprocessor/embedthumbnail.py +++ b/yt_dlp/postprocessor/embedthumbnail.py @@ -73,7 +73,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor): # Correct extension for WebP file with wrong extension (see #25687, #25717) convertor = FFmpegThumbnailsConvertorPP(self._downloader) - convertor.fixup_webp(info, idx) + convertor.fixup_thumbnail(info, idx) original_thumbnail = thumbnail_filename = info['thumbnails'][idx]['filepath'] diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 8965806ae..fec502d62 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -1072,16 +1072,17 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor): SUPPORTED_EXTS = MEDIA_EXTENSIONS.thumbnails FORMAT_RE = create_mapping_re(SUPPORTED_EXTS) - def __init__(self, downloader=None, format=None): + def __init__(self, downloader=None, format=None, force_convert_thumbnails=False): super().__init__(downloader) self.mapping = format + self._force_convert_thumbnails = force_convert_thumbnails @classmethod def is_webp(cls, path): deprecation_warning(f'{cls.__module__}.{cls.__name__}.is_webp is deprecated') return imghdr.what(path) == 'webp' - def fixup_webp(self, info, idx=-1): + def fixup_thumbnail(self, info, idx=-1): thumbnail_filename = info['thumbnails'][idx]['filepath'] _, thumbnail_ext = os.path.splitext(thumbnail_filename) if thumbnail_ext: @@ -1092,6 +1093,13 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor): info['thumbnails'][idx]['filepath'] = webp_filename info['__files_to_move'][webp_filename] = replace_extension( info['__files_to_move'].pop(thumbnail_filename), 'webp') + elif thumbnail_ext.lower() != '.png' and imghdr.what(thumbnail_filename) == 'png': + self.to_screen('Correcting thumbnail "%s" extension to png' % thumbnail_filename) + webp_filename = replace_extension(thumbnail_filename, 'png') + os.replace(thumbnail_filename, webp_filename) + info['thumbnails'][idx]['filepath'] = webp_filename + info['__files_to_move'][webp_filename] = replace_extension( + info['__files_to_move'].pop(thumbnail_filename), 'png') @staticmethod def _options(target_ext): @@ -1118,17 +1126,23 @@ class FFmpegThumbnailsConvertorPP(FFmpegPostProcessor): if not original_thumbnail: continue has_thumbnail = True - self.fixup_webp(info, idx) + self.fixup_thumbnail(info, idx) original_thumbnail = thumbnail_dict['filepath'] # Path can change during fixup thumbnail_ext = os.path.splitext(original_thumbnail)[1][1:].lower() if thumbnail_ext == 'jpeg': thumbnail_ext = 'jpg' target_ext, _skip_msg = resolve_mapping(thumbnail_ext, self.mapping) + is_forced_converting = False if _skip_msg: - self.to_screen(f'Not converting thumbnail "{original_thumbnail}"; {_skip_msg}') - continue + if self._force_convert_thumbnails and target_ext == thumbnail_ext: + self.to_screen(f'Force converting thumbnail "{original_thumbnail}" despite of: {_skip_msg}') + is_forced_converting = True + else: + self.to_screen(f'Not converting thumbnail "{original_thumbnail}"; {_skip_msg}') + continue thumbnail_dict['filepath'] = self.convert_thumbnail(original_thumbnail, target_ext) - files_to_delete.append(original_thumbnail) + if is_forced_converting == False: + files_to_delete.append(original_thumbnail) info['__files_to_move'][thumbnail_dict['filepath']] = replace_extension( info['__files_to_move'][original_thumbnail], target_ext)