from typing import Any from pydantic import SecretStr from resonance_engine.adapters.amazon_music import AmazonMusicClient from resonance_engine.dsp.backends.base import DSPBackend from resonance_engine.dsp.enums import DSPId from resonance_engine.dsp.exceptions import DSPResourceUnsupportedError from resonance_engine.dsp.types import TokenResult from resonance_engine.utils.functional import exclude # Art URLs stripped from every object before the sink. The Music Web API is in # closed beta — the noise key set may need confirming against live responses. _EXCLUDE_KEYS = frozenset( { "images", "art", "artwork", "url", "visibility", "playbackVisibility", "playParams", "playbackAvailability", "eligibility", } ) class AmazonMusicDSPBackend(DSPBackend): dsp_id = DSPId.amazon def __init__(self, client: AmazonMusicClient) -> None: self._client = client def close(self) -> None: self._client.close() def refresh_token(self, refresh_token: SecretStr) -> TokenResult: response = self._client.refresh_token(refresh_token) result = TokenResult(access_token=response["access_token"]) new_refresh_token = response.get("refresh_token") if new_refresh_token: result["refresh_token"] = new_refresh_token return result def get_profile(self, access_token: SecretStr) -> dict[str, Any]: return exclude( self._client.get_current_user_profile(access_token), keys=_EXCLUDE_KEYS, recursive=True, ) def get_top_artists(self, access_token: SecretStr) -> list[dict[str, Any]]: # noqa: ARG002 raise DSPResourceUnsupportedError("Amazon Music has no top artists endpoint") def get_top_tracks(self, access_token: SecretStr) -> list[dict[str, Any]]: # noqa: ARG002 raise DSPResourceUnsupportedError("Amazon Music has no top tracks endpoint") def get_recently_played( self, access_token: SecretStr, *, after: int | None = None, # noqa: ARG002 — Amazon paginates by opaque cursor ) -> list[dict[str, Any]]: return exclude( self._client.get_current_user_recently_played(access_token, max_items=60), keys=_EXCLUDE_KEYS, recursive=True, ) def get_playlists(self, access_token: SecretStr) -> list[dict[str, Any]]: return exclude( self._client.get_current_user_playlists(access_token, max_items=100), keys=_EXCLUDE_KEYS, recursive=True, ) def get_saved_albums(self, access_token: SecretStr) -> list[dict[str, Any]]: # noqa: ARG002 raise DSPResourceUnsupportedError("Amazon Music has no saved albums endpoint") def get_saved_tracks(self, access_token: SecretStr) -> list[dict[str, Any]]: # noqa: ARG002 raise DSPResourceUnsupportedError("Amazon Music library tracks return only IDs") def get_followed_artists(self, access_token: SecretStr) -> list[dict[str, Any]]: return exclude( self._client.get_current_user_followed_artists(access_token, max_items=100), keys=_EXCLUDE_KEYS, recursive=True, )