Source code for minim.api.spotify._web_api.search

from __future__ import annotations
from typing import TYPE_CHECKING

from ..._shared import TTLCache
from ._shared import SpotifyResourceAPI

if TYPE_CHECKING:
    from typing import Any

    from ...._types import Collection


[docs] class SearchAPI(SpotifyResourceAPI): """ Search API endpoints for the Spotify Web API. .. important:: This class is managed by :class:`~minim.api.spotify.SpotifyWebAPIClient` and should not be instantiated directly. """ _RESOURCE_TYPES = { "album", "artist", "audiobook", "episode", "playlist", "show", "track", } __slots__ = ()
[docs] @TTLCache.cached_method(ttl="search") def search( self, query: str, /, item_types: str | Collection[str], *, external_content: str | None = None, country_code: str | None = None, limit: int | None = None, offset: int | None = None, ) -> dict[str, Any]: """ `Search > Search for Item <https://developer.spotify.com /documentation/web-api/reference/search>`_: Search for albums, artists, playlists, tracks, shows, episodes, and/or audiobooks in the Spotify catalog. .. important:: Audiobooks are only available in the US, UK, Canada, Ireland, New Zealand, and Australia markets. .. admonition:: Third-party application mode :class: entitlement dropdown .. tab-set:: .. tab-item:: Optional Extended quota mode before November 27, 2024 Access 30-second preview URLs. `Learn more. <https://developer.spotify.com/blog /2024-11-27-changes-to-the-web-api>`__ Parameters ---------- query : str, positional-only Search query. .. tip:: Searches can be narrowed using field filters, such as :code:`album`, :code:`artist`, :code:`track`, :code:`year`, :code:`upc`, :code:`tag:hipster`, :code:`tag:new`, :code:`isrc`, and :code:`genre`. Each filter applies only to certain result types: * :code:`artist` and :code:`year` can be used when searching albums, artists and tracks. The :code:`year` filter accepts a year or a range (e.g., :code:`"year:1955-1960"`). * :code:`album` can be used when searching albums and tracks. * :code:`genre` can be used when searching artists and tracks. * :code:`isrc` and :code:`track` can be used when searching tracks. * :code:`upc`, :code:`tag:new`, and :code:`tag:hipster` can be used when searching albums. The :code:`tag:new` filter returns albums released in the past two weeks, and the :code:`tag:hipster` filter returns albums in the lowest 10% popularity. **Example**: :code:`"remaster track:Doxy artist:Miles Davis"`. item_types : str or Collection[str] Types of items to return. **Valid values**: :code:`"album"`, :code:`"artist"`, :code:`"playlist"`, :code:`"track"`, :code:`"show"`, :code:`"episode"`, :code:`"audiobook"`. **Examples**: :code:`"artist"`, :code:`"track,episode"`, :code:`["album", "playlist"]`. external_content : str; keyword-only; optional Externally hosted content that the client can play. **Valid value**: :code:`"audio"`. country_code : str; keyword-only; optional ISO 3166-1 alpha-2 country code. If provided, only content available in that market is returned. When a user access token accompanies the request, the country associated with the user account takes priority over this parameter. .. note:: If neither a country code is provided nor a country can be determined from the user account, the content is considered unavailable for the client. **Example**: :code:`"ES"`. limit : int; keyword-only; optional Maximum number of items to return. **Valid range**: :code:`1` to :code:`10`. **API default**: :code:`5`. offset : int; keyword-only; optional Index of the first item to return. Use with `limit` to get the next batch of items. **Valid range**: :code:`0` to :code:`1_000`. **Minimum value**: :code:`0`. **API default**: :code:`0`. Returns ------- items : dict[str, Any] Page of Spotify metadata for the matching catalog items. .. admonition:: Sample response :class: response dropdown .. code-block:: { "albums": { "href": <str>, "items": [ { "album_type": <str>, "artists": [ { "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "name": <str>, "type": "artist", "uri": <str> } ], "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "images": [ { "height": <int>, "url": <str>, "width": <int> } ], "is_playable": <bool>, "name": <str>, "release_date": <str>, "release_date_precision": <str>, "total_tracks": <int>, "type": "album", "uri": <str> } ], "limit": <int>, "next": <str>, "offset": <int>, "previous": <int>, "total": <int> }, "artists": { "href": <str>, "items": [ { "external_urls": { "spotify": <str> }, "followers": { "href": <str>, "total": <int> }, "genres": <list[str]>, "href": <str>, "id": <str>, "images": [ { "height": <int>, "url": <str>, "width": <int> } ], "name": <str>, "popularity": <int>, "type": "artist", "uri": <str> } ], "limit": <int>, "next": <str>, "offset": <int>, "previous": <int>, "total": <int> }, "audiobooks": { "href": <str>, "items": [ { "authors": [ { "name": <str> } ], "copyrights": <list[str]>, "description": <str>, "edition": <str>, "explicit": <bool>, "external_urls": { "spotify": <str> }, "href": <str>, "html_description": <str>, "id": <str>, "images": [ { "height": <int>, "url": <str>, "width": <int> } ], "is_externally_hosted": <bool>, "languages": <list[str]>, "media_type": <str>, "name": <str>, "narrators": [ { "name": <str> } ], "publisher": <str>, "total_chapters": <int>, "type": "audiobook", "uri": <str> } ], "limit": <int>, "next": <str>, "offset": <int>, "previous": <int>, "total": <int> }, "episodes": { "href": <str>, "items": [ { "audio_preview_url": <str>, "description": <str>, "duration_ms": <int>, "explicit": <bool>, "external_urls": { "spotify": <str> }, "href": <str>, "html_description": <str>, "id": <str>, "images": [ { "height": <int>, "url": <str>, "width": <int> } ], "is_externally_hosted": <bool>, "is_playable": <bool>, "language": <str>, "languages": <list[str]>, "name": <str>, "release_date": <str>, "release_date_precision": <str>, "resume_point": { "fully_played": <bool>, "resume_position_ms": <int> }, "type": "episode", "uri": <str> } ], "limit": <int>, "next": <str>, "offset": <int>, "previous": <int>, "total": <int> }, "playlists": { "href": <str>, "items": [ { "collaborative": <bool>, "description": <str>, "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "images": [ { "height": <int>, "url": <str>, "width": <int> } ], "name": <str>, "owner": { "display_name": <str>, "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "type": "user", "uri": <str> }, "primary_color": <str>, "public": <bool>, "snapshot_id": <str>, "tracks": { "href": <str>, "total": <int> }, "type": "playlist", "uri": <str> } ], "limit": <int>, "next": <str>, "offset": <int>, "previous": <int>, "total": <int> }, "shows": { "href": <str>, "items": [ { "copyrights": <list[str]>, "description": <str>, "explicit": <bool>, "external_urls": { "spotify": <str> }, "href": <str>, "html_description": <str>, "id": <str>, "images": [ { "height": <int>, "url": <str>, "width": <int> } ], "is_externally_hosted": <bool>, "languages": <list[str]>, "media_type": <str>, "name": <str>, "publisher": <str>, "total_episodes": <int>, "type": "show", "uri": <str> } ], "limit": <int>, "next": <str>, "offset": <int>, "previous": <int>, "total": <int> }, "tracks": { "href": <str>, "items": [ { "album": { "album_type": <str>, "artists": [ { "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "name": <str>, "type": "artist", "uri": <str> } ], "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "images": [ { "height": <int>, "url": <str>, "width": <int> } ], "is_playable": <bool>, "name": <str>, "release_date": <str>, "release_date_precision": <str>, "total_tracks": <int>, "type": "album", "uri": <str> }, "artists": [ { "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "name": <str>, "type": "artist", "uri": <str> } ], "disc_number": <int>, "duration_ms": <int>, "explicit": <bool>, "external_ids": { "isrc": <str> }, "external_urls": { "spotify": <str> }, "href": <str>, "id": <str>, "is_local": <bool>, "is_playable": <bool>, "name": <str>, "popularity": <int>, "preview_url": <str>, "track_number": <int>, "type": "track", "uri": <str> } ], "limit": <int>, "next": <str>, "offset": <int>, "previous": <int>, "total": <int> } } """ params = { "q": self._prepare_string("query", query), "type": self._prepare_types( item_types, allowed_types=self._RESOURCE_TYPES, type_prefix="item", ), } if external_content is not None: if external_content != "audio": raise ValueError( f"Invalid external content {external_content!r}. " "Valid value: 'audio'." ) params["include_external"] = external_content if country_code is not None: self._client.markets._validate_market(country_code) params["market"] = country_code if limit is not None: # Leave upper bound at 50 for Extended Quota Mode apps self._validate_number("limit", limit, int, 1, 50) params["limit"] = limit if offset is not None: self._validate_number("offset", offset, int, 0, 1_000) params["offset"] = offset return self._client._request("GET", "search", params=params).json()