From d39679951bcceaa657a2c88c21a5c51cddc49d9e Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sat, 16 May 2026 14:18:18 -0700 Subject: [PATCH] Wire Amazon Music into enhanced search and global search source picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 'amazon' to VALID_SOURCES (and transitively VALID_STREAM_SOURCES) in core/search/orchestrator.py so the backend accepts it as a requested source without returning 400 - Add resolve_client('amazon') case — mirrors musicbrainz pattern, gets the cached AmazonClient from the metadata registry - Add 'amazon' to _alternate_sources() so it appears as a tab when another source is primary (always available, no credentials) - Add SERVICE_CONFIG_REGISTRY entry 'amazon': {'always': True} so /api/settings/config-status reports it as configured - Add SOURCE_LABELS['amazon'] and SOURCE_ORDER entry in shared-helpers.js so both enhanced search and global search show the Amazon Music tab - Add 'amazon' to _ALWAYS_CONFIGURED_SOURCES so the picker never dims the tab (no credentials required) - Add .enh-tab-amazon.active CSS (Amazon orange #FF9900) - 3530 tests pass --- core/search/orchestrator.py | 11 ++++++++++- web_server.py | 1 + webui/static/shared-helpers.js | 8 ++++++-- webui/static/style.css | 1 + 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/core/search/orchestrator.py b/core/search/orchestrator.py index da934759..a1961424 100644 --- a/core/search/orchestrator.py +++ b/core/search/orchestrator.py @@ -31,7 +31,7 @@ from . import sources logger = logging.getLogger(__name__) VALID_SOURCES = ( - 'spotify', 'itunes', 'deezer', 'discogs', 'hydrabase', 'musicbrainz', + 'spotify', 'itunes', 'deezer', 'discogs', 'hydrabase', 'musicbrainz', 'amazon', ) VALID_STREAM_SOURCES = VALID_SOURCES + ('youtube_videos',) @@ -88,6 +88,13 @@ def resolve_client(source_name: str, deps: SearchDeps) -> tuple[Any, bool]: except Exception as e: logger.warning(f"MusicBrainz search client init failed: {e}") return None, False + if source_name == 'amazon': + try: + from core.metadata.registry import get_amazon_client + return get_amazon_client(), True + except Exception as e: + logger.warning(f"Amazon Music client init failed: {e}") + return None, False return None, False @@ -183,6 +190,8 @@ def _alternate_sources(primary_source: str, deps: SearchDeps) -> list[str]: alts.append('discogs') if primary_source != 'hydrabase' and hydrabase_available: alts.append('hydrabase') + if primary_source != 'amazon': + alts.append('amazon') # always available (T2Tunes, no auth) alts.append('youtube_videos') # always available (yt-dlp, no auth) alts.append('musicbrainz') # always available (public API) return alts diff --git a/web_server.py b/web_server.py index 24f7f773..c9a774f2 100644 --- a/web_server.py +++ b/web_server.py @@ -1858,6 +1858,7 @@ SERVICE_CONFIG_REGISTRY = { 'spotify': {'required': ['client_id', 'client_secret']}, 'itunes': {'always': True}, # default storefront works anon 'deezer': {'always': True}, # anon search works, premium ARL is optional + 'amazon': {'always': True}, # T2Tunes proxy, no credentials required 'discogs': {'required': ['token']}, 'tidal': {'custom': lambda _svc: _tidal_has_auth_token()}, 'qobuz': {'any_of': [['email', 'password'], ['token'], ['user_auth_token']]}, diff --git a/webui/static/shared-helpers.js b/webui/static/shared-helpers.js index 6cf1da3d..82b86653 100644 --- a/webui/static/shared-helpers.js +++ b/webui/static/shared-helpers.js @@ -62,6 +62,10 @@ const SOURCE_LABELS = { logo: '/static/hydrabase.png', tabClass: 'enh-tab-hydrabase', badgeClass: 'enh-badge-hydrabase', }, + amazon: { + text: 'Amazon Music', icon: '🛒', + tabClass: 'enh-tab-amazon', badgeClass: 'enh-badge-amazon', + }, musicbrainz: { text: 'MusicBrainz', icon: '🧠', logo: 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/MusicBrainz_Logo_%282016%29.svg/500px-MusicBrainz_Logo_%282016%29.svg.png', @@ -82,7 +86,7 @@ const SOURCE_LABELS = { // Canonical display order for the source picker. Standard metadata sources // first, then YouTube Music Videos, then Soulseek (basic-file source). const SOURCE_ORDER = [ - 'spotify', 'itunes', 'deezer', 'discogs', 'hydrabase', 'musicbrainz', + 'spotify', 'itunes', 'deezer', 'discogs', 'hydrabase', 'amazon', 'musicbrainz', 'youtube_videos', 'soulseek', ]; @@ -91,7 +95,7 @@ const SOURCE_ORDER = [ // Soulseek IS configurable (needs slskd URL), so it's intentionally not here: // /api/settings/config-status reports its real state and the picker dims it // when no slskd is set up, redirecting clicks to Settings → Downloads. -const _ALWAYS_CONFIGURED_SOURCES = new Set(['musicbrainz', 'youtube_videos']); +const _ALWAYS_CONFIGURED_SOURCES = new Set(['amazon', 'musicbrainz', 'youtube_videos']); // Fetch /api/settings/config-status and return a map { src -> bool } // covering every source in SOURCE_ORDER. Sources not present in the backend diff --git a/webui/static/style.css b/webui/static/style.css index 074a4479..bffb0361 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -34545,6 +34545,7 @@ div.artist-hero-badge { .enh-source-tab.enh-tab-deezer.active { background: rgba(162, 56, 255, 0.2); color: #a238ff; } .enh-source-tab.enh-tab-discogs.active { background: rgba(212, 165, 116, 0.2); color: #D4A574; } .enh-source-tab.enh-tab-hydrabase.active { background: rgba(0, 180, 216, 0.2); color: #00b4d8; } +.enh-source-tab.enh-tab-amazon.active { background: rgba(255, 153, 0, 0.2); color: #FF9900; } .enh-source-tab.enh-tab-youtube.active { background: rgba(255, 0, 0, 0.2); color: #ff4444; } .enh-source-tab.enh-tab-musicbrainz.active { background: rgba(186, 51, 88, 0.2); color: #BA3358; }