Source code for minim.api.tidal._api.artists

from __future__ import annotations
from typing import TYPE_CHECKING

from ...._types import COLLECTION_TYPES, ORDERED_COLLECTION_TYPES
from ..._shared import TTLCache, _copy_docstring
from ._shared import TIDALResourceAPI
from .search import SearchAPI
from .users import UsersAPI

if TYPE_CHECKING:
    from typing import Any

    from ...._types import Collection


[docs] class ArtistsAPI(TIDALResourceAPI): """ Artist Roles and Artists API endpoints for the TIDAL API. .. important:: This class is managed by :class:`~minim.api.tidal.TIDALAPIClient` and should not be instantiated directly. """ _RELATIONSHIPS = { "albums", "biography", "followers", "following", "owners", "profileArt", "radio", "roles", "similarArtists", "trackProviders", "tracks", "videos", } __slots__ = ()
[docs] @TTLCache.cached_method(ttl="static") def get_roles( self, artist_role_ids: int | str | Collection[int | str], / ) -> dict[str, Any]: """ `Artist Roles > Get Single Artist Role <https://tidal-music.github.io/tidal-api-reference/#/artistRoles /get_artistRoles>`_: Get TIDAL catalog information for an artist role․ `Artist Roles > Get Multiple Artist Roles <https://tidal-music.github.io/tidal-api-reference/#/artistRoles /get_artistRoles__id_>`_: Get TIDAL catalog information for multiple artist roles. Parameters ---------- artist_role_ids : int, str, or Collection[int | str]; \ positional-only TIDAL IDs of the artist roles. **Examples**: :code:`1`, :code:`"2"`, :code:`[3, "4"]`. Returns ------- artist_roles : dict[str, Any] TIDAL catalog information for the artist roles. .. admonition:: Sample responses :class: response dropdown .. tab-set:: .. tab-item:: Single artist role .. code-block:: { "data": { "attributes": { "name": <str> }, "id": <str>, "type": "artistRoles" }, "links": { "self": <str> } } .. tab-item:: Multiple artist roles .. code-block:: { "data": [ { "attributes": { "name": <str> }, "id": <str>, "type": "artistRoles" } ], "links": { "self": <str> } } """ self._get_resources("artistRoles", artist_role_ids)
[docs] @TTLCache.cached_method(ttl="popularity") def get_artists( self, artist_ids: int | str | Collection[int | str] | None = None, /, *, handles: str | Collection[str] | None = None, owner_ids: int | str | Collection[int | str] | None = None, country_code: str | None = None, expand: str | Collection[str] | None = None, ) -> dict[str, Any]: """ `Artists > Get Single Artist <https://tidal-music.github.io /tidal-api-reference/#/artists/get_artists__id_>`_: Get TIDAL catalog information for an artist․ `Artists > Get Multiple Artists <https://tidal-music.github.io /tidal-api-reference/#/artists/get_artists>`_: Get TIDAL catalog information for multiple artists. .. admonition:: User authentication :class: entitlement dropdown .. tab-set:: .. tab-item:: Optional User authentication Access information for a resource's owners. .. important:: Exactly one of `artist_ids`, `handles`, or `owner_ids` must be provided. When `handles` or `owner_ids` is specified, the request will always be sent to the endpoint for multiple artists. Parameters ---------- artist_ids : int, str, or Collection[int | str]; \ positional-only; optional TIDAL IDs of the artists. **Examples**: :code:`1566`, :code:`"4676988"`, :code:`[1566, "4676988"]`. handles : str or Collection[str]; keyword-only; optional Artist handles. **Example**: :code:`"jayz"`. owner_ids : int, str, or Collection[int | str]; keyword-only; \ optional TIDAL IDs of the artist resources' owners. If authenticated, :code:`"me"` can be used in lieu of a TIDAL ID for the current user. **Examples**: :code:"me"`, :code:`123456`, :code:`"654321"`, :code:`[123456, "654321"]`. country_code : str; keyword-only; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. expand : str or Collection[str]; keyword-only; optional Related resources to include metadata for in the response. **Valid values**: :code:`"albums"`, :code:`"biography"`, :code:`"followers"`, :code:`"following"`, :code:`"owners"`, :code:`"profileArt"`, :code:`"radio"`, :code:`"roles"`, :code:`"similarArtists"`, :code:`"trackProviders"`, :code:`"tracks"`, :code:`"videos"`. **Examples**: :code:`"profileArt"`, :code:`["albums", "tracks"]`. Returns ------- artists : dict[str, Any] TIDAL metadata for the artists. .. admonition:: Sample responses :class: response dropdown .. tab-set:: .. tab-item:: Single artist .. code-block:: { "data": { "attributes": { "contributionsEnabled": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "name": <str>, "popularity": <float>, "spotlighted": <bool> }, "id": <str>, "relationships": { "albums": { "data": [ { "id": <str>, "type": "albums" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } }, "biography": { "data": { "id": <str>, "type": "artistBiographies" }, "links": { "self": <str> } }, "followers": { "data": [], "links": { "self": <str> } }, "following": { "data": [], "links": { "self": <str> } }, "owners": { "data": [], "links": { "self": <str> } }, "profileArt": { "data": [ { "id": <str>, "type": "artworks" } ], "links": { "self": <str> } }, "radio": { "data": [ { "id": <str>, "type": "playlists" } ], "links": { "self": <str> } }, "roles": { "data": [ { "id": <str>, "type": "artistRoles" } ], "links": { "self": <str> } }, "similarArtists": { "links": { "self": <str> } }, "trackProviders": { "links": { "self": <str> } }, "tracks": { "links": { "self": <str> } }, "videos": { "links": { "self": <str> } } }, "type": "artists" }, "included": [ { "attributes": { "accessType": <str>, "availability": <list[str]>, "barcodeId": <str>, "copyright": { "text": <str> }, "duration": <str>, "explicit": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "mediaTags": <list[str]>, "numberOfItems": <int>, "numberOfVolumes": <int>, "popularity": <float>, "releaseDate": <str>, "title": <str>, "type": "ALBUM" }, "id": <str>, "relationships": { "artists": { "links": { "self": <str> } }, "coverArt": { "links": { "self": <str> } }, "genres": { "links": { "self": <str> } }, "items": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } }, "providers": { "links": { "self": <str> } }, "similarAlbums": { "links": { "self": <str> } }, "suggestedCoverArts" : { "links": { "self": <str> } } }, "type": "albums" }, { "attributes": { "name": <str> }, "id": <str>, "type": "artistRoles" }, { "attributes": { "files": [ { "href": <str>, "meta": { "height": <int>, "width": <int> } } ], "mediaType": "IMAGE" }, "id": <str>, "relationships": { "owners": { "links": { "self": <str> } } }, "type": "artworks" }, { "attributes": { "accessType": <str>, "bounded": <bool>, "createdAt": <str>, "description": "Artist Radio", "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "lastModifiedAt": <str>, "name": <str>, "playlistType": "MIX" }, "id": <str>, "relationships": { "coverArt": { "links": { "self": <str> } }, "items": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } } }, "type": "playlists" }, { "attributes": { "contributionsEnabled": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "name": <str>, "popularity": <float>, "spotlighted": <bool> }, "id": <str>, "relationships": { "albums": { "links": { "self": <str> } }, "biography": { "links": { "self": <str> } }, "followers": { "links": { "self": <str> } }, "following": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } }, "profileArt": { "links": { "self": <str> } }, "radio": { "links": { "self": <str> } }, "roles": { "links": { "self": <str> } }, "similarArtists": { "links": { "self": <str> } }, "trackProviders": { "links": { "self": <str> } }, "tracks": { "links": { "self": <str> } }, "videos": { "links": { "self": <str> } } }, "type": "artists" }, { "attributes": { "name": <str> }, "id": <str>, "type": "providers" }, { "attributes": { "copyright": { "text": <str> }, "duration": <str>, "explicit": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "isrc": <str>, "popularity": <float>, "releaseDate": <str>, "title": <str> }, "id": <str>, "relationships": { "albums": { "links": { "self": <str> } }, "artists": { "links": { "self": <str> } }, "providers": { "links": { "self": <str> } }, "thumbnailArt": { "links": { "self": <str> } } }, "type": "videos" } ], "links": { "self": <str> } } .. tab-item:: Multiple artists .. code-block:: { "data": [ { "attributes": { "contributionsEnabled": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "name": <str>, "popularity": <float>, "spotlighted": <bool> }, "id": <str>, "relationships": { "albums": { "data": [ { "id": <str>, "type": "albums" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } }, "biography": { "data": { "id": <str>, "type": "artistBiographies" }, "links": { "self": <str> } }, "followers": { "data": [], "links": { "self": <str> } }, "following": { "data": [], "links": { "self": <str> } }, "owners": { "data": [], "links": { "self": <str> } }, "profileArt": { "data": [ { "id": <str>, "type": "artworks" } ], "links": { "self": <str> } }, "radio": { "data": [ { "id": <str>, "type": "playlists" } ], "links": { "self": <str> } }, "roles": { "data": [ { "id": <str>, "type": "artistRoles" } ], "links": { "self": <str> } }, "similarArtists": { "links": { "self": <str> } }, "trackProviders": { "links": { "self": <str> } }, "tracks": { "links": { "self": <str> } }, "videos": { "links": { "self": <str> } } }, "type": "artists" } ], "included": [ { "attributes": { "accessType": <str>, "availability": <list[str]>, "barcodeId": <str>, "copyright": { "text": <str> }, "duration": <str>, "explicit": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "mediaTags": <list[str]>, "numberOfItems": <int>, "numberOfVolumes": <int>, "popularity": <float>, "releaseDate": <str>, "title": <str>, "type": "ALBUM" }, "id": <str>, "relationships": { "artists": { "links": { "self": <str> } }, "coverArt": { "links": { "self": <str> } }, "genres": { "links": { "self": <str> } }, "items": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } }, "providers": { "links": { "self": <str> } }, "similarAlbums": { "links": { "self": <str> } }, "suggestedCoverArts" : { "links": { "self": <str> } } }, "type": "albums" }, { "attributes": { "name": <str> }, "id": <str>, "type": "artistRoles" }, { "attributes": { "files": [ { "href": <str>, "meta": { "height": <int>, "width": <int> } } ], "mediaType": "IMAGE" }, "id": <str>, "relationships": { "owners": { "links": { "self": <str> } } }, "type": "artworks" }, { "attributes": { "accessType": <str>, "bounded": <bool>, "createdAt": <str>, "description": "Artist Radio", "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "lastModifiedAt": <str>, "name": <str>, "playlistType": "MIX" }, "id": <str>, "relationships": { "coverArt": { "links": { "self": <str> } }, "items": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } } }, "type": "playlists" }, { "attributes": { "contributionsEnabled": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "name": <str>, "popularity": <float>, "spotlighted": <bool> }, "id": <str>, "relationships": { "albums": { "links": { "self": <str> } }, "biography": { "links": { "self": <str> } }, "followers": { "links": { "self": <str> } }, "following": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } }, "profileArt": { "links": { "self": <str> } }, "radio": { "links": { "self": <str> } }, "roles": { "links": { "self": <str> } }, "similarArtists": { "links": { "self": <str> } }, "trackProviders": { "links": { "self": <str> } }, "tracks": { "links": { "self": <str> } }, "videos": { "links": { "self": <str> } } }, "type": "artists" }, { "attributes": { "name": <str> }, "id": <str>, "type": "providers" }, { "attributes": { "copyright": { "text": <str> }, "duration": <str>, "explicit": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "isrc": <str>, "popularity": <float>, "releaseDate": <str>, "title": <str> }, "id": <str>, "relationships": { "albums": { "links": { "self": <str> } }, "artists": { "links": { "self": <str> } }, "providers": { "links": { "self": <str> } }, "thumbnailArt": { "links": { "self": <str> } } }, "type": "videos" } ], "links": { "self": <str> } } """ if ( sum(arg is not None for arg in (artist_ids, handles, owner_ids)) != 1 ): raise ValueError( "Exactly one of `artist_ids`, `handles`, or " "`owner_ids` must be provided." ) params = {} if handles is not None: if isinstance(handles, COLLECTION_TYPES): handles = [ self._prepare_string(f"handles[{idx}]", handle) for idx, handle in enumerate(handles) ] elif not isinstance(handles, str): raise ValueError( "`handles` must be a string or a collection of strings." ) params["handle"] = handles elif owner_ids is not None: self._validate_tidal_ids(owner_ids) params["filter[owners.id]"] = ( owner_ids if isinstance(owner_ids, ORDERED_COLLECTION_TYPES) else sorted(owner_ids) ) return self._get_resources( "artists", artist_ids, country_code=country_code, expand=expand, params=params, )
[docs] @TTLCache.cached_method(ttl="popularity") def get_artist_albums( self, artist_id: int | str, /, country_code: str | None = None, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Albums Relationship <https://tidal-music.github.io/tidal-api-reference/#/artists /get_artists__id__relationships_albums>`_: Get TIDAL catalog information for albums by an artist. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's albums. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- albums : dict[str, Any] Page of TIDAL metadata for the artist's albums. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "type": "albums" } ], "included": [ { "attributes": { "accessType": <str>, "availability": <list[str]>, "barcodeId": <str>, "copyright": { "text": <str> }, "duration": <str>, "explicit": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "mediaTags": <list[str]>, "numberOfItems": <int>, "numberOfVolumes": <int>, "popularity": <float>, "releaseDate": <str>, "title": <str>, "type": "ALBUM" }, "id": <str>, "relationships": { "artists": { "links": { "self": <str> } }, "coverArt": { "links": { "self": <str> } }, "genres": { "links": { "self": <str> } }, "items": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } }, "providers": { "links": { "self": <str> } }, "similarAlbums": { "links": { "self": <str> } }, "suggestedCoverArts" : { "links": { "self": <str> } } }, "type": "albums" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "albums", country_code=country_code, include_metadata=include_metadata, cursor=cursor, )
[docs] @TTLCache.cached_method(ttl="static") def get_artist_biography( self, artist_id: int | str, /, country_code: str | None = None, *, include_metadata: bool = False, ) -> dict[str, Any]: """ `Artists > Get Biography Relationship <https://tidal-music.github.io /tidal-api-reference/#/artists /get_artists__id__relationships_biography>`_: Get an artist's biography. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's biography. Returns ------- biography : dict[str, Any] TIDAL metadata for the artist's biography. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": { "id": <str>, "type": "artistBiographies" }, "included": [], "links": { "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "biography", country_code=country_code, include_metadata=include_metadata, )
[docs] @TTLCache.cached_method(ttl="static") def get_artist_owners( self, artist_id: int | str, /, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Owners Relationship <https://tidal-music.github.io/tidal-api-reference/#/artists /get_artists__id__relationships_owners>`_: Get TIDAL profile information for the owners of an artist resource. .. admonition:: User authentication :class: entitlement dropdown .. tab-set:: .. tab-item:: Optional User authentication Access information for a resource's owners. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the owners. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- owners : dict[str, Any] Page of TIDAL profile information for the artist resource's owners. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [], "included": [], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "owners", include_metadata=include_metadata, cursor=cursor, )
[docs] @TTLCache.cached_method(ttl="static") def get_artist_profile_art( self, artist_id: int | str, /, country_code: str | None = None, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Profile Art Relationship <https://tidal-music.github.io/tidal-api-reference/#/artists /get_artists__id__relationships_profileArt>`_: Get TIDAL catalog information for the profile art for an artist. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's profile art. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- profile_art : dict[str, Any] Page of TIDAL metadata for the artist's profile art. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "type": "artworks" } ], "included": [ { "attributes": { "files": [ { "href": <str>, "meta": { "height": <int>, "width": <int> } } ], "mediaType": "IMAGE" }, "id": <str>, "relationships": { "owners": { "links": { "self": <str> } } }, "type": "artworks" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "profileArt", country_code=country_code, include_metadata=include_metadata, cursor=cursor, )
[docs] @TTLCache.cached_method(ttl="daily") def get_artist_mix( self, artist_id: int | str, /, country_code: str | None = None, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Radio Relationship <https://tidal-music.github.io /tidal-api-reference/#/artists /get_artists__id__relationships_radio>`_: Get TIDAL catalog information for an artist's mix. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's mix. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- mix : dict[str, Any] Page of TIDAL metadata for the artist's mix. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "type": "playlists" } ], "included": [ { "attributes": { "accessType": <str>, "bounded": <bool>, "createdAt": <str>, "description": "Artist Radio", "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "lastModifiedAt": <str>, "name": <str>, "playlistType": "MIX" }, "id": <str>, "relationships": { "coverArt": { "links": { "self": <str> } }, "items": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } } }, "type": "playlists" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "radio", country_code=country_code, include_metadata=include_metadata, cursor=cursor, )
[docs] @TTLCache.cached_method(ttl="daily") def get_artist_roles( self, artist_id: int | str, /, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Roles Relationship <https://tidal-music.github.io/tidal-api-reference/#/artists /get_artists__id__relationships_artistRoles>`_: Get TIDAL catalog information for an artist's roles. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's roles. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- roles : dict[str, Any] Page of TIDAL metadata for the artist's roles. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "type": "artistRoles" } ], "included": [ { "attributes": { "name": <str> }, "id": <str>, "type": "artistRoles" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "roles", include_metadata=include_metadata, cursor=cursor, )
[docs] @TTLCache.cached_method(ttl="popularity") def get_similar_artists( self, artist_id: int | str, /, country_code: str | None = None, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Similar Artists Relationship <https://tidal-music.github.io/tidal-api-reference/#/artists /get_artists__id__relationships_similarArtists>`_: Get TIDAL catalog information for similar artists Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the similar artists. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- artists : dict[str, Any] Page of TIDAL metadata for the similar artists. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "type": "artists" } ], "included": [ { "attributes": { "contributionsEnabled": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "name": <str>, "popularity": <float>, "spotlighted": <bool> }, "id": <str>, "relationships": { "albums": { "links": { "self": <str> } }, "biography": { "links": { "self": <str> } }, "followers": { "links": { "self": <str> } }, "following": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } }, "profileArt": { "links": { "self": <str> } }, "radio": { "links": { "self": <str> } }, "roles": { "links": { "self": <str> } }, "similarArtists": { "links": { "self": <str> } }, "trackProviders": { "links": { "self": <str> } }, "tracks": { "links": { "self": <str> } }, "videos": { "links": { "self": <str> } } }, "type": "artists" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "similarArtists", country_code=country_code, include_metadata=include_metadata, cursor=cursor, )
[docs] @TTLCache.cached_method(ttl="daily") def get_artist_track_providers( self, artist_id: int | str, /, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Track Providers <https://tidal-music.github.io /tidal-api-reference/#/artists /get_artists__id__relationships_trackProviders>`_: Get TIDAL catalog information for the providers of an artist's tracks. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's track providers. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- providers : dict[str, Any] Page of TIDAL metadata for the artist's track providers. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "meta": { "numberOfTracks": <int> }, "type": "providers" } ], "included": [ { "attributes": { "name": <str> }, "id": <str>, "type": "providers" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "trackProviders", include_metadata=include_metadata, cursor=cursor, )
[docs] @TTLCache.cached_method(ttl="popularity") def get_artist_tracks( self, artist_id: int | str, /, country_code: str | None = None, *, group_by: str = "FINGERPRINT", include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Tracks Relationship <https://tidal-music.github.io/tidal-api-reference/#/artists /get_artists__id__relationships_tracks>`_: Get TIDAL catalog information for tracks by an artist. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. group_by : str; keyword-only; default: :code:`"FINGERPRINT"` How the returned tracks are grouped. **Valid values**: * :code:`"FINGERPRINT"` – Collapses tracks that share the same audio fingerprint. * :code:`"ID"` – Returns every track as a separate item. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's tracks. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- tracks : dict[str, Any] Page of TIDAL metadata for the artist's tracks. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "type": "tracks" } ], "included": [ { "attributes": { "accessType": <str>, "availability": <list[str]>, "bpm": <float>, "copyright": { "text": <str> }, "duration": <str>, "explicit": <bool>, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "isrc": <str>, "key": <str>, "keyScale": <str>, "mediaTags": <list[str]>, "popularity": <float>, "spotlighted": <bool>, "title": <str>, "toneTags": <list[str]>, "version": <str> }, "id": <str>, "relationships": { "albums": { "links": { "self": <str> } }, "artists": { "links": { "self": <str> } }, "genres": { "links": { "self": <str> } }, "lyrics": { "links": { "self": <str> } }, "owners": { "links": { "self": <str> } }, "providers": { "links": { "self": <str> } }, "radio": { "links": { "self": <str> } }, "shares": { "links": { "self": <str> } }, "similarTracks": { "links": { "self": <str> } }, "sourceFile": { "links": { "self": <str> } }, "trackStatistics": { "links": { "self": <str> } } }, "type": "tracks" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ group_by = group_by.strip().upper() if group_by not in {"FINGERPRINT", "ID"}: raise ValueError( f"Cannot group tracks by {group_by!r}. " "Valid values: 'FINGERPRINT', 'ID'." ) return self._get_resource_relationship( "artists", artist_id, "tracks", country_code=country_code, include_metadata=include_metadata, cursor=cursor, params={"collapseBy": group_by}, )
[docs] @TTLCache.cached_method(ttl="popularity") def get_artist_videos( self, artist_id: int | str, /, country_code: str | None = None, *, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: """ `Artists > Get Videos Relationship <https://tidal-music.github.io/tidal-api-reference/#/artists /get_artists__id__relationships_videos>`_: Get TIDAL catalog information for videos by an artist. Parameters ---------- artist_id : int or str; positional-only TIDAL ID of the artist. **Examples**: :code:`1566`, :code:`"4676988"`. country_code : str; optional ISO 3166-1 alpha-2 country code. **Example**: :code:`"US"`. include_metadata : bool; keyword-only; default: :code:`False` Whether to include metadata for the artist's videos. cursor : str; keyword-only; optional Cursor for fetching the next page of results. **Example**: :code:`"3nI1Esi"`. Returns ------- videos : dict[str, Any] Page of TIDAL metadata for the artist's videos. .. admonition:: Sample response :class: response dropdown .. code-block:: { "data": [ { "id": <str>, "type": "videos" } ], "included": [ { "attributes": { "copyright": { "text": <str> }, "duration": <str>, "explicit": false, "externalLinks": [ { "href": <str>, "meta": { "type": <str> } } ], "isrc": <str>, "popularity": <float>, "releaseDate": <str>, "title": <str> }, "id": <str>, "relationships": { "albums": { "links": { "self": <str> } }, "artists": { "links": { "self": <str> } }, "providers": { "links": { "self": <str> } }, "thumbnailArt": { "links": { "self": <str> } } }, "type": "videos" } ], "links": { "meta": { "nextCursor": <str> }, "next": <str>, "self": <str> } } """ return self._get_resource_relationship( "artists", artist_id, "videos", country_code=country_code, include_metadata=include_metadata, cursor=cursor, )
[docs] @_copy_docstring(SearchAPI.search_artists) def search_artists( self, query: str, /, country_code: str | None = None, *, include_explicit: bool | None = None, include_metadata: bool = False, cursor: str | None = None, ) -> dict[str, Any]: return self._client.search.search_artists( query, country_code=country_code, include_explicit=include_explicit, include_metadata=include_metadata, cursor=cursor, )
[docs] @_copy_docstring(UsersAPI.get_artist_collection) def get_artist_collection( self, collection_id: str | None = None, /, *, country_code: str | None = None, locale: str | None = None, expand: str | Collection[str] | None = None, ) -> dict[str, Any]: return self._client.users.get_artist_collection( collection_id=collection_id, country_code=country_code, locale=locale, expand=expand, )
[docs] @_copy_docstring(UsersAPI.get_user_followed_artists) def get_user_followed_artists( self, *, collection_id: str | None = None, user_id: int | str | None = None, country_code: str | None = None, locale: str | None = None, include_metadata: bool = False, cursor: str | None = None, sort_by: str | None = None, descending: bool | None = None, ) -> dict[str, Any]: return self._client.users.get_user_followed_artists( collection_id=collection_id, user_id=user_id, country_code=country_code, locale=locale, include_metadata=include_metadata, cursor=cursor, sort_by=sort_by, descending=descending, )
[docs] @_copy_docstring(UsersAPI.follow_artists) def follow_artists( self, artist_ids: int | str | dict[str, int | str] | list[int | str | dict[str, int | str]], /, *, collection_id: str | None = None, user_id: int | str | None = None, country_code: str | None = None, ) -> None: self._client.users.follow_artists( artist_ids, collection_id=collection_id, user_id=user_id, country_code=country_code, )
[docs] @_copy_docstring(UsersAPI.unfollow_artists) def unfollow_artists( self, artist_ids: int | str | dict[str, int | str] | list[int | str | dict[str, int | str]], /, *, collection_id: str | None = None, user_id: int | str | None = None, country_code: str | None = None, ) -> None: self._client.users.unfollow_artists( artist_ids, collection_id=collection_id, user_id=user_id, country_code=country_code, )