Add Amazon Music as a primary metadata source
Wires AmazonClient into the metadata source registry following the exact same pattern as DeezerClient. No existing source paths touched. - Add get_album_metadata / get_artist_info / get_artist_albums_list aliases to AmazonClient (mirrors DeezerClient interface aliases) - Register amazon in METADATA_SOURCE_PRIORITY and METADATA_SOURCE_LABELS - Add _get_amazon_factory() + get_amazon_client() to registry.py - Add amazon branch to get_client_for_source(); thread amazon_client_factory kwarg through get_primary_client() and get_primary_source_status() - Re-export get_amazon_client from the core.metadata_service shim - Add Amazon Music option to Settings metadata source dropdown - 3530 tests pass
This commit is contained in:
parent
e8b9f80597
commit
1f579cede8
5 changed files with 40 additions and 2 deletions
|
|
@ -511,6 +511,11 @@ class AmazonClient:
|
||||||
"""Not available from Amazon Music — returns None for compatibility."""
|
"""Not available from Amazon Music — returns None for compatibility."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# ==================== Interface Aliases (match DeezerClient method names) ====================
|
||||||
|
get_album_metadata = get_album
|
||||||
|
get_artist_info = get_artist
|
||||||
|
get_artist_albums_list = get_artist_albums
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Private helpers
|
# Private helpers
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,14 @@ logger = get_logger("metadata.registry")
|
||||||
|
|
||||||
MetadataClientFactory = Callable[[], Any]
|
MetadataClientFactory = Callable[[], Any]
|
||||||
|
|
||||||
METADATA_SOURCE_PRIORITY = ("deezer", "itunes", "spotify", "discogs", "hydrabase")
|
METADATA_SOURCE_PRIORITY = ("deezer", "itunes", "spotify", "discogs", "hydrabase", "amazon")
|
||||||
METADATA_SOURCE_LABELS = {
|
METADATA_SOURCE_LABELS = {
|
||||||
"spotify": "Spotify",
|
"spotify": "Spotify",
|
||||||
"itunes": "iTunes",
|
"itunes": "iTunes",
|
||||||
"deezer": "Deezer",
|
"deezer": "Deezer",
|
||||||
"discogs": "Discogs",
|
"discogs": "Discogs",
|
||||||
"hydrabase": "Hydrabase",
|
"hydrabase": "Hydrabase",
|
||||||
|
"amazon": "Amazon Music",
|
||||||
}
|
}
|
||||||
|
|
||||||
_UNSET = object()
|
_UNSET = object()
|
||||||
|
|
@ -140,6 +141,14 @@ def _get_discogs_factory(client_factory: Optional[MetadataClientFactory]) -> Met
|
||||||
return DiscogsClient
|
return DiscogsClient
|
||||||
|
|
||||||
|
|
||||||
|
def _get_amazon_factory(client_factory: Optional[MetadataClientFactory]) -> MetadataClientFactory:
|
||||||
|
if client_factory is not None:
|
||||||
|
return client_factory
|
||||||
|
from core.amazon_client import AmazonClient
|
||||||
|
|
||||||
|
return AmazonClient
|
||||||
|
|
||||||
|
|
||||||
def get_spotify_client(client_factory: Optional[MetadataClientFactory] = None):
|
def get_spotify_client(client_factory: Optional[MetadataClientFactory] = None):
|
||||||
"""Get shared Spotify client.
|
"""Get shared Spotify client.
|
||||||
|
|
||||||
|
|
@ -260,6 +269,18 @@ def get_discogs_client(
|
||||||
return client
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
def get_amazon_client(client_factory: Optional[MetadataClientFactory] = None):
|
||||||
|
"""Get cached Amazon Music client."""
|
||||||
|
cache_key = "amazon"
|
||||||
|
factory = _get_amazon_factory(client_factory)
|
||||||
|
with _client_cache_lock:
|
||||||
|
client = _client_cache.get(cache_key)
|
||||||
|
if client is None:
|
||||||
|
client = factory()
|
||||||
|
_client_cache[cache_key] = client
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
def is_hydrabase_enabled() -> bool:
|
def is_hydrabase_enabled() -> bool:
|
||||||
"""Return True when Hydrabase is connected and app-enabled."""
|
"""Return True when Hydrabase is connected and app-enabled."""
|
||||||
try:
|
try:
|
||||||
|
|
@ -331,6 +352,7 @@ def get_primary_client(
|
||||||
itunes_client_factory: Optional[MetadataClientFactory] = None,
|
itunes_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
deezer_client_factory: Optional[MetadataClientFactory] = None,
|
deezer_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
discogs_client_factory: Optional[MetadataClientFactory] = None,
|
discogs_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
|
amazon_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
):
|
):
|
||||||
"""Return client for configured primary source."""
|
"""Return client for configured primary source."""
|
||||||
return get_client_for_source(
|
return get_client_for_source(
|
||||||
|
|
@ -339,6 +361,7 @@ def get_primary_client(
|
||||||
itunes_client_factory=itunes_client_factory,
|
itunes_client_factory=itunes_client_factory,
|
||||||
deezer_client_factory=deezer_client_factory,
|
deezer_client_factory=deezer_client_factory,
|
||||||
discogs_client_factory=discogs_client_factory,
|
discogs_client_factory=discogs_client_factory,
|
||||||
|
amazon_client_factory=amazon_client_factory,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -348,6 +371,7 @@ def get_primary_source_status(
|
||||||
itunes_client_factory: Optional[MetadataClientFactory] = None,
|
itunes_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
deezer_client_factory: Optional[MetadataClientFactory] = None,
|
deezer_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
discogs_client_factory: Optional[MetadataClientFactory] = None,
|
discogs_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
|
amazon_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Return a generic status snapshot for the active primary metadata source."""
|
"""Return a generic status snapshot for the active primary metadata source."""
|
||||||
source = _get_config_value("metadata.fallback_source", "deezer") or "deezer"
|
source = _get_config_value("metadata.fallback_source", "deezer") or "deezer"
|
||||||
|
|
@ -361,6 +385,7 @@ def get_primary_source_status(
|
||||||
itunes_client_factory=itunes_client_factory,
|
itunes_client_factory=itunes_client_factory,
|
||||||
deezer_client_factory=deezer_client_factory,
|
deezer_client_factory=deezer_client_factory,
|
||||||
discogs_client_factory=discogs_client_factory,
|
discogs_client_factory=discogs_client_factory,
|
||||||
|
amazon_client_factory=amazon_client_factory,
|
||||||
)
|
)
|
||||||
if source == "spotify":
|
if source == "spotify":
|
||||||
connected = bool(client and client.is_spotify_authenticated())
|
connected = bool(client and client.is_spotify_authenticated())
|
||||||
|
|
@ -387,6 +412,7 @@ def get_client_for_source(
|
||||||
itunes_client_factory: Optional[MetadataClientFactory] = None,
|
itunes_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
deezer_client_factory: Optional[MetadataClientFactory] = None,
|
deezer_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
discogs_client_factory: Optional[MetadataClientFactory] = None,
|
discogs_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
|
amazon_client_factory: Optional[MetadataClientFactory] = None,
|
||||||
):
|
):
|
||||||
"""Return exact client for a source, or None if unavailable."""
|
"""Return exact client for a source, or None if unavailable."""
|
||||||
if source == "spotify":
|
if source == "spotify":
|
||||||
|
|
@ -410,4 +436,7 @@ def get_client_for_source(
|
||||||
if source == "itunes":
|
if source == "itunes":
|
||||||
return get_itunes_client(client_factory=itunes_client_factory)
|
return get_itunes_client(client_factory=itunes_client_factory)
|
||||||
|
|
||||||
|
if source == "amazon":
|
||||||
|
return get_amazon_client(client_factory=amazon_client_factory)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ from core.metadata.registry import (
|
||||||
clear_cached_metadata_client,
|
clear_cached_metadata_client,
|
||||||
clear_cached_metadata_clients,
|
clear_cached_metadata_clients,
|
||||||
clear_cached_profile_spotify_client,
|
clear_cached_profile_spotify_client,
|
||||||
|
get_amazon_client,
|
||||||
get_client_for_source,
|
get_client_for_source,
|
||||||
get_deezer_client,
|
get_deezer_client,
|
||||||
get_discogs_client,
|
get_discogs_client,
|
||||||
|
|
@ -75,6 +76,7 @@ except Exception: # pragma: no cover - optional dependency fallback
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"METADATA_SOURCE_PRIORITY",
|
"METADATA_SOURCE_PRIORITY",
|
||||||
|
"get_amazon_client",
|
||||||
"MetadataCache",
|
"MetadataCache",
|
||||||
"MetadataLookupOptions",
|
"MetadataLookupOptions",
|
||||||
"MetadataProvider",
|
"MetadataProvider",
|
||||||
|
|
|
||||||
|
|
@ -3632,10 +3632,11 @@
|
||||||
<option value="itunes">iTunes / Apple Music</option>
|
<option value="itunes">iTunes / Apple Music</option>
|
||||||
<option value="deezer">Deezer</option>
|
<option value="deezer">Deezer</option>
|
||||||
<option value="discogs">Discogs</option>
|
<option value="discogs">Discogs</option>
|
||||||
|
<option value="amazon">Amazon Music</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="callback-info">
|
<div class="callback-info">
|
||||||
<div class="callback-help">Choose the primary source for artist, album, and track metadata. Spotify can only be selected while an active Spotify session exists. Discogs requires a personal token.</div>
|
<div class="callback-help">Choose the primary source for artist, album, and track metadata. Spotify can only be selected while an active Spotify session exists. Discogs requires a personal token. Amazon Music uses the T2Tunes proxy — no account needed.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3415,6 +3415,7 @@ function closeHelperSearch() {
|
||||||
const WHATS_NEW = {
|
const WHATS_NEW = {
|
||||||
'2.5.3': [
|
'2.5.3': [
|
||||||
{ unreleased: true },
|
{ unreleased: true },
|
||||||
|
{ title: 'Amazon Music Metadata Source', desc: 'Amazon Music is now a selectable primary metadata source alongside Spotify, iTunes, Deezer, and Discogs. backed by the same T2Tunes proxy as the download source — no account needed. covers track search, album lookup with cover art, and artist discography. select it under Settings → Connections → Metadata Source.', page: 'settings' },
|
||||||
{ title: 'Amazon Music Download Source', desc: 'new download source backed by T2Tunes proxy. searches the Amazon Music catalog, downloads 24-bit/48kHz FLAC (or Opus 320kbps / Dolby Atmos EAC3 fallback). codec waterfall mirrors Tidal/Qobuz — best quality first, auto-fallback. selectable as a standalone or hybrid source from Settings.', page: 'settings' },
|
{ title: 'Amazon Music Download Source', desc: 'new download source backed by T2Tunes proxy. searches the Amazon Music catalog, downloads 24-bit/48kHz FLAC (or Opus 320kbps / Dolby Atmos EAC3 fallback). codec waterfall mirrors Tidal/Qobuz — best quality first, auto-fallback. selectable as a standalone or hybrid source from Settings.', page: 'settings' },
|
||||||
],
|
],
|
||||||
'2.5.2': [
|
'2.5.2': [
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue