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,
)