From 071326c0cc880f844ec5d3da55ea7fe3a97290f3 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 08:35:28 +0700 Subject: [PATCH 01/13] [ie] Add new fields with proper support for multiple values --- yt_dlp/YoutubeDL.py | 20 ++++++++++-- yt_dlp/__init__.py | 5 +++ yt_dlp/extractor/common.py | 19 +++++++---- yt_dlp/postprocessor/__init__.py | 1 + yt_dlp/postprocessor/ffmpeg.py | 13 +++++--- yt_dlp/postprocessor/mutagenmetadata.py | 42 +++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 yt_dlp/postprocessor/mutagenmetadata.py diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 8d96498a6..ea03e7274 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -24,6 +24,7 @@ import traceback import unicodedata from .cache import Cache + from .compat import functools, urllib # isort: split from .compat import compat_os_name, compat_shlex_quote, urllib_req_to_req from .cookies import LenientSimpleCookie, load_cookies @@ -1735,6 +1736,7 @@ class YoutubeDL: '_type': 'compat_list', 'entries': ie_result, } + self.fix_deprecated_fields(ie_result) if extra_info.get('original_url'): ie_result.setdefault('original_url', extra_info['original_url']) self.add_default_extra_info(ie_result, ie, url) @@ -1744,6 +1746,19 @@ class YoutubeDL: else: return ie_result + def fix_deprecated_fields(self, ie_result): + deprecated_multivalue_fields = { + 'artist': 'artist_list', + 'composer': 'composer_list', + 'album_artist': 'album_artist_list', + 'genre': 'genre_list', + } + for deprecated_field, new_field in deprecated_multivalue_fields.items(): + if deprecated_field not in ie_result: + continue + self.deprecation_warning(f'"{deprecated_field}" field is deprecated. Use "{new_field}" instead') + ie_result[new_field] = re.split(r', ?', ie_result[deprecated_field]) + def add_default_extra_info(self, ie_result, ie, url): if url is not None: self.add_extra_info(ie_result, { @@ -3918,10 +3933,9 @@ class YoutubeDL: # These imports can be slow. So import them only as needed from .extractor.extractors import _LAZY_LOADER - from .extractor.extractors import ( - _PLUGIN_CLASSES as plugin_ies, + from .extractor.extractors import _PLUGIN_CLASSES as plugin_ies + from .extractor.extractors import \ _PLUGIN_OVERRIDES as plugin_ie_overrides - ) def get_encoding(stream): ret = str(getattr(stream, 'encoding', 'missing (%s)' % type(stream).__name__)) diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 57a487157..025b97a31 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -670,6 +670,11 @@ def get_postprocessors(opts): 'add_metadata': opts.addmetadata, 'add_infojson': opts.embed_infojson, } + # MutagenMetadata must run after FFmpegMetadata + if opts.addmetadata: + yield { + 'key': 'MutagenMetadata', + } # Deprecated # This should be above EmbedThumbnail since sponskrub removes the thumbnail attachment # but must be below EmbedSubtitle and FFmpegMetadata diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index af534775f..b614472b5 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -422,16 +422,23 @@ class InfoExtractor: track_number: Number of the track within an album or a disc, as an integer. track_id: Id of the track (useful in case of custom indexing, e.g. 6.iii), as a unicode string. - artist: Artist(s) of the track. - genre: Genre(s) of the track. + artist_list: Artist(s) of the track, as a list of unicode strings. + composer_list: Composer(s) of the piece, as a list of unicode strings. + genre_list: Genre(s) of the track, as a list of unicode strings. + album: Title of the album the track belongs to. album_type: Type of the album (e.g. "Demo", "Full-length", "Split", "Compilation", etc). - album_artist: List of all artists appeared on the album (e.g. - "Ash Borer / Fell Voices" or "Various Artists", useful for splits - and compilations). + album_artist_list: All artists appeared on the album, as a list of unicode strings. + (e.g. ["Ash Borer", "Fell Voices"] or ["Various Artists"], + useful for splits and compilations). disc_number: Number of the disc or other physical medium the track belongs to, as an integer. - composer: Composer of the piece + composer: Deprecated, use "composer_list" instead. Composer(s) of the piece, + comma-separated + artist: Deprecated, use "artist_list" instead. Artist(s) of the track, comma-separated. + genre: Deprecated, use "genre_list" instead. Genre(s) of the track, comma-separated. + album_artist: Deprecated, use "album_artist_list" instead. All artists appeared on the + album, comma-separated. The following fields should only be set for clips that should be cut from the original video: diff --git a/yt_dlp/postprocessor/__init__.py b/yt_dlp/postprocessor/__init__.py index bfe9df733..e96a015e6 100644 --- a/yt_dlp/postprocessor/__init__.py +++ b/yt_dlp/postprocessor/__init__.py @@ -30,6 +30,7 @@ from .metadataparser import ( ) from .modify_chapters import ModifyChaptersPP from .movefilesafterdownload import MoveFilesAfterDownloadPP +from .mutagenmetadata import MutagenMetadataPP from .sponskrub import SponSkrubPP from .sponsorblock import SponsorBlockPP from .xattrpp import XAttrMetadataPP diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index 7c904417b..b7e08de4b 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -23,6 +23,7 @@ from ..utils import ( encodeFilename, filter_dict, float_or_none, + is_iterable_like, is_outdated_version, orderedSet, prepend_extension, @@ -738,9 +739,12 @@ class FFmpegMetadataPP(FFmpegPostProcessor): def add(meta_list, info_list=None): value = next(( - str(info[key]) for key in [f'{meta_prefix}_'] + list(variadic(info_list or meta_list)) + info[key] for key in [f'{meta_prefix}_'] + list(variadic(info_list or meta_list)) if info.get(key) is not None), None) if value not in ('', None): + if is_iterable_like(value): + value = ', '.join(value) + value = str(value) value = value.replace('\0', '') # nul character cannot be passed in command line metadata['common'].update({meta_f: value for meta_f in variadic(meta_list)}) @@ -754,10 +758,11 @@ class FFmpegMetadataPP(FFmpegPostProcessor): add(('description', 'synopsis'), 'description') add(('purl', 'comment'), 'webpage_url') add('track', 'track_number') - add('artist', ('artist', 'creator', 'uploader', 'uploader_id')) - add('genre') + add('artist', ('artist_list', 'creator', 'uploader', 'uploader_id')) + add('composer', 'composer_list') + add('genre', 'genre_list') add('album') - add('album_artist') + add('album_artist', 'album_artist_list') add('disc', 'disc_number') add('show', 'series') add('season_number') diff --git a/yt_dlp/postprocessor/mutagenmetadata.py b/yt_dlp/postprocessor/mutagenmetadata.py new file mode 100644 index 000000000..25d7f016c --- /dev/null +++ b/yt_dlp/postprocessor/mutagenmetadata.py @@ -0,0 +1,42 @@ +from .common import PostProcessor +from ..dependencies import mutagen + +if mutagen: + from mutagen.easymp4 import EasyMP4 + from mutagen.flac import FLAC + from mutagen.mp3 import EasyMP3 + from mutagen.musepack import Musepack + from mutagen.oggopus import OggOpus + from mutagen.oggvorbis import OggVorbis + + +class MutagenMetadataPP(PostProcessor): + def __init__(self, downloader): + PostProcessor.__init__(self, downloader) + + @PostProcessor._restrict_to(images=False) + def run(self, information): + extension = information['ext'] + ret = [], information + if not mutagen: + if extension in ['mp3', 'm4a', 'ogg', 'opus', 'flac', '.mpc']: + self.report_warning('module mutagen was not found. Tags with multiple values (e.g. artist, album artist and genre) may be set incorrectly. Please install using `python -m pip install mutagen`') + return ret + tag_mapping = { + 'artist': 'artist_list', + 'albumartist': 'album_artist_list', + 'genre': 'genre_list', + 'composer': 'composer_list' + } + supported_formats = [EasyMP3, EasyMP4, OggVorbis, OggOpus, FLAC, Musepack] + file = mutagen.File(information['filepath'], supported_formats) + if not file: + return ret + if isinstance(file, EasyMP4): + file.RegisterTextKey('composer', '\251wrt') + for tag_key, info_key in tag_mapping.items(): + value = information.get(info_key) + if value: + file[tag_key] = value + file.save() + return ret From 698199b0e86b8ebbc1b21fea6b95c52908b81cc6 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Wed, 3 Jan 2024 09:07:28 +0530 Subject: [PATCH 02/13] Apply suggestions from code review --- yt_dlp/YoutubeDL.py | 2 -- yt_dlp/extractor/common.py | 27 ++++++++++++++------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index ea03e7274..8ac93fecc 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -24,7 +24,6 @@ import traceback import unicodedata from .cache import Cache - from .compat import functools, urllib # isort: split from .compat import compat_os_name, compat_shlex_quote, urllib_req_to_req from .cookies import LenientSimpleCookie, load_cookies @@ -1756,7 +1755,6 @@ class YoutubeDL: for deprecated_field, new_field in deprecated_multivalue_fields.items(): if deprecated_field not in ie_result: continue - self.deprecation_warning(f'"{deprecated_field}" field is deprecated. Use "{new_field}" instead') ie_result[new_field] = re.split(r', ?', ie_result[deprecated_field]) def add_default_extra_info(self, ie_result, ie, url): diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index b614472b5..cde9c167b 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -422,23 +422,24 @@ class InfoExtractor: track_number: Number of the track within an album or a disc, as an integer. track_id: Id of the track (useful in case of custom indexing, e.g. 6.iii), as a unicode string. - artist_list: Artist(s) of the track, as a list of unicode strings. - composer_list: Composer(s) of the piece, as a list of unicode strings. - genre_list: Genre(s) of the track, as a list of unicode strings. - + artist_list: List of artists of the track. + composer_list: List of composers of the piece + genre_list: List of genres of the track. album: Title of the album the track belongs to. album_type: Type of the album (e.g. "Demo", "Full-length", "Split", "Compilation", etc). - album_artist_list: All artists appeared on the album, as a list of unicode strings. - (e.g. ["Ash Borer", "Fell Voices"] or ["Various Artists"], - useful for splits and compilations). + album_artist_list: List of all artists appeared on the album. E.g. + ["Ash Borer", "Fell Voices"] or ["Various Artists"]. + Useful for splits and compilations. disc_number: Number of the disc or other physical medium the track belongs to, as an integer. - composer: Deprecated, use "composer_list" instead. Composer(s) of the piece, - comma-separated - artist: Deprecated, use "artist_list" instead. Artist(s) of the track, comma-separated. - genre: Deprecated, use "genre_list" instead. Genre(s) of the track, comma-separated. - album_artist: Deprecated, use "album_artist_list" instead. All artists appeared on the - album, comma-separated. + composer: Deprecated; use "composer_list" instead. + Composer(s) of the piece, comma-separated. + artist: Deprecated; use "artist_list" instead. + Artist(s) of the track, comma-separated. + genre: Deprecated; use "genre_list" instead. + Genre(s) of the track, comma-separated. + album_artist: Deprecated; use "album_artist_list" instead. + All artists appeared on the album, comma-separated. The following fields should only be set for clips that should be cut from the original video: From a69169629089ae27e58d200794a1d8c079f293cb Mon Sep 17 00:00:00 2001 From: pukkandan Date: Wed, 3 Jan 2024 09:10:07 +0530 Subject: [PATCH 03/13] Apply suggestions from code review --- yt_dlp/postprocessor/ffmpeg.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index b7e08de4b..f9ceb5eb4 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -23,7 +23,6 @@ from ..utils import ( encodeFilename, filter_dict, float_or_none, - is_iterable_like, is_outdated_version, orderedSet, prepend_extension, @@ -742,9 +741,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor): info[key] for key in [f'{meta_prefix}_'] + list(variadic(info_list or meta_list)) if info.get(key) is not None), None) if value not in ('', None): - if is_iterable_like(value): - value = ', '.join(value) - value = str(value) + value = ', '.join(map(str, variadic(value))) value = value.replace('\0', '') # nul character cannot be passed in command line metadata['common'].update({meta_f: value for meta_f in variadic(meta_list)}) From d60ad1994447460dc0fe469eeffbb770a443494d Mon Sep 17 00:00:00 2001 From: pukkandan Date: Wed, 3 Jan 2024 09:10:53 +0530 Subject: [PATCH 04/13] Update yt_dlp/extractor/common.py --- yt_dlp/extractor/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index cde9c167b..f11ae0e8c 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -427,8 +427,8 @@ class InfoExtractor: genre_list: List of genres of the track. album: Title of the album the track belongs to. album_type: Type of the album (e.g. "Demo", "Full-length", "Split", "Compilation", etc). - album_artist_list: List of all artists appeared on the album. E.g. - ["Ash Borer", "Fell Voices"] or ["Various Artists"]. + album_artist_list: List of all artists appeared on the album. + E.g. ["Ash Borer", "Fell Voices"] or ["Various Artists"]. Useful for splits and compilations. disc_number: Number of the disc or other physical medium the track belongs to, as an integer. From ac52bf09527fdf3265ae3e8a816af982c6524009 Mon Sep 17 00:00:00 2001 From: pukkandan Date: Wed, 3 Jan 2024 09:16:21 +0530 Subject: [PATCH 05/13] Update yt_dlp/YoutubeDL.py --- yt_dlp/YoutubeDL.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 8ac93fecc..6d30d223e 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -1753,9 +1753,8 @@ class YoutubeDL: 'genre': 'genre_list', } for deprecated_field, new_field in deprecated_multivalue_fields.items(): - if deprecated_field not in ie_result: - continue - ie_result[new_field] = re.split(r', ?', ie_result[deprecated_field]) + if ie_result.get(deprecated_field): + ie_result[new_field] = re.split(r', ?', ie_result[deprecated_field]) def add_default_extra_info(self, ie_result, ie, url): if url is not None: From 265e0f7154e6cae93e33427ca8cd32170d1001e5 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 14:12:02 +0700 Subject: [PATCH 06/13] Rename new fields - Moved fix_deprecated_fields into _fill_common_fields --- yt_dlp/YoutubeDL.py | 23 +++++++++++------------ yt_dlp/extractor/common.py | 16 ++++++++-------- yt_dlp/postprocessor/ffmpeg.py | 8 ++++---- yt_dlp/postprocessor/mutagenmetadata.py | 8 ++++---- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 6d30d223e..fe63e249e 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -24,6 +24,7 @@ import traceback import unicodedata from .cache import Cache + from .compat import functools, urllib # isort: split from .compat import compat_os_name, compat_shlex_quote, urllib_req_to_req from .cookies import LenientSimpleCookie, load_cookies @@ -1735,7 +1736,6 @@ class YoutubeDL: '_type': 'compat_list', 'entries': ie_result, } - self.fix_deprecated_fields(ie_result) if extra_info.get('original_url'): ie_result.setdefault('original_url', extra_info['original_url']) self.add_default_extra_info(ie_result, ie, url) @@ -1745,17 +1745,6 @@ class YoutubeDL: else: return ie_result - def fix_deprecated_fields(self, ie_result): - deprecated_multivalue_fields = { - 'artist': 'artist_list', - 'composer': 'composer_list', - 'album_artist': 'album_artist_list', - 'genre': 'genre_list', - } - for deprecated_field, new_field in deprecated_multivalue_fields.items(): - if ie_result.get(deprecated_field): - ie_result[new_field] = re.split(r', ?', ie_result[deprecated_field]) - def add_default_extra_info(self, ie_result, ie, url): if url is not None: self.add_extra_info(ie_result, { @@ -2653,6 +2642,16 @@ class YoutubeDL: if final and info_dict.get('%s_number' % field) is not None and not info_dict.get(field): info_dict[field] = '%s %d' % (field.capitalize(), info_dict['%s_number' % field]) + deprecated_multivalue_fields = { + 'artist': 'artists', + 'composer': 'composers', + 'album_artist': 'album_artists', + 'genre': 'genres', + } + for deprecated_field, new_field in deprecated_multivalue_fields.items(): + if info_dict.get(deprecated_field): + info_dict[new_field] = re.split(r', ?', info_dict[deprecated_field]) + def _raise_pending_errors(self, info): err = info.pop('__pending_error', None) if err: diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index f11ae0e8c..20015769d 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -422,23 +422,23 @@ class InfoExtractor: track_number: Number of the track within an album or a disc, as an integer. track_id: Id of the track (useful in case of custom indexing, e.g. 6.iii), as a unicode string. - artist_list: List of artists of the track. - composer_list: List of composers of the piece - genre_list: List of genres of the track. + artists: List of artists of the track. + composers: List of composers of the piece + genres: List of genres of the track. album: Title of the album the track belongs to. album_type: Type of the album (e.g. "Demo", "Full-length", "Split", "Compilation", etc). - album_artist_list: List of all artists appeared on the album. + album_artists: List of all artists appeared on the album. E.g. ["Ash Borer", "Fell Voices"] or ["Various Artists"]. Useful for splits and compilations. disc_number: Number of the disc or other physical medium the track belongs to, as an integer. - composer: Deprecated; use "composer_list" instead. + composer: Deprecated; use "composers" instead. Composer(s) of the piece, comma-separated. - artist: Deprecated; use "artist_list" instead. + artist: Deprecated; use "artists" instead. Artist(s) of the track, comma-separated. - genre: Deprecated; use "genre_list" instead. + genre: Deprecated; use "genres" instead. Genre(s) of the track, comma-separated. - album_artist: Deprecated; use "album_artist_list" instead. + album_artist: Deprecated; use "album_artists" instead. All artists appeared on the album, comma-separated. The following fields should only be set for clips that should be cut from the original video: diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index f9ceb5eb4..c94c556ca 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -755,11 +755,11 @@ class FFmpegMetadataPP(FFmpegPostProcessor): add(('description', 'synopsis'), 'description') add(('purl', 'comment'), 'webpage_url') add('track', 'track_number') - add('artist', ('artist_list', 'creator', 'uploader', 'uploader_id')) - add('composer', 'composer_list') - add('genre', 'genre_list') + add('artist', ('artists', 'creator', 'uploader', 'uploader_id')) + add('composer', 'composers') + add('genre', 'genres') add('album') - add('album_artist', 'album_artist_list') + add('album_artist', 'album_artists') add('disc', 'disc_number') add('show', 'series') add('season_number') diff --git a/yt_dlp/postprocessor/mutagenmetadata.py b/yt_dlp/postprocessor/mutagenmetadata.py index 25d7f016c..7a2925ed8 100644 --- a/yt_dlp/postprocessor/mutagenmetadata.py +++ b/yt_dlp/postprocessor/mutagenmetadata.py @@ -23,10 +23,10 @@ class MutagenMetadataPP(PostProcessor): self.report_warning('module mutagen was not found. Tags with multiple values (e.g. artist, album artist and genre) may be set incorrectly. Please install using `python -m pip install mutagen`') return ret tag_mapping = { - 'artist': 'artist_list', - 'albumartist': 'album_artist_list', - 'genre': 'genre_list', - 'composer': 'composer_list' + 'artist': 'artists', + 'albumartist': 'album_artists', + 'genre': 'genres', + 'composer': 'composers' } supported_formats = [EasyMP3, EasyMP4, OggVorbis, OggOpus, FLAC, Musepack] file = mutagen.File(information['filepath'], supported_formats) From 41c3dab54770320517ec7ee7ea0a80cdf53d2bdd Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 14:50:55 +0700 Subject: [PATCH 07/13] Revert unrelated changes --- yt_dlp/YoutubeDL.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index fe63e249e..4d78ef1a2 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -3929,9 +3929,10 @@ class YoutubeDL: # These imports can be slow. So import them only as needed from .extractor.extractors import _LAZY_LOADER - from .extractor.extractors import _PLUGIN_CLASSES as plugin_ies - from .extractor.extractors import \ + from .extractor.extractors import ( + _PLUGIN_CLASSES as plugin_ies, _PLUGIN_OVERRIDES as plugin_ie_overrides + ) def get_encoding(stream): ret = str(getattr(stream, 'encoding', 'missing (%s)' % type(stream).__name__)) From c3fe956e87e06c67d14ba02bbcc2f98803d55206 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 14:52:19 +0700 Subject: [PATCH 08/13] Revert unrelated change --- yt_dlp/YoutubeDL.py | 1 - 1 file changed, 1 deletion(-) diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index 4d78ef1a2..c6b1175a1 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -24,7 +24,6 @@ import traceback import unicodedata from .cache import Cache - from .compat import functools, urllib # isort: split from .compat import compat_os_name, compat_shlex_quote, urllib_req_to_req from .cookies import LenientSimpleCookie, load_cookies From c6246594cff0b5833cb1773ff19e37e491e78a41 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 14:55:47 +0700 Subject: [PATCH 09/13] Update README --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cfd861c56..74dfbb541 100644 --- a/README.md +++ b/README.md @@ -1761,10 +1761,11 @@ Metadata fields | From `description`, `synopsis` | `description` `purl`, `comment` | `webpage_url` `track` | `track_number` -`artist` | `artist`, `creator`, `uploader` or `uploader_id` -`genre` | `genre` +`artist` | `artists`, `creator`, `uploader` or `uploader_id` +`composer` | `composers` +`genre` | `genres` `album` | `album` -`album_artist` | `album_artist` +`album_artist` | `album_artists` `disc` | `disc_number` `show` | `series` `season_number` | `season_number` From dca6384283a38d0b2db2b3bf2aaf68c2035abd95 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 15:05:08 +0700 Subject: [PATCH 10/13] Update README and fix IE documentation typo --- README.md | 7 ++++--- yt_dlp/extractor/common.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 74dfbb541..75946df24 100644 --- a/README.md +++ b/README.md @@ -1379,11 +1379,12 @@ Available for the media that is a track or a part of a music album: - `track` (string): Title of the track - `track_number` (numeric): Number of the track within an album or a disc - `track_id` (string): Id of the track - - `artist` (string): Artist(s) of the track - - `genre` (string): Genre(s) of the track + - `artists` (list): Artist(s) of the track + - `composers` (list): Composer(s) of the piece + - `genres` (list): Genre(s) of the track - `album` (string): Title of the album the track belongs to - `album_type` (string): Type of the album - - `album_artist` (string): List of all artists appeared on the album + - `album_artists` (list): List of all artists appeared on the album - `disc_number` (numeric): Number of the disc or other physical medium the track belongs to Available only when using `--download-sections` and for `chapter:` prefix when using `--split-chapters` for videos with internal chapters: diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py index 20015769d..d73c519b9 100644 --- a/yt_dlp/extractor/common.py +++ b/yt_dlp/extractor/common.py @@ -423,7 +423,7 @@ class InfoExtractor: track_id: Id of the track (useful in case of custom indexing, e.g. 6.iii), as a unicode string. artists: List of artists of the track. - composers: List of composers of the piece + composers: List of composers of the piece. genres: List of genres of the track. album: Title of the album the track belongs to. album_type: Type of the album (e.g. "Demo", "Full-length", "Split", "Compilation", etc). From 2598790093e47121a21937e527ecfb91393f59d7 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 15:16:10 +0700 Subject: [PATCH 11/13] Revert MutagenMetadataPP --- yt_dlp/__init__.py | 5 --- yt_dlp/postprocessor/__init__.py | 1 - yt_dlp/postprocessor/mutagenmetadata.py | 42 ------------------------- 3 files changed, 48 deletions(-) delete mode 100644 yt_dlp/postprocessor/mutagenmetadata.py diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 025b97a31..57a487157 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -670,11 +670,6 @@ def get_postprocessors(opts): 'add_metadata': opts.addmetadata, 'add_infojson': opts.embed_infojson, } - # MutagenMetadata must run after FFmpegMetadata - if opts.addmetadata: - yield { - 'key': 'MutagenMetadata', - } # Deprecated # This should be above EmbedThumbnail since sponskrub removes the thumbnail attachment # but must be below EmbedSubtitle and FFmpegMetadata diff --git a/yt_dlp/postprocessor/__init__.py b/yt_dlp/postprocessor/__init__.py index e96a015e6..bfe9df733 100644 --- a/yt_dlp/postprocessor/__init__.py +++ b/yt_dlp/postprocessor/__init__.py @@ -30,7 +30,6 @@ from .metadataparser import ( ) from .modify_chapters import ModifyChaptersPP from .movefilesafterdownload import MoveFilesAfterDownloadPP -from .mutagenmetadata import MutagenMetadataPP from .sponskrub import SponSkrubPP from .sponsorblock import SponsorBlockPP from .xattrpp import XAttrMetadataPP diff --git a/yt_dlp/postprocessor/mutagenmetadata.py b/yt_dlp/postprocessor/mutagenmetadata.py deleted file mode 100644 index 7a2925ed8..000000000 --- a/yt_dlp/postprocessor/mutagenmetadata.py +++ /dev/null @@ -1,42 +0,0 @@ -from .common import PostProcessor -from ..dependencies import mutagen - -if mutagen: - from mutagen.easymp4 import EasyMP4 - from mutagen.flac import FLAC - from mutagen.mp3 import EasyMP3 - from mutagen.musepack import Musepack - from mutagen.oggopus import OggOpus - from mutagen.oggvorbis import OggVorbis - - -class MutagenMetadataPP(PostProcessor): - def __init__(self, downloader): - PostProcessor.__init__(self, downloader) - - @PostProcessor._restrict_to(images=False) - def run(self, information): - extension = information['ext'] - ret = [], information - if not mutagen: - if extension in ['mp3', 'm4a', 'ogg', 'opus', 'flac', '.mpc']: - self.report_warning('module mutagen was not found. Tags with multiple values (e.g. artist, album artist and genre) may be set incorrectly. Please install using `python -m pip install mutagen`') - return ret - tag_mapping = { - 'artist': 'artists', - 'albumartist': 'album_artists', - 'genre': 'genres', - 'composer': 'composers' - } - supported_formats = [EasyMP3, EasyMP4, OggVorbis, OggOpus, FLAC, Musepack] - file = mutagen.File(information['filepath'], supported_formats) - if not file: - return ret - if isinstance(file, EasyMP4): - file.RegisterTextKey('composer', '\251wrt') - for tag_key, info_key in tag_mapping.items(): - value = information.get(info_key) - if value: - file[tag_key] = value - file.save() - return ret From bbc5ee2b97b138e182879a96c3e648362d9738d9 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 15:20:26 +0700 Subject: [PATCH 12/13] Bring MutagenMetadataPP back This reverts commit 2598790093e47121a21937e527ecfb91393f59d7. --- yt_dlp/__init__.py | 5 +++ yt_dlp/postprocessor/__init__.py | 1 + yt_dlp/postprocessor/mutagenmetadata.py | 42 +++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 yt_dlp/postprocessor/mutagenmetadata.py diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 57a487157..025b97a31 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -670,6 +670,11 @@ def get_postprocessors(opts): 'add_metadata': opts.addmetadata, 'add_infojson': opts.embed_infojson, } + # MutagenMetadata must run after FFmpegMetadata + if opts.addmetadata: + yield { + 'key': 'MutagenMetadata', + } # Deprecated # This should be above EmbedThumbnail since sponskrub removes the thumbnail attachment # but must be below EmbedSubtitle and FFmpegMetadata diff --git a/yt_dlp/postprocessor/__init__.py b/yt_dlp/postprocessor/__init__.py index bfe9df733..e96a015e6 100644 --- a/yt_dlp/postprocessor/__init__.py +++ b/yt_dlp/postprocessor/__init__.py @@ -30,6 +30,7 @@ from .metadataparser import ( ) from .modify_chapters import ModifyChaptersPP from .movefilesafterdownload import MoveFilesAfterDownloadPP +from .mutagenmetadata import MutagenMetadataPP from .sponskrub import SponSkrubPP from .sponsorblock import SponsorBlockPP from .xattrpp import XAttrMetadataPP diff --git a/yt_dlp/postprocessor/mutagenmetadata.py b/yt_dlp/postprocessor/mutagenmetadata.py new file mode 100644 index 000000000..7a2925ed8 --- /dev/null +++ b/yt_dlp/postprocessor/mutagenmetadata.py @@ -0,0 +1,42 @@ +from .common import PostProcessor +from ..dependencies import mutagen + +if mutagen: + from mutagen.easymp4 import EasyMP4 + from mutagen.flac import FLAC + from mutagen.mp3 import EasyMP3 + from mutagen.musepack import Musepack + from mutagen.oggopus import OggOpus + from mutagen.oggvorbis import OggVorbis + + +class MutagenMetadataPP(PostProcessor): + def __init__(self, downloader): + PostProcessor.__init__(self, downloader) + + @PostProcessor._restrict_to(images=False) + def run(self, information): + extension = information['ext'] + ret = [], information + if not mutagen: + if extension in ['mp3', 'm4a', 'ogg', 'opus', 'flac', '.mpc']: + self.report_warning('module mutagen was not found. Tags with multiple values (e.g. artist, album artist and genre) may be set incorrectly. Please install using `python -m pip install mutagen`') + return ret + tag_mapping = { + 'artist': 'artists', + 'albumartist': 'album_artists', + 'genre': 'genres', + 'composer': 'composers' + } + supported_formats = [EasyMP3, EasyMP4, OggVorbis, OggOpus, FLAC, Musepack] + file = mutagen.File(information['filepath'], supported_formats) + if not file: + return ret + if isinstance(file, EasyMP4): + file.RegisterTextKey('composer', '\251wrt') + for tag_key, info_key in tag_mapping.items(): + value = information.get(info_key) + if value: + file[tag_key] = value + file.save() + return ret From aa3498b17ee2ca404d859fecb41b7d12acd7d2e8 Mon Sep 17 00:00:00 2001 From: Lev Plyusnin Date: Wed, 3 Jan 2024 16:42:24 +0700 Subject: [PATCH 13/13] Remove Musepack from supported formats --- yt_dlp/postprocessor/mutagenmetadata.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/yt_dlp/postprocessor/mutagenmetadata.py b/yt_dlp/postprocessor/mutagenmetadata.py index 7a2925ed8..875616337 100644 --- a/yt_dlp/postprocessor/mutagenmetadata.py +++ b/yt_dlp/postprocessor/mutagenmetadata.py @@ -5,7 +5,6 @@ if mutagen: from mutagen.easymp4 import EasyMP4 from mutagen.flac import FLAC from mutagen.mp3 import EasyMP3 - from mutagen.musepack import Musepack from mutagen.oggopus import OggOpus from mutagen.oggvorbis import OggVorbis @@ -19,7 +18,7 @@ class MutagenMetadataPP(PostProcessor): extension = information['ext'] ret = [], information if not mutagen: - if extension in ['mp3', 'm4a', 'ogg', 'opus', 'flac', '.mpc']: + if extension in ['mp3', 'm4a', 'ogg', 'opus', 'flac']: self.report_warning('module mutagen was not found. Tags with multiple values (e.g. artist, album artist and genre) may be set incorrectly. Please install using `python -m pip install mutagen`') return ret tag_mapping = { @@ -28,7 +27,7 @@ class MutagenMetadataPP(PostProcessor): 'genre': 'genres', 'composer': 'composers' } - supported_formats = [EasyMP3, EasyMP4, OggVorbis, OggOpus, FLAC, Musepack] + supported_formats = [EasyMP3, EasyMP4, OggVorbis, OggOpus, FLAC] file = mutagen.File(information['filepath'], supported_formats) if not file: return ret