diff --git a/beetsplug/tidal/__init__.py b/beetsplug/tidal/__init__.py index d16a8ca40c..cf14aa9691 100644 --- a/beetsplug/tidal/__init__.py +++ b/beetsplug/tidal/__init__.py @@ -1,6 +1,5 @@ from __future__ import annotations -import itertools import os import re import time @@ -129,8 +128,12 @@ def candidates( ): return candidates - for query in self._album_queries(items): - candidates += self.search_albums_by_query(query) + query = ( + album.strip() + if va_likely + else f"{artist.strip()} {album.strip()}".strip() + ) + candidates += self.search_albums_by_query(query) log.debug("Found {0} candidates", len(candidates)) return candidates @@ -148,30 +151,16 @@ def item_candidates( ): return candidates - for query in self._item_queries(item): - candidates += self.search_tracks_by_query(query) + query = ( + f"{artist.strip()} {title.strip()}" + if artist.strip() + else title.strip() + ) + candidates += self.search_tracks_by_query(query) log.debug("Found {0} candidates", len(candidates)) return candidates - @staticmethod - def _item_queries(item: Item) -> Iterable[str]: - """Search queries for items.""" - yield item.title - - if item.artist: - yield f"{item.artist} {item.title}" - - @staticmethod - def _album_queries(items: Sequence[Item]) -> Iterable[str]: - """Search queries for albums.""" - - album_names = set(i.album for i in items) - artist_names = set(i.artist for i in items) - - for album, artist in itertools.product(album_names, artist_names): - yield f"{artist} {album}" - def search_tracks_by_query(self, query: str) -> Iterable[TrackInfo]: """Search for tracks given a string query.""" search_doc = self.api.search_results(query, include=["tracks.artists"]) diff --git a/test/plugins/test_tidal.py b/test/plugins/test_tidal.py index b30ac17c46..1fdfaff3f7 100644 --- a/test/plugins/test_tidal.py +++ b/test/plugins/test_tidal.py @@ -672,6 +672,46 @@ def test_candidates_with_query_fallback(self): assert len(candidates) == 1 assert candidates[0].album == "Query Album" + def test_candidates_with_manual_search_override(self): + """Test candidates uses manual search terms instead of items tags.""" + items = [ + Item( + title="Original Song", + artist="Original Artist", + album="Original Album", + ) + ] + + self.tidal.api.search_results = Mock( + return_value={ + "data": { + "relationships": { + "albums": {"data": [{"id": "1", "type": "albums"}]} + } + } + } + ) + + track = _make_track("101", "Album Track", "PT3M", "ISRC001", ["1001"]) + album, track_lookup, artist_lookup = _make_album( + "1", "Query Album", [track], ["1001"] + ) + self.tidal.api.get_albums = Mock( + return_value={ + "data": [album], + "included": [*artist_lookup.values(), *track_lookup.values()], + } + ) + + list( + self.tidal.candidates(items, "Manual Artist", "Manual Album", False) + ) + + # Should search using manual query terms, not item tags + self.tidal.api.search_results.assert_called_once_with( + "Manual Artist Manual Album", include=["albums"] + ) + class TestItemCandidates(TidalPluginTest): """Tests for item_candidates method.""" @@ -724,6 +764,35 @@ def test_item_candidates_with_query_fallback(self): assert self.tidal.api.search_results.called assert results[0].title == "Query Track" + def test_item_candidates_with_manual_search_override(self): + """Test item_candidates uses manual search terms instead of item tags.""" + item = Item(title="Original Song", artist="Original Artist") + + self.tidal.api.search_results = Mock( + return_value={ + "data": { + "relationships": { + "tracks": { + "data": [{"id": "490839595", "type": "tracks"}] + } + } + }, + "included": [ + _make_track( + "490839595", "Query Track", "PT3M", "ISRC002", ["1001"] + ), + _make_artist("1001", "Query Artist"), + ], + } + ) + + list(self.tidal.item_candidates(item, "Manual Artist", "Manual Song")) + + # Should search using manual query terms, not item tags + self.tidal.api.search_results.assert_called_once_with( + "Manual Artist Manual Song", include=["tracks.artists"] + ) + class TestStaticHelpers: """Tests for static helper methods."""