Allow selecting either tags or genres in the includes, defaulting to genres (#5874)

Genres is a filtered list based on what musicbrainz considers a genre,
tags are all the user-submitted tags. [1]

1.
https://musicbrainz.org/doc/MusicBrainz_API#:~:text=Since%20genres%20are,!).
This commit is contained in:
Šarūnas Nejus 2025-11-12 21:40:02 +00:00 committed by GitHub
commit e326aafac0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 39 additions and 2 deletions

View file

@ -90,6 +90,7 @@ RELEASE_INCLUDES = list(
"isrcs", "isrcs",
"url-rels", "url-rels",
"release-rels", "release-rels",
"genres",
"tags", "tags",
} }
& set(musicbrainzngs.VALID_INCLUDES["release"]) & set(musicbrainzngs.VALID_INCLUDES["release"])
@ -370,6 +371,10 @@ def _merge_pseudo_and_actual_album(
class MusicBrainzPlugin(MetadataSourcePlugin): class MusicBrainzPlugin(MetadataSourcePlugin):
@cached_property
def genres_field(self) -> str:
return f"{self.config['genres_tag'].as_choice(['genre', 'tag'])}-list"
def __init__(self): def __init__(self):
"""Set up the python-musicbrainz-ngs module according to settings """Set up the python-musicbrainz-ngs module according to settings
from the beets configuration. This should be called at startup. from the beets configuration. This should be called at startup.
@ -382,6 +387,7 @@ class MusicBrainzPlugin(MetadataSourcePlugin):
"ratelimit": 1, "ratelimit": 1,
"ratelimit_interval": 1, "ratelimit_interval": 1,
"genres": False, "genres": False,
"genres_tag": "genre",
"external_ids": { "external_ids": {
"discogs": False, "discogs": False,
"bandcamp": False, "bandcamp": False,
@ -723,8 +729,8 @@ class MusicBrainzPlugin(MetadataSourcePlugin):
if self.config["genres"]: if self.config["genres"]:
sources = [ sources = [
release["release-group"].get("tag-list", []), release["release-group"].get(self.genres_field, []),
release.get("tag-list", []), release.get(self.genres_field, []),
] ]
genres: Counter[str] = Counter() genres: Counter[str] = Counter()
for source in sources: for source in sources:

View file

@ -13,6 +13,8 @@ been dropped.
New features: New features:
- :doc:`plugins/ftintitle`: Added argument for custom feat. words in ftintitle. - :doc:`plugins/ftintitle`: Added argument for custom feat. words in ftintitle.
- :doc:`plugins/musicbrainz`: Allow selecting tags or genres to populate the
genres tag.
- :doc:`plugins/ftintitle`: Added argument to skip the processing of artist and - :doc:`plugins/ftintitle`: Added argument to skip the processing of artist and
album artist are the same in ftintitle. album artist are the same in ftintitle.
- :doc:`plugins/play`: Added `$playlist` marker to precisely edit the playlist - :doc:`plugins/play`: Added `$playlist` marker to precisely edit the playlist

View file

@ -32,6 +32,7 @@ Default
ratelimit_interval: 1.0 ratelimit_interval: 1.0
extra_tags: [] extra_tags: []
genres: no genres: no
genres_tag: genre
external_ids: external_ids:
discogs: no discogs: no
bandcamp: no bandcamp: no
@ -136,6 +137,12 @@ Default
``beatport_album_id``, ``deezer_album_id``, ``tidal_album_id``). On re-imports ``beatport_album_id``, ``deezer_album_id``, ``tidal_album_id``). On re-imports
existing data will be overwritten. existing data will be overwritten.
.. conf:: genres_tag
:default: genre
Either ``genre`` or ``tag``. Specify ``genre`` to use just musicbrainz genre and
``tag`` to use all user-supplied musicbrainz tags.
.. include:: ./shared_metadata_source_config.rst .. include:: ./shared_metadata_source_config.rst
.. _building search indexes: https://musicbrainz.org/doc/Development/Search_server_setup .. _building search indexes: https://musicbrainz.org/doc/Development/Search_server_setup

View file

@ -65,6 +65,8 @@ class MBAlbumInfoTest(MusicBrainzTestCase):
], ],
"date": "3001", "date": "3001",
"medium-list": [], "medium-list": [],
"genre-list": [{"count": 1, "name": "GENRE"}],
"tag-list": [{"count": 1, "name": "TAG"}],
"label-info-list": [ "label-info-list": [
{ {
"catalog-number": "CATALOG NUMBER", "catalog-number": "CATALOG NUMBER",
@ -515,6 +517,26 @@ class MBAlbumInfoTest(MusicBrainzTestCase):
d = self.mb.album_info(release) d = self.mb.album_info(release)
assert d.data_source == "MusicBrainz" assert d.data_source == "MusicBrainz"
def test_genres(self):
config["musicbrainz"]["genres"] = True
config["musicbrainz"]["genres_tag"] = "genre"
release = self._make_release()
d = self.mb.album_info(release)
assert d.genre == "GENRE"
def test_tags(self):
config["musicbrainz"]["genres"] = True
config["musicbrainz"]["genres_tag"] = "tag"
release = self._make_release()
d = self.mb.album_info(release)
assert d.genre == "TAG"
def test_no_genres(self):
config["musicbrainz"]["genres"] = False
release = self._make_release()
d = self.mb.album_info(release)
assert d.genre is None
def test_ignored_media(self): def test_ignored_media(self):
config["match"]["ignored_media"] = ["IGNORED1", "IGNORED2"] config["match"]["ignored_media"] = ["IGNORED1", "IGNORED2"]
tracks = [ tracks = [