Source code for minim.api.qobuz._private_api.users

from __future__ import annotations
from typing import TYPE_CHECKING

from ..._shared import TTLCache, _copy_docstring
from ._shared import PrivateQobuzResourceAPI
from .favorites import PrivateFavoritesAPI

if TYPE_CHECKING:
    from typing import Any

    from ...._types import Collection


[docs] class PrivateUsersAPI(PrivateQobuzResourceAPI): """ Users API endpoints for the private Qobuz API. .. important:: This class is managed by :class:`~minim.api.qobuz.PrivateQobuzAPIClient` and should not be instantiated directly. """ __slots__ = ()
[docs] @TTLCache.cached_method(ttl="user") def get_me(self) -> dict[str, Any]: """ Get Qobuz profile information for the current user. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access private profile information. Returns ------- profile : dict[str, Any] Qobuz profile information for the current user. .. admonition:: Sample response :class: response dropdown .. code-block:: { "age": <int>, "avatar": <str>, "birthdate": <str>, "country": <str>, "country_code": <str>, "creation_date": <str>, "credential": { "description": <str>, "id": <int>, "label": <str>, "parameters": { "color_scheme": { "logo": <str> }, "hfp_purchase": <bool>, "hires_purchases_streaming": <bool>, "hires_streaming": <bool>, "included_format_group_ids": <list[int]>, "label": <str>, "lossless_streaming": <bool>, "lossy_streaming": <bool>, "mobile_streaming": <bool>, "offline_streaming": <bool>, "short_label": <str>, "source": <str> } }, "display_name": <str>, "email": <str>, "firstname": <str>, "genre": <str>, "id": <int>, "language_code": <str>, "last_update": { "favorite": <int>, "favorite_album": <int>, "favorite_artist": <int>, "favorite_award": <int>, "favorite_label": <int>, "favorite_track": <int>, "playlist": <int>, "purchase": <int> }, "lastname": <str>, "login": <str>, "publicId": <str>, "store": <str>, "store_features": { "autoplay": <bool>, "club": <bool>, "download": <bool>, "editorial": <bool>, "inapp_purchase_subscripton": <bool>, "music_import": <bool>, "opt_in": <bool>, "pre_register_opt_in": <bool>, "pre_register_zipcode": <bool>, "radio": <bool>, "stream_purchase": <bool>, "streaming": <bool>, "wallet": <bool>, "weeklyq": <bool> }, "subscription": { "end_date": <str>, "household_size_max": <int>, "is_canceled": <bool>, "offer": <str>, "periodicity": <str>, "start_date": <str> }, "zipcode": <str>, "zone": <str> } """ self._client._require_authentication("users.get_me") return self._client._request("GET", "user/get").json()
[docs] @TTLCache.cached_method(ttl="user") def get_my_last_updates(self) -> dict[str, dict[str, int]]: """ Get the timestamps for the last updates to favorites, playlists, and purchases performed by the current user. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access private profile information. Returns ------- last_updates : dict[str, dict[str, int]] Timestamps for the current user's last updates. .. admonition:: Sample response :class: response dropdown .. code-block:: { "last_update":{ "favorite": <int>, "favorite_album": <int>, "favorite_artist": <int>, "favorite_track": <int>, "playlist": <int>, "purchase": <int> } } """ self._client._require_authentication("users.get_last_update") return self._client._request("GET", "user/lastUpdate").json()
[docs] @TTLCache.cached_method(ttl="static") def login( self, username: str, password: str, /, *, device_uuid: str | None = None, device_model: str | None = None, device_os: str | None = None, device_platform: str | None = None, ) -> dict[str, Any]: """ Perform a credential-based login. Parameters ---------- username : str; positional-only Email or username. password : str; positional-only Password or its MD5 hash. device_uuid : str; keyword-only; optional UUID of the device running the client. If provided, the response will contain the Qobuz ID of the device to report streaming. **Example**: :code:`"16922031-0352-59D3-ADA2-B8E48236E8F0"`. device_model : str; keyword-only; optional Device model. **Example**: :code:`"Mac17,2"`. device_os : str; keyword-only; optional Device operating system. **Example**: :code:`"macOS 26.0"`. device_platform : str; keyword-only; optional Device platform. **Example**: :code:`"macOS-26.0-arm64"`. Returns ------- token : dict[str, Any] User authentication token and Qobuz profile information. .. admonition:: Sample response :class: response dropdown .. code-block:: { "user": { "age": <int>, "avatar": <str>, "birthdate": <str>, "country": <str>, "country_code": <str>, "creation_date": <str>, "credential": { "description": <str>, "id": <int>, "label": <str>, "parameters": { "color_scheme": { "logo": <str> }, "hfp_purchase": <bool>, "hires_purchases_streaming": <bool>, "hires_streaming": <bool>, "included_format_group_ids": <list[int]>, "label": <str>, "lossless_streaming": <bool>, "lossy_streaming": <bool>, "mobile_streaming": <bool>, "offline_streaming": <bool>, "short_label": <str>, "source": <str> } }, "device": { "device_manufacturer_id": <str>, "device_model": <str>, "device_os_version": <str>, "device_platform": <str>, "id": <int> }, "display_name": <str>, "email": <str>, "firstname": <str>, "genre": <str>, "id": <int>, "language_code": <str>, "last_update": { "favorite": <int>, "favorite_album": <int>, "favorite_artist": <int>, "favorite_award": <int>, "favorite_label": <int>, "favorite_track": <int>, "playlist": <int>, "purchase": <int> }, "lastname": <str>, "login": <str>, "publicId": <str>, "store": <str>, "store_features": { "autoplay": <bool>, "club": <bool>, "download": <bool>, "editorial": <bool>, "inapp_purchase_subscripton": <bool>, "music_import": <bool>, "opt_in": <bool>, "pre_register_opt_in": <bool>, "pre_register_zipcode": <bool>, "radio": <bool>, "stream_purchase": <bool>, "streaming": <bool>, "wallet": <bool>, "weeklyq": <bool> }, "subscription": { "end_date": <str>, "household_size_max": <int>, "is_canceled": <bool>, "offer": <str>, "periodicity": <str>, "start_date": <str> }, "zipcode": <str>, "zone": <str> }, "user_auth_token": <str> } """ self._validate_type("password", password, str) params = { "username": self._prepare_string("username", username), "password": password, } if device_uuid is not None: self._validate_uuids(device_uuid) params["device_manufacturer_id"] = device_uuid if device_model is not None: params["device_model"] = self._prepare_string( "device_model", device_model ) if device_os is not None: params["device_os_version"] = self._prepare_string( "device_os", device_os ) if device_platform is not None: params["device_platform"] = self._prepare_string( "device_platform", device_platform ) return self._client._request( "POST", "user/login", params=params ).json()
[docs] @_copy_docstring(PrivateFavoritesAPI.save_items) def save_items( self, *, album_ids: str | Collection[str] | None = None, artist_ids: int | str | Collection[int | str] | None = None, track_ids: int | str | Collection[int | str] | None = None, ) -> dict[str, str]: return self._client.favorites.save_items( album_ids=album_ids, artist_ids=artist_ids, track_ids=track_ids )
[docs] @_copy_docstring(PrivateFavoritesAPI.remove_saved_items) def remove_saved_items( self, *, album_ids: str | Collection[str] | None = None, artist_ids: int | str | Collection[int | str] | None = None, track_ids: int | str | Collection[int | str] | None = None, ) -> dict[str, str]: return self._client.favorites.remove_saved_items( album_ids=album_ids, artist_ids=artist_ids, track_ids=track_ids )
[docs] @_copy_docstring(PrivateFavoritesAPI.get_my_saved_items) def get_my_saved_items( self, item_type: str, /, *, limit: int | None = None, offset: int | None = None, ) -> dict[str, Any]: return self._client.favorites.get_my_saved_items( item_type, limit=limit, offset=offset )
[docs] @_copy_docstring(PrivateFavoritesAPI.get_my_saved_item_ids) def get_my_saved_item_ids(self) -> dict[str, Any]: return self._client.favorites.get_my_saved_item_ids()
[docs] @_copy_docstring(PrivateFavoritesAPI.is_item_saved) def is_item_saved( self, item_type: str, item_id: int | str, / ) -> dict[str, bool]: return self._client.favorites.is_item_saved(item_type, item_id)
[docs] @_copy_docstring(PrivateFavoritesAPI.toggle_item_saved) def toggle_item_saved( self, item_type: str, item_id: int | str, / ) -> dict[str, bool]: return self._client.favorites.toggle_item_saved(item_type, item_id)
[docs] @TTLCache.cached_method(ttl="user") def get_my_purchases( self, *, limit: int | None = None, offset: int | None = None ) -> dict[str, Any]: """ Get Qobuz catalog information for albums and tracks purchased by the current user. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access personal collection and favorites. Parameters ---------- limit : int; keyword-only; optional Maximum number of items to return. **Valid range**: :code:`1` to :code:`500`. **API default**: :code:`50`. offset : int; keyword-only; optional Index of the first item to return. Use with `limit` to get the next batch of items. **Minimum value**: :code:`0`. **API default**: :code:`0`. Returns ------- purchases : dict[str, Any] Page of Qobuz metadata for the current user's purchased albums and tracks. .. admonition:: Sample response :class: response dropdown .. code-block:: { "albums": { "items": [ { "articles": [], "artist": { "albums_count": <int>, "id": <int>, "image": None, "name": <str>, "picture": None, "slug": <str> }, "artists": [ { "id": <int>, "name": <str>, "roles": <list[str]> } ], "displayable": <bool>, "downloadable": <bool>, "downloadable_format_ids": <list[str]>, "duration": <int>, "genre": { "color": <int>, "id": <int>, "name": <int>, "path": <list[int]>, "slug": <str> }, "hires": <bool>, "hires_purchased": <bool>, "hires_streamable": <bool>, "id": <str>, "image": { "back": None, "large": <str>, "small": <str>, "thumbnail": <str> }, "label": { "albums_count": <int>, "id": <int>, "name": <str>, "slug": <str>, "supplier_id": <int> }, "maximum_bit_depth": <int>, "maximum_channel_count": <int>, "maximum_sampling_rate": <int>, "media_count": <int>, "order_id": <int>, "order_line_id": <int>, "parental_warning": <bool>, "popularity": <int>, "previewable": <bool>, "purchasable": <bool>, "purchasable_at": <int>, "purchased_at": <int>, "qobuz_id": <int>, "release_date_download": <str>, "release_date_original": <str>, "release_date_stream": <str>, "released_at": <int>, "sampleable": <bool>, "streamable": <bool>, "streamable_at": <int>, "title": <str>, "tracks_count": <int>, "upc": <str>, "url": <str>, "version": <str> } ], "limit": <int>, "offset": <int>, "total": <int> }, "tracks": { "items": [ { "album": { "artist": { "albums_count": <int>, "id": <int>, "image": None, "name": <str>, "picture": None, "slug": <str> }, "displayable": <bool>, "downloadable": <bool>, "duration": <int>, "genre": { "color": <int>, "id": <int>, "name": <int>, "path": <list[int]>, "slug": <str> }, "hires": <bool>, "hires_streamable": <bool>, "id": <str>, "image": { "large": <str>, "small": <str>, "thumbnail": <str> }, "label": { "albums_count": <int>, "id": <int>, "name": <str>, "slug": <str>, "supplier_id": <int> }, "maximum_bit_depth": <int>, "maximum_channel_count": <int>, "maximum_sampling_rate": <int>, "maximum_technical_specifications": <str>, "media_count": <int>, "parental_warning": <bool>, "previewable": <bool>, "purchasable": <bool>, "purchasable_at": <int>, "qobuz_id": <int>, "release_date_download": <str>, "release_date_original": <str>, "release_date_stream": <str>, "released_at": <int>, "sampleable": <bool>, "streamable": <bool>, "streamable_at": <int>, "title": <str>, "tracks_count": <int>, "upc": <str>, "version": <str> }, "audio_info": { "replaygain_track_gain": <float>, "replaygain_track_peak": <float> }, "composer": { "id": <int>, "name": <str> }, "copyright": <str>, "displayable": <bool>, "downloadable": <bool>, "downloadable_format_ids": <list[int]>, "duration": <int>, "hires": <bool>, "hires_purchased": <bool>, "hires_streamable": <bool>, "id": <int>, "isrc": <str>, "maximum_bit_depth": <int>, "maximum_channel_count": <int>, "maximum_sampling_rate": <float>, "media_number": <int>, "order_id": <int>, "order_line_id": <int>, "parental_warning": <bool>, "performer": { "id": <int>, "name": <str> }, "performers": <str>, "previewable": <bool>, "purchasable": <bool>, "purchasable_at": <int>, "purchased_at": <int>, "release_date_download": <str>, "release_date_original": <str>, "release_date_stream": <str>, "sampleable": <bool>, "streamable": <bool>, "streamable_at": <int>, "title": <str>, "track_number": <int>, "type": <str>, "version": <str>, "work": None } ], "limit": <int>, "offset": <int>, "total": <int> }, "user": {"id": <int>, "login": <str>} } """ self._client._require_authentication("purchases.get_my_purchases") return self._get_paginated_resources( "purchase/getUserPurchases", limit=limit, offset=offset )
[docs] @TTLCache.cached_method(ttl="user") def get_my_purchased_item_ids(self) -> dict[str, Any]: """ Get Qobuz IDs of albums and tracks purchased by the current user. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access personal collection and favorites. Returns ------- item_ids : dict[str, Any] Qobuz IDs of the current user's purchased albums and tracks. .. admonition:: Sample response :class: response dropdown .. code-block:: { "albums": { "items": [ { "id": <str> } ], "total": <int> }, "tracks": { "items": [ { "bought": <bool>, "id": <int> } ], "total": <int> }, "user": { "id": <int>, "login": <str> } } """ self._client._require_authentication( "purchases.get_my_purchased_item_ids" ) return self._client._request( "GET", "purchase/getUserPurchasesIds" ).json()
[docs] def follow_playlist(self, playlist_id: int | str, /) -> dict[str, str]: """ Favorite a playlist. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access and manage your library. Parameters ---------- playlist_id : int or str; positional-only Qobuz ID of the playlist. **Examples**: :code:`2776610`, :code:`"6754150"`. Returns ------- status : dict[str, str] Whether the playlist was favorited successfully. **Sample response**: :code:`{"status": "success"}`. """ self._client._require_authentication("playlists.follow_playlist") self._validate_qobuz_ids(playlist_id, recursive=False) return self._client._request( "POST", "playlist/subscribe", data={"playlist_id": playlist_id} ).json()
[docs] def unfollow_playlist(self, playlist_id: int | str, /) -> dict[str, str]: """ Unfavorite a playlist. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access and manage your library. Parameters ---------- playlist_id : int or str; positional-only Qobuz ID of the playlist. **Examples**: :code:`2776610`, :code:`"6754150"`. Returns ------- status : dict[str, str] Whether the playlist was unfavorited successfully. **Sample response**: :code:`{"status": "success"}`. """ self._client._require_authentication("playlists.follow_playlist") self._validate_qobuz_ids(playlist_id, recursive=False) return self._client._request( "POST", "playlist/unsubscribe", data={"playlist_id": playlist_id} ).json()
[docs] @TTLCache.cached_method(ttl="daily") def get_personalized_playlists(self) -> list[dict[str, Any]]: """ Get Qobuz catalog information for playlists curated for the current user. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access and manage your library. Returns ------- playlists : list[dict[str, Any]] Qobuz metadata for the curated playlists. .. admonition:: Sample response :class: response dropdown .. code-block:: [ { "baseline": <str>, "description": <str>, "graphics": { "background": <str>, "foreground": <str> }, "images": { "large": <str>, "small": <str> }, "step_pagination": <int>, "title": <str>, "type": <str> } ] """ self._client._require_authentication( "dynamic.get_personalized_playlists" ) return self._client._request("GET", "dynamic-tracks/list").json()
[docs] @TTLCache.cached_method(ttl="daily") def get_personalized_playlist_tracks( self, playlist_type: str, /, *, limit: int | None = None, offset: int | None = None, ) -> dict[str, Any]: """ Get Qobuz catalog information for tracks in a playlist curated for the current user. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access and manage your library. Parameters ---------- playlist_type : str; positional-only Type of the curated playlist. .. seealso:: :meth:`get_personalized_playlists` – Get types of curated playlists. **Example**: :code:`"weekly"`. limit : int; keyword-only; optional Maximum number of items to return. Only applicable when `playlist_type` is not :code:`"weekly"`. **Valid range**: :code:`1` to :code:`500`. **API default**: :code:`50`. offset : int; keyword-only; optional Index of the first item to return. Use with `limit` to get the next batch of items. Only applicable when `playlist_type` is not :code:`"weekly"`. **Minimum value**: :code:`0`. **API default**: :code:`0`. Returns ------- tracks : dict[str, Any] Page of Qobuz metadata for tracks in the curated playlist. .. admonition:: Sample response :class: response dropdown .. code-block:: { "baseline": <str>, "description": <str>, "duration": <int>, "expires_on": <int>, "generated_at": <int>, "graphics": { "background": <str>, "foreground": <str> }, "images": { "large": <str>, "small": <str> }, "step_pagination": <int>, "title": <str>, "track_count": <int>, "tracks": { "items": [ { "album": { "artist": { "albums_count": <int>, "id": <int>, "image": None, "name": <str>, "picture": None, "slug": <str> }, "displayable": <bool>, "downloadable": <bool>, "genre": { "id": <int>, "name": <str>, "path": <list[int]>, "slug": <str> }, "hires": <bool>, "hires_streamable": <bool>, "id": <str>, "image": { "large": <str>, "small": <str>, "thumbnail": <str> }, "label": { "albums_count": <int>, "id": <int>, "name": <str>, "slug": <str>, "supplier_id": <int> }, "maximum_bit_depth": <int>, "maximum_channel_count": <int>, "maximum_sampling_rate": <float>, "previewable": <bool>, "purchasable": <bool>, "purchasable_at": <str>, "qobuz_id": <int>, "release_date_download": <str>, "release_date_original": <str>, "release_date_purchase": <str>, "release_date_stream": <str>, "released_at": <int>, "sampleable": <bool>, "streamable": <bool>, "streamable_at": <int>, "title": <str>, "version": <str> }, "audio_info": { "replaygain_track_gain": <float>, "replaygain_track_peak": <float> }, "composer": { "id": <int>, "name": <str> }, "copyright": <str>, "displayable": <bool>, "downloadable": <bool>, "duration": <int>, "hires": <bool>, "hires_streamable": <bool>, "id": <int>, "isrc": <str>, "maximum_bit_depth": <int>, "maximum_channel_count": <int>, "maximum_sampling_rate": <float>, "parental_warning": <bool>, "performer": { "id": <int>, "name": <str>, }, "performers": <str>, "position": <int>, "previewable": <bool>, "purchasable": <bool>, "purchasable_at": <int>, "release_date_download": <str>, "release_date_original": <str>, "release_date_purchase": <str>, "release_date_stream": <str>, "sampleable": <bool>, "streamable": <bool>, "streamable_at": <int>, "title": <str>, "version": <str>, "work": None } ], "limit": <int>, "offset": <int> }, "type": <str> } """ self._client._require_authentication( "dynamic.get_personalized_playlist_tracks" ) return self._get_paginated_resources( "dynamic-tracks/get", limit=limit, offset=offset, params={ "type": self._prepare_string("playlist_type", playlist_type) }, )
[docs] @TTLCache.cached_method(ttl="popularity") def get_track_recommendations( self, seed_track_ids: int | str | Collection[int | str], /, exclude_track_ids: int | str | Collection[int | str] | None = None, *, limit: int | None = None, ) -> dict[str, Any]: """ Get track recommendations based on seed tracks. .. admonition:: User authentication :class: entitlement .. tab-set:: .. tab-item:: Required User authentication Access the :code:`POST /dynamic/suggest` endpoint. Parameters ---------- seed_track_ids : int | str | Collection[int | str]; \ positional-only Qobuz IDs of seed tracks. **Examples**: :code:`23929516`, :code:`"344521217"`, :code:`"23929516,344521217"`, :code:`[23929516, "344521217"]`. exclude_track_ids : int | str | Collection[int | str]; optional Qobuz IDs of tracks to exclude. **Examples**: :code:`256316240`, :code:`"53859680"`, :code:`"256316240,53859680"`, :code:`[256316240, "53859680"]`. limit : int; keyword-only; optional Maximum number of items to return. **Valid range**: :code:`1` to :code:`500`. **API default**: :code:`50`. Returns ------- recommendations : dict[str, Any] Qobuz metadata for the tracks recommended based on the seed tracks. .. admonition:: Sample response :class: response dropdown .. code-block:: { "algorithm": <str>, "tracks": { "items": [ { "album": { "artist": { "albums_count": <int>, "id": <int>, "image": None, "name": <str>, "picture": None, "slug": <str>, }, "displayable": <bool>, "downloadable": <bool>, "duration": <int>, "genre": { "id": <int>, "name": <str>, "path": <list[int]>, "slug": <str> }, "hires": <bool>, "hires_streamable": <bool>, "id": <str>, "image": { "large": <str>, "small": <str>, "thumbnail": <str> }, "label": { "albums_count": <int>, "id": <int>, "name": <str>, "slug": <str>, "supplier_id": <int> }, "maximum_bit_depth": <int>, "maximum_channel_count": <int>, "maximum_sampling_rate": <float>, "media_count": <int>, "parental_warning": <bool>, "popularity": <int>, "previewable": <bool>, "purchasable": <bool>, "purchasable_at": None, "qobuz_id": <int>, "release_date_download": <str>, "release_date_original": <str>, "release_date_stream": <str>, "released_at": <int>, "sampleable": <bool>, "streamable": <bool>, "streamable_at": <int>, "title": <str>, "tracks_count": <int>, "upc": <str>, "version": <str> }, "audio_info": { "replaygain_track_gain": <float>, "replaygain_track_peak": <float> }, "composer": { "id": <int>, "name": <str> }, "copyright": <str>, "displayable": <bool>, "downloadable": <bool>, "duration": <int>, "hires": <bool>, "hires_streamable": <bool>, "id": <int>, "isrc": <str>, "maximum_bit_depth": <int>, "maximum_channel_count": <int>, "maximum_sampling_rate": <float>, "media_number": <int>, "parental_warning": <bool>, "performer": { "id": <int>, "name": <str> }, "performers": <str>, "previewable": <bool>, "purchasable": <bool>, "purchasable_at": <int>, "sampleable": <bool>, "streamable": <bool>, "streamable_at": <int>, "title": <str>, "track_number": <int>, "version": <str>, "work": None } ], "limit": <int> } } """ self._client._require_authentication( "dynamic.get_track_recommendations" ) payload = { "track_to_analyse": self._prepare_qobuz_ids( seed_track_ids, data_type=dict ), "listened_tracks_ids": ( [] if exclude_track_ids is None else self._prepare_qobuz_ids(exclude_track_ids, data_type=list) ), } if limit is not None: self._validate_number("limit", limit, int, 1, 500) payload["limit"] = limit return self._client._request( "POST", "dynamic/suggest", json=payload ).json()