diff --git a/beetsplug/_utils/musicbrainz.py b/beetsplug/_utils/musicbrainz.py index 2fc821df9..5d96581ab 100644 --- a/beetsplug/_utils/musicbrainz.py +++ b/beetsplug/_utils/musicbrainz.py @@ -193,10 +193,20 @@ class MusicBrainzAPI(RequestHandler): * Each filter key-value pair is formatted as 'key:"value"' unless - 'key' is empty, in which case only the value is used, '"value"' - 'value' is empty, in which case the filter is ignored + - 'value' is a UUID (MBID), in which case it's not quoted * Values are lowercased and stripped of whitespace. """ + def format_value(value: str) -> str: + """Format a filter value, quoting it unless it's a UUID.""" + # Check if value is a UUID (MBID) - 8-4-4-4-12 format with hyphens + if len(value) == 36 and value.count("-") == 4: + # Likely a UUID/MBID, don't quote it + return value + # Regular string value, quote it + return f'"{value}"' + query = " AND ".join( - ":".join(filter(None, (k, f'"{_v}"'))) + ":".join(filter(None, (k, format_value(_v)))) for k, v in filters.items() if (_v := v.lower().strip()) ) diff --git a/test/plugins/test_musicbrainz.py b/test/plugins/test_musicbrainz.py index 069f1fb99..7d0f373bc 100644 --- a/test/plugins/test_musicbrainz.py +++ b/test/plugins/test_musicbrainz.py @@ -1109,6 +1109,62 @@ class TestMusicBrainzPlugin(PluginMixin): assert candidates[0].tracks[0].track_id == self.RECORDING["id"] assert candidates[0].album == "hi" + def test_candidates_with_va_likely(self, monkeypatch, mb): + """Test that Various Artists searches work with unquoted MBIDs.""" + from unittest import mock + + # Track what query was used + query_used = [] + + def mock_get_json(*args, **kwargs): + if 'params' in kwargs and 'query' in kwargs['params']: + query_used.append(kwargs['params']['query']) + return {"releases": [{"id": self.mbid}]} + + monkeypatch.setattr( + "beetsplug._utils.musicbrainz.MusicBrainzAPI.get_json", + mock_get_json, + ) + monkeypatch.setattr( + "beetsplug._utils.musicbrainz.MusicBrainzAPI.get_release", + lambda *_, **__: { + "title": "VA Album", + "id": self.mbid, + "status": "official", + "media": [ + { + "tracks": [ + { + "id": "track1", + "recording": self.RECORDING, + "position": 1, + "number": "1", + } + ], + "position": 1, + } + ], + "artist-credit": [ + {"artist": {"name": "Various Artists", "id": musicbrainz.VARIOUS_ARTISTS_ID}} + ], + "release-group": {"id": "rg-id"}, + }, + ) + + # Test VA search + candidates = list(mb.candidates([], "Various Artists", "Test Album", va_likely=True)) + + assert len(candidates) == 1 + assert candidates[0].album == "VA Album" + + # Verify that the MBID was NOT quoted in the query + assert len(query_used) == 1 + query = query_used[0] + # The VA MBID should appear unquoted + assert f'arid:{musicbrainz.VARIOUS_ARTISTS_ID}' in query + # Make sure it's not quoted + assert f'arid:"{musicbrainz.VARIOUS_ARTISTS_ID}"' not in query + def test_import_handles_404_gracefully(self, mb, requests_mock): id_ = uuid.uuid4() response = requests.Response()