diff --git a/beetsplug/deezer.py b/beetsplug/deezer.py index 65d98f5d0e..6ea1726313 100644 --- a/beetsplug/deezer.py +++ b/beetsplug/deezer.py @@ -215,9 +215,20 @@ def get_search_query_with_filters( name: str, va_likely: bool, ) -> tuple[str, dict[str, str]]: - query = f'album:"{name}"' if query_type == "album" else name - if query_type == "track" or not va_likely: - query += f' artist:"{artist}"' + if query_type == "album": + query = f'album:"{name}"' + if not va_likely: + query += f' artist:"{artist}"' + else: + # Deezer drops unquoted free text as soon as the query carries any + # field:"value" filter, so ` artist:"<artist>"` degenerated + # into "every track by this artist", truncated to `search_limit`. + # The wanted track routinely fell outside that window. Filtering on + # the title instead is no better, because `artist:` is fuzzy enough + # to match unrelated artists ("Pan Da Punk" for "Daft Punk"), so the + # two filters can intersect to nothing even for a well-tagged file. + # Plain free text lets Deezer's own relevance ranking do the work. + query = f"{name} {artist}".strip() return query, {} diff --git a/docs/changelog.rst b/docs/changelog.rst index 8316ff9a3c..2702d108fe 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -30,6 +30,13 @@ Bug fixes - :doc:`plugins/lyrics`: ``beet lyrics`` no longer crashes with an ``AttributeError`` on tracks that have no stored lyrics when ``force`` is enabled; a missing lyrics body is now treated as empty text. :bug:`6860` +- :doc:`plugins/deezer`: Singleton searches now use plain free text rather than + ``<title> artist:"<artist>"``. Deezer discards unquoted free text as soon as a + query contains any ``field:"value"`` filter, so the old query was evaluated as + ``artist:"<artist>"`` alone -- every track by the artist, in Deezer's own + relevance order and truncated to ``search_limit``. For artists with more + releases than that window, the track being imported was never among the + candidates offered. .. For plugin developers diff --git a/test/plugins/test_deezer.py b/test/plugins/test_deezer.py new file mode 100644 index 0000000000..e62514824d --- /dev/null +++ b/test/plugins/test_deezer.py @@ -0,0 +1,41 @@ +import pytest + +from beets.library import Item +from beetsplug.deezer import DeezerPlugin + + +@pytest.fixture +def plugin(): + return DeezerPlugin() + + +class TestSearchQuery: + def test_track_query_is_free_text(self, plugin): + query, filters = plugin.get_search_query_with_filters( + "track", [Item()], "Artist", "Title", False + ) + + assert query == "Title Artist" + assert filters == {} + + def test_track_query_tolerates_missing_artist(self, plugin): + query, _ = plugin.get_search_query_with_filters( + "track", [Item()], "", "Title", False + ) + + assert query == "Title" + + def test_album_query_filters_on_album_and_artist(self, plugin): + query, filters = plugin.get_search_query_with_filters( + "album", [Item()], "Artist", "Album", False + ) + + assert query == 'album:"Album" artist:"Artist"' + assert filters == {} + + def test_album_query_omits_artist_for_various_artists(self, plugin): + query, _ = plugin.get_search_query_with_filters( + "album", [Item()], "Various Artists", "Album", True + ) + + assert query == 'album:"Album"'