diff --git a/core/amazon_client.py b/core/amazon_client.py index 278493c4..3febed1e 100644 --- a/core/amazon_client.py +++ b/core/amazon_client.py @@ -601,6 +601,25 @@ class AmazonClient: """Not available from Amazon Music — returns None for compatibility.""" return None + def _get_artist_image_from_albums(self, artist_id: str) -> Optional[str]: + """Return an album cover as artist image stand-in (T2Tunes has no artist images).""" + search_name = _unslugify(artist_id) + try: + items = self.search_raw(search_name, types="track,album") + except AmazonClientError: + return None + name_lower = search_name.lower() + for item in items: + if _primary_artist(item.artist_name).lower() != name_lower: + continue + asin = item.album_asin or item.asin + if not asin: + continue + metas = self._fetch_album_metas([asin]) + if asin in metas and metas[asin].get("image"): + return metas[asin]["image"] + return None + # ==================== Interface Aliases (match DeezerClient method names) ==================== get_album_metadata = get_album get_artist_info = get_artist diff --git a/core/artist_source_lookup.py b/core/artist_source_lookup.py index d7497e1c..72888af2 100644 --- a/core/artist_source_lookup.py +++ b/core/artist_source_lookup.py @@ -58,19 +58,18 @@ def find_library_artist_for_source( Returns ``None`` on miss or on any database error. """ column = SOURCE_ID_FIELD.get(source) - if not column: - return None try: with database._get_connection() as conn: cursor = conn.cursor() - cursor.execute( - f"SELECT id, name FROM artists WHERE {column} = ? LIMIT 1", - (str(source_artist_id),), - ) - row = cursor.fetchone() - if row: - return row[0] + if column: + cursor.execute( + f"SELECT id, name FROM artists WHERE {column} = ? LIMIT 1", + (str(source_artist_id),), + ) + row = cursor.fetchone() + if row: + return row[0] if artist_name and active_server: cursor.execute( diff --git a/tests/metadata/test_artist_source_lookup.py b/tests/metadata/test_artist_source_lookup.py index 75ca4582..7e803d70 100644 --- a/tests/metadata/test_artist_source_lookup.py +++ b/tests/metadata/test_artist_source_lookup.py @@ -68,11 +68,11 @@ class TestSourceIdFieldMapping: "(and the test body) to match." ) - def test_source_only_set_matches_mapping_keys(self): - """Sources eligible for the source-only fallback must all have a - column to look them up by — otherwise the upgrade path silently - returns None.""" - assert SOURCE_ONLY_ARTIST_SOURCES == frozenset(SOURCE_ID_FIELD.keys()) + def test_source_only_set_contains_all_mapped_sources(self): + """Every source with a SOURCE_ID_FIELD column must also be in + SOURCE_ONLY_ARTIST_SOURCES. The reverse is not required — sources + without a DB column (e.g. amazon) use name-based lookup only.""" + assert frozenset(SOURCE_ID_FIELD.keys()).issubset(SOURCE_ONLY_ARTIST_SOURCES) def test_every_mapped_column_exists_on_artists_table(self, db): """Regression for the 2026-04 ``deezer_artist_id`` typo: every column