From 354871d7bc132a32a6905e668f4c4c5c881a4213 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Sat, 6 May 2023 09:08:49 +0100 Subject: [PATCH 01/18] Update setup.py Refactor code to adhere to PEP8 style guide and maintain consistency in the use of double quotes. Defined variables using clear and concise names that follow standard Python naming conventions. --- setup.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index dd1ab177..9de919de 100644 --- a/setup.py +++ b/setup.py @@ -1,32 +1,37 @@ +# Import required packages from setuptools import setup -with open("README.md", "r") as f: - long_description = f.read() +# Open the README file and read the contents into a variable +with open("README.md", "r") as readme_file: + long_description = readme_file.read() -test_reqs = [ - 'mock==2.0.0' +# Define lists of test and documentation requirements +test_requirements = [ + "mock==2.0.0" ] -doc_reqs = [ - 'Sphinx>=1.5.2' +doc_requirements = [ + "Sphinx>=1.5.2" ] -extra_reqs = { - 'doc': doc_reqs, - 'test': test_reqs +# Define a dictionary of extra requirements +extra_requirements = { + "doc": doc_requirements, + "test": test_requirements } +# Configure the setup function with required and optional parameters setup( - name='spotipy', - version='2.23.0', - description='A light weight Python library for the Spotify Web API', + name="spotipy", + version="2.23.0", + description="A lightweight Python library for the Spotify Web API", long_description=long_description, long_description_content_type="text/markdown", author="@plamere", author_email="paul@echonest.com", - url='https://spotipy.readthedocs.org/', + url="https://spotipy.readthedocs.org/", project_urls={ - 'Source': 'https://github.com/plamere/spotipy', + "Source": "https://github.com/plamere/spotipy", }, install_requires=[ "redis>=3.5.3", @@ -35,7 +40,8 @@ "six>=1.15.0", "urllib3>=1.26.0" ], - tests_require=test_reqs, - extras_require=extra_reqs, - license='MIT', - packages=['spotipy']) + tests_require=test_requirements, + extras_require=extra_requirements, + license="MIT", + packages=["spotipy"] +) From a8b566201bad854cfee0c120962025d74e727cbb Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Sat, 6 May 2023 17:27:38 +0100 Subject: [PATCH 02/18] Update index.rst Rewrote Installation section with instructions on installing spotipy on windows, macOS, and linux systems. Added User Guide section detailing use on features such as retrieving user data and searching for music. Added Troubleshooting section detailing some common problems encountered and suggested fixes. --- docs/index.rst | 124 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 111 insertions(+), 13 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index a6fa61b8..21aed212 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -76,32 +76,77 @@ API `_ documentation. Installation ============ -Install or upgrade *Spotipy* with:: +**Installing Spotipy on Windows**: + +- Install Python: Download and install Python from the official Python website (https://www.python.org/downloads/). + +- Install Spotipy: Open a command prompt and run pip install spotipy. +Open command prompt and run the following:: + + pip install spotipy + +- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. + +**Installing Spotipy on macOS**: + + +- Install Homebrew: Install Homebrew, a package manager for macOS. + +- Run the followng command:: + + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + +- Install Python: Run brew install python in the terminal:: + + brew install python + +- Install Spotipy: Run pip install spotipy in the terminal:: + + pip install spotipy + +- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. + +**Installing Spotipy on Linux**: + +- Install Python: Use your Linux distribution's package manager to install Python using the following command:: + + sudo apt-get install python3 + +- Install pip: Use your Linux distribution's package manager to install pip using the command:: + + sudo apt-get install python3-pip + +- Install Spotipy: Run pip install spotipy in the terminal. + + pip install spotipy + +- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. + + + .. Install or upgrade *Spotipy* with:: pip install spotipy --upgrade -Or you can get the source from github at https://github.com/plamere/spotipy +You can get the source from github at https://github.com/plamere/spotipy -Getting Started +Getting Started with Spotipy =============== -All methods require user authorization. You will need to register your app at -`My Dashboard `_ -to get the credentials necessary to make authorized calls -(a *client id* and *client secret*). +Before you can use Spotipy, there are a few things you need to do: -*Spotipy* supports two authorization flows: +Register your app: To make authorized calls to the Spotify Web API, you need to register your app and obtain a client ID and client secret. You can register your app at My Dashboard _. Make sure to keep your client ID and client secret secure. - - The **Authorization Code flow** This method is suitable for long-running applications +Choose an authorization flow: Spotipy supports two authorization flows: the Authorization Code flow and the Client Credentials flow. Choose the one that's suitable for your application. + - **Authorization Code flow** This method is suitable for long-running applications which the user logs into once. It provides an access token that can be refreshed. - .. note:: Requires you to add a redirect URI to your application at + .. note:: This method requires you to add a redirect URI to your application at `My Dashboard `_. See `Redirect URI`_ for more details. - - The **Client Credentials flow** The method makes it possible - to authenticate your requests to the Spotify Web API and to obtain - a higher rate limit than you would with the Authorization Code flow. + - **The Client Credentials flow** This is suitable for short-lived applications that don't require user permission. It makes it possible to authenticate your requests to the Spotify Web API and to obtain a higher rate limit than you would with the Authorization Code flow. + +Before you can use Spotipy's methods, you need to authorize your app by registering it at My Dashboard _. This will give you a *client id* and *client secret* that you'll need to use in your code. Authorization Code Flow @@ -240,6 +285,42 @@ The following handlers are available and defined in the URL above. Feel free to contribute new cache handlers to the repo. +User Guide +======================= + +In this section, we'll provide a step-by-step tutorial for using some of Spotipy's essential features, such as retrieving user data, and searching for music. + +**Retrieving User Data** + - Import the Spotipy module in your Python code:: + + import spotipy + + - Create a Spotipy object with authentication manager:: + + from spotipy.oauth2 import SpotifyOAuth + + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id='', + client_secret='', + redirect_uri='')) + - Use the sp.current_user() method to retrieve the authenticated user's data:: + + user_data = sp.current_user() + + - Access various pieces of user data from the user_data dictionary, such as the user's display name:: + + display_name = user_data['display_name'] + +**Searching for Music** + - Use the sp.search() method to search for a track, artist, album or playlist:: + + results = sp.search(q='chocolate', type='track') + + - The results variable contains a dictionary with search results. You can access the list of tracks returned by the search by accessing results['tracks']['items']. + + - Each item in the list of tracks is a dictionary containing information about the track. For example, you can retrieve the track name using track_name = results['tracks']['items'][0]['name']. + + + Examples ======================= @@ -288,6 +369,23 @@ If you think you've found a bug, let us know at `Spotify Issues `_ +Troubleshooting +======= + +This section aims to address common issues that users may encounter while working with Spotipy and provide practical solutions to resolve them. + +**Authentication errors**: Make sure that you have correctly set up your credentials and are using the correct authorization flow to avoid authenthication erros. Ensure that your client ID and client secret are correct and that you have added the appropriate redirect URIs to your Spotify Developer Dashboard. + +**Playlist creation errors**: If you're having trouble creating a playlist, check that your user ID is correct, and that the user has the necessary permissions to create playlists. Additionally, make sure that your code is formatted correctly, along with the fact that you are sending the appropriate request to the Spotify API. + +**Search errors**: If you're having problems when searching for music, make sure that you are providing the correct search query parameters. You should also check the Spotify API documentation to ensure that the endpoint you're using supports the search parameters you are providing. + +**API changes**: Sometimes the Spotify API may change, causing errors in your application. To fix this, check the Spotify API documentation to see if there are any changes that may affect your code and update it accordingly. + +**Rate limiting**: Making too many requests to the Spotify API within a short period of time, will result in you hitting the rate limit. To prevent this, use caching and backoff mechanisms in your code + +**Authorization errors**: If you encounter authorization errors, make sure that you have correctly set up your credentials and are using the correct authorization flow. You may also need to check if your access token has expired and obtain a new one if necessary. + Contribute ========== From 85cfcc1a2dda1e1dc29f9bab5809bd1c61828c0b Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Sun, 7 May 2023 15:14:58 +0100 Subject: [PATCH 03/18] Add files via upload --- docs/index.html | 6114 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6114 insertions(+) create mode 100644 docs/index.html diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..4263fcae --- /dev/null +++ b/docs/index.html @@ -0,0 +1,6114 @@ + + + + + + + + + + Welcome to Spotipy! — spotipy 2.0 documentation + + + + + + + + + + + + + + +
+
+
+
+ + _images/spotify-web-api-doc.jpg +
+

Welcome to Spotipy!

+

Spotipy is a lightweight Python library for the Spotify Web API. With Spotipy + you get full access to all of the music data provided by the Spotify platform.

+

Assuming you set the SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET + environment variables (here is a video explaining how to do so). For a longer tutorial with + examples included, refer to this video + playlist. Below is a quick example of using Spotipy to list the + names of all the albums released by the artist ‘Birdy’:

+
+
+
import spotipy
+from spotipy.oauth2 import SpotifyClientCredentials
+
+birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP'
+spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials())
+
+results = spotify.artist_albums(birdy_uri, album_type='album')
+albums = results['items']
+while results['next']:
+    results = spotify.next(results)
+    albums.extend(results['items'])
+
+for album in albums:
+    print(album['name'])
+
+
+
+

Here’s another example showing how to get 30 second samples and cover art + for the top 10 tracks for Led Zeppelin:

+
+
+
import spotipy
+from spotipy.oauth2 import SpotifyClientCredentials
+
+lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
+
+spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials())
+results = spotify.artist_top_tracks(lz_uri)
+
+for track in results['tracks'][:10]:
+    print('track    : ' + track['name'])
+    print('audio    : ' + track['preview_url'])
+    print('cover art: ' + track['album']['images'][0]['url'])
+    print()
+
+
+
+

Finally, here’s an example that will get the URL for an artist image given the + artist’s name:

+
+
+
import spotipy
+import sys
+from spotipy.oauth2 import SpotifyClientCredentials
+
+spotify = spotipy.Spotify(auth_manager=SpotifyClientCredentials())
+
+if len(sys.argv) > 1:
+    name = ' '.join(sys.argv[1:])
+else:
+    name = 'Radiohead'
+
+results = spotify.search(q='artist:' + name, type='artist')
+items = results['artists']['items']
+if len(items) > 0:
+    artist = items[0]
+    print(artist['name'], artist['images'][0]['url'])
+
+
+
+
+
+

Features

+

Spotipy supports all of the features of the Spotify Web API including access + to all end points, and support for user authorization. For details on the + capabilities you are encouraged to review the Spotify Web + API documentation.

+
+
+

Installation

+

Installing Spotipy on Windows:

+
    +
  • +

    Install Python: Download and install Python from the official Python website (https://www.python.org/downloads/).

    +
  • +
  • +

    Install Spotipy: Open a command prompt and run pip install spotipy.

    +
  • +
+

Open command prompt and run the following:

+
+
+
pip install spotipy
+
+
+
+
    +
  • +

    Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID + and client secret.

    +
  • +
+

Installing Spotipy on macOS:

+
    +
  • +

    Install Homebrew: Install Homebrew, a package manager for macOS.

    +
  • +
  • +

    Run the followng command:

    +
    +
    +
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    +
    +
    +
    +
  • +
  • +

    Install Python: Run brew install python in the terminal:

    +
    +
    +
    brew install python
    +
    +
    +
    +
  • +
  • +

    Install Spotipy: Run pip install spotipy in the terminal:

    +
    +
    +
    pip install spotipy
    +
    +
    +
    +
  • +
  • +

    Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID + and client secret.

    +
  • +
+

Installing Spotipy on Linux:

+
    +
  • +

    Install Python: Use your Linux distribution’s package manager to install Python using the following + command:

    +
    +
    +
    sudo apt-get install python3
    +
    +
    +
    +
  • +
  • +

    Install pip: Use your Linux distribution’s package manager to install pip using the command:

    +
    +
    +
    sudo apt-get install python3-pip
    +
    +
    +
    +
  • +
  • +

    Install Spotipy: Run pip install spotipy in the terminal.

    +
    +
    +

    pip install spotipy

    +
    +
    +
  • +
  • +

    Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID + and client secret.

    +
  • +
+
+
+
+

You can get the source from github at https://github.com/plamere/spotipy

+
+
+

Getting Started with Spotipy

+

Before you can use Spotipy, there are a few things you need to do:

+

Register your app: To make authorized calls to the Spotify Web API, you need to register your app and + obtain a client ID and client secret. You can register your app at My Dashboard <https://developer.spotify.com/dashboard/applications>_. + Make sure to keep your client ID and client secret secure.

+
+
Choose an authorization flow: Spotipy supports two authorization flows: the Authorization Code flow + and the Client Credentials flow. Choose the one that’s suitable for your application.
+
+
    +
  • +

    Authorization Code flow This method is suitable for long-running applications + which the user logs into once. It provides an access token that can be refreshed.

    +
  • +
+
+
+
+

Note

+

This method requires you to add a redirect URI to your application at + My + Dashboard. + See Redirect URI for more details. +

+
+
+
+
    +
  • +

    The Client Credentials flow This is suitable for short-lived applications that + don’t require user permission. It makes it possible to authenticate your requests to the Spotify + Web API and to obtain a higher rate limit than you would with the Authorization Code flow.

    +
  • +
+
+
+

Before you can use Spotipy’s methods, you need to authorize your app by registering it at My Dashboard + <https://developer.spotify.com/dashboard/applications>_. + This will give you a client id and client secret that you’ll need to use in your code. +

+
+
+

Authorization Code Flow

+

This flow is suitable for long-running applications in which the user grants + permission only once. It provides an access token that can be refreshed. + Since the token exchange involves sending your secret key, perform this on a + secure location, like a backend service, and not from a client such as a + browser or from a mobile app.

+
+

Quick start

+

To support the Client Authorization Code Flow Spotipy provides a + class SpotifyOAuth that can be used to authenticate requests like so:

+
+
+
import spotipy
+from spotipy.oauth2 import SpotifyOAuth
+
+scope = "user-library-read"
+
+sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
+
+results = sp.current_user_saved_tracks()
+for idx, item in enumerate(results['items']):
+    track = item['track']
+    print(idx, track['artists'][0]['name'], " – ", track['name'])
+
+
+
+

or if you are reluctant to immortalize your app credentials in your source code, + you can set environment variables like so (use $env:"credentials" + instead of export + on Windows):

+
+
+
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
+export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
+export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
+
+
+
+
+
+

Scopes

+

See Using + Scopes for information + about scopes.

+
+
+

Redirect URI

+

The Authorization Code Flow needs you to add a redirect URI + to your application at + My + Dashboard + (navigate to your application and then [Edit Settings]). +

+

The redirect_uri argument or + SPOTIPY_REDIRECT_URI + environment variable + must match the redirect URI added to your application in your Dashboard. + The redirect URI can be any valid URI (it does not need to be accessible) + such as http://example.com, + http://localhost or http://127.0.0.1:9090. +

+
+
+
+

Note

+

If you choose an http-scheme URL, and it’s for localhost or + 127.0.0.1`, AND it specifies a port, then spotipy will instantiate

+
+

a server on the indicated response to receive the access token from the + response at the end of the oauth flow [see the code](https://github.com/plamere/spotipy/blob/master/spotipy/oauth2.py#L483-L490). +

+
+
+
+
+
+

Client Credentials Flow

+

The Client Credentials flow is used in server-to-server authentication. Only + endpoints that do not access user information can be accessed. The advantage here + in comparison with requests to the Web API made without an access token, + is that a higher rate limit is applied.

+

As opposed to the Authorization Code Flow, you will not need to set SPOTIPY_REDIRECT_URI, + which means you will never be redirected to the sign in page in your browser:

+
+
+
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
+export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
+
+
+
+

To support the Client Credentials Flow Spotipy provides a + class SpotifyClientCredentials that can be used to authenticate requests like so:

+
+
+
import spotipy
+from spotipy.oauth2 import SpotifyClientCredentials
+
+auth_manager = SpotifyClientCredentials()
+sp = spotipy.Spotify(auth_manager=auth_manager)
+
+playlists = sp.user_playlists('spotify')
+while playlists:
+    for i, playlist in enumerate(playlists['items']):
+        print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'],  playlist['name']))
+    if playlists['next']:
+        playlists = sp.next(playlists)
+    else:
+        playlists = None
+
+
+
+
+
+

IDs URIs and URLs +

+

Spotipy supports a number of different ID types:

+
+
+
    +
  • +

    Spotify URI - The resource identifier that you can enter, for example, in + the Spotify Desktop client’s search box to locate an artist, album, or + track. Example: spotify:track:6rqhFgbbKwnb9MLmUQDhG6 +

    +
  • +
  • +

    Spotify URL - An HTML link that opens a track, album, app, playlist or other + Spotify resource in a Spotify client. Example: + http://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6 +

    +
  • +
  • +

    Spotify ID - A base-62 number that you can find at the end of the Spotify + URI (see above) for an artist, track, album, etc. Example: + 6rqhFgbbKwnb9MLmUQDhG6 +

    +
  • +
+
+
+

In general, any Spotipy method that needs an artist, album, track or playlist ID + will accept ids in any of the above form

+
+
+

Customized token caching

+

Tokens are refreshed automatically and stored by default in the project main folder. + As this might not suit everyone’s needs, spotipy provides a way to create customized + cache handlers.

+

https://github.com/plamere/spotipy/blob/master/spotipy/cache_handler.py +

+

The custom cache handler would need to be a class that inherits from the base + cache handler CacheHandler. The + default cache handler CacheFileHandler is a good example. + An instance of that new class can then be passed as a parameter when + creating SpotifyOAuth, SpotifyPKCE or SpotifyImplicitGrant. + The following handlers are available and defined in the URL above.

+
+
+
    +
  • +

    CacheFileHandler

    +
  • +
  • +

    MemoryCacheHandler

    +
  • +
  • +

    DjangoSessionCacheHandler +

    +
  • +
  • +

    FlaskSessionCacheHandler +

    +
  • +
  • +

    RedisCacheHandler

    +
  • +
+
+
+

Feel free to contribute new cache handlers to the repo.

+
+
+

User Guide

+

In this section, we’ll provide a step-by-step tutorial for using some of Spotipy’s essential features, + such as retrieving user data, and searching for music.

+
+
Retrieving User Data
+
+
    +
  • +

    Import the Spotipy module in your Python code:

    +
    +
    +
    import spotipy
    +
    +
    +
    +
  • +
  • +

    Create a Spotipy object with authentication manager:

    +
    +
    +
    from spotipy.oauth2 import SpotifyOAuth
    +
    +sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id='<your_client_id>',
    +                                         client_secret='<your_client_secret>',
    +                                         redirect_uri='<your_redirect_uri>'))
    +
    +
    +
    +
  • +
  • +

    Use the sp.current_user() method to retrieve the authenticated user’s data:

    +
    +
    +
    user_data = sp.current_user()
    +
    +
    +
    +
  • +
  • +

    Access various pieces of user data from the user_data dictionary, such as the user’s display + name:

    +
    +
    +
    display_name = user_data['display_name']
    +
    +
    +
    +
  • +
+
+
Searching for Music
+
+
    +
  • +

    Use the sp.search() method to search for a track, artist, album or playlist:

    +
    +
    +
    results = sp.search(q='chocolate', type='track')
    +
    +
    +
    +
  • +
  • +

    The results variable contains a dictionary with search results. You can access the list of tracks + returned by the search by accessing results[‘tracks’][‘items’].

    +
  • +
  • +

    Each item in the list of tracks is a dictionary containing information about the track. For + example, you can retrieve the track name using track_name = results[‘tracks’][‘items’][0][‘name’]. +

    +
  • +
+
+
+
+
+

Examples

+

There are many more examples of how to use Spotipy in the Examples + Directory on Github

+
+
+

API Reference

+
+
+ +

client + Module

+

A simple and thin Python library for the Spotify Web API

+
+
+ class spotipy.client.Spotify(auth=None, + requests_session=True, client_credentials_manager=None, + oauth_manager=None, + auth_manager=None, + proxies=None, + requests_timeout=5, status_forcelist=None, retries=3, status_retries=3, backoff_factor=0.3, + language=None) +
+
+

Bases: object

+

Example usage:

+
+
+
import spotipy
+
+urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu'
+sp = spotipy.Spotify()
+
+artist = sp.artist(urn)
+print(artist)
+
+user = sp.user('plamere')
+print(user)
+
+
+
+
+
+ __init__(auth=None, requests_session=True, client_credentials_manager=None, oauth_manager=None, auth_manager=None, proxies=None, requests_timeout=5, + status_forcelist=None, retries=3, status_retries=3, + backoff_factor=0.3, language=None) +
+
+

Creates a Spotify API client.

+
+
Parameters:
+
+
    +
  • +

    auth – An access token (optional)

    +
  • +
  • +

    requests_session – A Requests session object or a truthy value to create + one. + A falsy value disables sessions. + It should generally be a good idea to keep sessions enabled + for performance reasons (connection pooling).

    +
  • +
  • +

    client_credentials_manager – SpotifyClientCredentials object

    +
  • +
  • +

    oauth_manager – SpotifyOAuth object

    +
  • +
  • +

    auth_manager – SpotifyOauth, SpotifyClientCredentials, + or SpotifyImplicitGrant object

    +
  • +
  • +

    proxies – Definition of proxies (optional). + See Requests doc https://2.python-requests.org/en/master/user/advanced/#proxies +

    +
  • +
  • +

    requests_timeout – Tell Requests to stop waiting for a response after a + given + number of seconds

    +
  • +
  • +

    status_forcelist – Tell requests what type of status codes retries + should occur on

    +
  • +
  • +

    retries – Total number of retries to allow

    +
  • +
  • +

    status_retries – Number of times to retry on bad status codes

    +
  • +
  • +

    backoff_factor – A backoff factor to apply between attempts after the + second try + See urllib3 https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html +

    +
  • +
  • +

    language – The language parameter advertises what language the user + prefers to see. + See ISO-639-1 language code: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes +

    +
  • +
+
+
+
+
+ +
+
+ add_to_queue(uri, device_id=None) +
+
+

Adds a song to the end of a user’s queue

+

If device A is currently playing music and you try to add to the queue + and pass in the id for device B, you will get a + ‘Player command failed: Restriction violated’ error + I therefore recommend leaving device_id as None so that the active device is targeted

+
+
Parameters:
+
+
    +
  • +

    uri – song uri, id, or url

    +
  • +
  • +

    device_id – the id of a Spotify device. + If None, then the active device is used.

    +
  • +
+
+
+
+
+ +
+
+ album(album_id, market=None) +
+
+

returns a single album given the album’s ID, URIs or URL

+
+
Parameters:
+
+
    +
  • +

    album_id - the album ID, URI or URL

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code

    +
  • +
+
+
+
+
+ +
+
+ album_tracks(album_id, limit=50, offset=0, + market=None) +
+
+

Get Spotify catalog information about an album’s tracks

+
+
Parameters:
+
+
    +
  • +

    album_id - the album ID, URI or URL

    +
  • +
  • +

    limit - the number of items to return

    +
  • +
  • +

    offset - the index of the first item to return

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
+
+
+
+
+ +
+
+ albums(albums, market=None) +
+
+

returns a list of albums given the album IDs, URIs, or URLs

+
+
Parameters:
+
+
    +
  • +

    albums - a list of album IDs, URIs or URLs

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code

    +
  • +
+
+
+
+
+ +
+
+ artist(artist_id) +
+
+

returns a single artist given the artist’s ID, URI or URL

+
+
Parameters:
+
+
    +
  • +

    artist_id - an artist ID, URI or URL

    +
  • +
+
+
+
+
+ +
+
+ artist_albums(artist_id, album_type=None, country=None, limit=20, offset=0) +
+
+

Get Spotify catalog information about an artist’s albums

+
+
Parameters:
+
+
    +
  • +

    artist_id - the artist ID, URI or URL

    +
  • +
  • +

    album_type - ‘album’, ‘single’, ‘appears_on’, ‘compilation’

    +
  • +
  • +

    country - limit the response to one particular country.

    +
  • +
  • +

    limit - the number of albums to return

    +
  • +
  • +

    offset - the index of the first album to return

    +
  • +
+
+
+
+
+ +
+ +
+

Get Spotify catalog information about artists similar to an + identified artist. Similarity is based on analysis of the + Spotify community’s listening history.

+
+
Parameters:
+
+
    +
  • +

    artist_id - the artist ID, URI or URL

    +
  • +
+
+
+
+
+ +
+
+ artist_top_tracks(artist_id, country='US') +
+
+

Get Spotify catalog information about an artist’s top 10 tracks + by country.

+
+
Parameters:
+
+
    +
  • +

    artist_id - the artist ID, URI or URL

    +
  • +
  • +

    country - limit the response to one particular country.

    +
  • +
+
+
+
+
+ +
+
+ artists(artists) +
+
+

returns a list of artists given the artist IDs, URIs, or URLs

+
+
Parameters:
+
+
    +
  • +

    artists - a list of artist IDs, URIs or URLs

    +
  • +
+
+
+
+
+ +
+
+ audio_analysis(track_id) +
+
+

Get audio analysis for a track based upon its Spotify ID + Parameters:

+
+
+
    +
  • +

    track_id - a track URI, URL or ID

    +
  • +
+
+
+
+
+ +
+
+ audio_features(tracks=[]) +
+
+

Get audio features for one or multiple tracks based upon their Spotify IDs + Parameters:

+
+
+
    +
  • +

    tracks - a list of track URIs, URLs or IDs, maximum: 100 ids

    +
  • +
+
+
+
+
+ +
+
+ property auth_manager +
+
+
+ +
+
+ available_markets() +
+
+

Get the list of markets where Spotify is available. + Returns a list of the countries in which Spotify is available, identified by their + ISO 3166-1 alpha-2 country code with additional country codes for special territories.

+
+
+ +
+
+ categories(country=None, locale=None, limit=20, offset=0) +
+
+

Get a list of categories

+
+
Parameters:
+
+
    +
  • +

    country - An ISO 3166-1 alpha-2 country code.

    +
  • +
  • +

    locale - The desired language, consisting of an ISO 639-1 alpha-2 + language code and an ISO 3166-1 alpha-2 country code, joined + by an underscore.

    +
  • +
  • +

    limit - The maximum number of items to return. Default: 20. + Minimum: 1. Maximum: 50

    +
  • +
  • +

    offset - The index of the first item to return. Default: 0 + (the first object). Use with limit to get the next set of + items.

    +
  • +
+
+
+
+
+ +
+
+ category(category_id, country=None, locale=None) +
+
+

Get info about a category

+
+
Parameters:
+
+
    +
  • +

    category_id - The Spotify category ID for the category.

    +
  • +
  • +

    country - An ISO 3166-1 alpha-2 country code.

    +
  • +
  • +

    locale - The desired language, consisting of an ISO 639-1 alpha-2 + language code and an ISO 3166-1 alpha-2 country code, joined + by an underscore.

    +
  • +
+
+
+
+
+ +
+
+ category_playlists(category_id=None, country=None, limit=20, offset=0) +
+
+

Get a list of playlists for a specific Spotify category

+
+
Parameters:
+
+
    +
  • +

    category_id - The Spotify category ID for the category.

    +
  • +
  • +

    country - An ISO 3166-1 alpha-2 country code.

    +
  • +
  • +

    limit - The maximum number of items to return. Default: 20. + Minimum: 1. Maximum: 50

    +
  • +
  • +

    offset - The index of the first item to return. Default: 0 + (the first object). Use with limit to get the next set of + items.

    +
  • +
+
+
+
+
+ +
+
+ country_codes = ['AD', 'AR', 'AU', 'AT', 'BE', 'BO', 'BR', 'BG', 'CA', 'CL', 'CO', 'CR', 'CY', 'CZ', 'DK', 'DO', 'EC', 'SV', 'EE', 'FI', 'FR', 'DE', 'GR', 'GT', 'HN', 'HK', 'HU', 'IS', 'ID', 'IE', 'IT', 'JP', 'LV', 'LI', 'LT', 'LU', 'MY', 'MT', 'MX', 'MC', 'NL', 'NZ', 'NI', 'NO', 'PA', 'PY', 'PE', 'PH', 'PL', 'PT', 'SG', 'ES', 'SK', 'SE', 'CH', 'TW', 'TR', 'GB', 'US', 'UY'] +
+
+
+ +
+
+ current_playback(market=None, additional_types=None) +
+
+

Get information about user’s current playback.

+
+
Parameters:
+
+
    +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
  • +

    additional_types - episode to get podcast track information

    +
  • +
+
+
+
+
+ +
+
+ current_user() +
+
+

Get detailed profile information about the current user. + An alias for the ‘me’ method.

+
+
+ +
+
+ current_user_follow_playlist(playlist_id) +
+
+

Add the current authenticated user as a follower of a playlist.

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
+
+
+
+
+ +
+
+ current_user_followed_artists(limit=20, after=None) +
+
+

Gets a list of the artists followed by the current authorized user

+
+
Parameters:
+
+
    +
  • +

    limit - the number of artists to return

    +
  • +
  • +
    +
    after - the last artist ID retrieved from the previous
    +
    +

    request

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ current_user_following_artists(ids=None) +
+
+

Check if the current user is following certain artists

+

Returns list of booleans respective to ids

+
+
Parameters:
+
+
    +
  • +

    ids - a list of artist URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_following_users(ids=None) +
+
+

Check if the current user is following certain users

+

Returns list of booleans respective to ids

+
+
Parameters:
+
+
    +
  • +

    ids - a list of user URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_playing_track() +
+
+

Get information about the current users currently playing track.

+
+
+ +
+
+ current_user_playlists(limit=50, offset=0) +
+
+

Get current user playlists without required getting his profile + Parameters:

+
+
+
    +
  • +

    limit - the number of items to return

    +
  • +
  • +

    offset - the index of the first item to return

    +
  • +
+
+
+
+
+ +
+
+ current_user_recently_played(limit=50, after=None, before=None) +
+
+

Get the current user’s recently played tracks

+
+
Parameters:
+
+
    +
  • +

    limit - the number of entities to return

    +
  • +
  • +
    +
    after - unix timestamp in milliseconds. Returns all items
    +
    +

    after (but not including) this cursor position. + Cannot be used if before is specified.

    +
    +
    +
  • +
  • +
    +
    before - unix timestamp in milliseconds. Returns all items
    +
    +

    before (but not including) this cursor position. + Cannot be used if after is specified

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_albums(limit=20, offset=0, + market=None) +
+
+

Gets a list of the albums saved in the current authorized user’s + “Your Music” library

+
+
Parameters:
+
+
    +
  • +

    limit - the number of albums to return (MAX_LIMIT=50)

    +
  • +
  • +

    offset - the index of the first album to return

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_albums_add(albums=[]) +
+
+

Add one or more albums to the current user’s + “Your Music” library. + Parameters:

+
+
+
    +
  • +

    albums - a list of album URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_albums_contains(albums=[]) +
+
+

Check if one or more albums is already saved in + the current Spotify user’s “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    albums - a list of album URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_albums_delete(albums=[]) +
+
+

Remove one or more albums from the current user’s + “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    albums - a list of album URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_episodes(limit=20, offset=0, + market=None) +
+
+

Gets a list of the episodes saved in the current authorized user’s + “Your Music” library

+
+
Parameters:
+
+
    +
  • +

    limit - the number of episodes to return

    +
  • +
  • +

    offset - the index of the first episode to return

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_episodes_add(episodes=None) +
+
+

Add one or more episodes to the current user’s + “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    episodes - a list of episode URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_episodes_contains(episodes=None) +
+
+

Check if one or more episodes is already saved in + the current Spotify user’s “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    episodes - a list of episode URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_episodes_delete(episodes=None) +
+
+

Remove one or more episodes from the current user’s + “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    episodes - a list of episode URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_shows(limit=20, offset=0, + market=None) +
+
+

Gets a list of the shows saved in the current authorized user’s + “Your Music” library

+
+
Parameters:
+
+
    +
  • +

    limit - the number of shows to return

    +
  • +
  • +

    offset - the index of the first show to return

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_shows_add(shows=[]) +
+
+

Add one or more albums to the current user’s + “Your Music” library. + Parameters:

+
+
+
    +
  • +

    shows - a list of show URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_shows_contains(shows=[]) +
+
+

Check if one or more shows is already saved in + the current Spotify user’s “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    shows - a list of show URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_shows_delete(shows=[]) +
+
+

Remove one or more shows from the current user’s + “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    shows - a list of show URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_tracks(limit=20, offset=0, + market=None) +
+
+

Gets a list of the tracks saved in the current authorized user’s + “Your Music” library

+
+
Parameters:
+
+
    +
  • +

    limit - the number of tracks to return

    +
  • +
  • +

    offset - the index of the first track to return

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_tracks_add(tracks=None) +
+
+

Add one or more tracks to the current user’s + “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    tracks - a list of track URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_tracks_contains(tracks=None) +
+
+

Check if one or more tracks is already saved in + the current Spotify user’s “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    tracks - a list of track URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_saved_tracks_delete(tracks=None) +
+
+

Remove one or more tracks from the current user’s + “Your Music” library.

+
+
Parameters:
+
+
    +
  • +

    tracks - a list of track URIs, URLs or IDs

    +
  • +
+
+
+
+
+ +
+
+ current_user_top_artists(limit=20, offset=0, + time_range='medium_term') +
+
+

Get the current user’s top artists

+
+
Parameters:
+
+
    +
  • +

    limit - the number of entities to return

    +
  • +
  • +

    offset - the index of the first entity to return

    +
  • +
  • +

    time_range - Over what time frame are the affinities computed + Valid-values: short_term, medium_term, long_term

    +
  • +
+
+
+
+
+ +
+
+ current_user_top_tracks(limit=20, offset=0, + time_range='medium_term') +
+
+

Get the current user’s top tracks

+
+
Parameters:
+
+
    +
  • +

    limit - the number of entities to return

    +
  • +
  • +

    offset - the index of the first entity to return

    +
  • +
  • +

    time_range - Over what time frame are the affinities computed + Valid-values: short_term, medium_term, long_term

    +
  • +
+
+
+
+
+ +
+
+ current_user_unfollow_playlist(playlist_id) +
+
+

Unfollows (deletes) a playlist for the current authenticated + user

+
+
Parameters:
+
+
    +
  • +

    name - the name of the playlist

    +
  • +
+
+
+
+
+ +
+
+ currently_playing(market=None, additional_types=None) +
+
+

Get user’s currently playing track.

+
+
Parameters:
+
+
    +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
  • +

    additional_types - episode to get podcast track information

    +
  • +
+
+
+
+
+ +
+
+ default_retry_codes = (429, 500, 502, 503, 504) +
+
+
+ +
+
+ devices() +
+
+

Get a list of user’s available devices.

+
+
+ +
+
+ episode(episode_id, market=None) +
+
+

returns a single episode given the episode’s ID, URIs or URL

+
+
Parameters:
+
+
    +
  • +

    episode_id - the episode ID, URI or URL

    +
  • +
  • +
    +
    market - an ISO 3166-1 alpha-2 country code.
    +
    +

    The episode must be available in the given market. + If user-based authorization is in use, the user’s country + takes precedence. If neither market nor user country are + provided, the content is considered unavailable for the client.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ episodes(episodes, market=None) +
+
+

returns a list of episodes given the episode IDs, URIs, or URLs

+
+
Parameters:
+
+
    +
  • +

    episodes - a list of episode IDs, URIs or URLs

    +
  • +
  • +
    +
    market - an ISO 3166-1 alpha-2 country code.
    +
    +

    Only episodes available in the given market will be returned. + If user-based authorization is in use, the user’s country + takes precedence. If neither market nor user country are + provided, the content is considered unavailable for the client.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ featured_playlists(locale=None, country=None, timestamp=None, limit=20, offset=0) +
+
+

Get a list of Spotify featured playlists

+
+
Parameters:
+
+
    +
  • +

    locale - The desired language, consisting of a lowercase ISO + 639-1 alpha-2 language code and an uppercase ISO 3166-1 alpha-2 + country code, joined by an underscore.

    +
  • +
  • +

    country - An ISO 3166-1 alpha-2 country code.

    +
  • +
  • +

    timestamp - A timestamp in ISO 8601 format: + yyyy-MM-ddTHH:mm:ss. Use this parameter to specify the user’s + local time to get results tailored for that specific date and + time in the day

    +
  • +
  • +

    limit - The maximum number of items to return. Default: 20. + Minimum: 1. Maximum: 50

    +
  • +
  • +

    offset - The index of the first item to return. Default: 0 + (the first object). Use with limit to get the next set of + items.

    +
  • +
+
+
+
+
+ +
+
+ max_retries = 3 +
+
+
+ +
+
+ me() +
+
+

Get detailed profile information about the current user. + An alias for the ‘current_user’ method.

+
+
+ +
+
+ new_releases(country=None, limit=20, offset=0) +
+
+

Get a list of new album releases featured in Spotify

+
+
Parameters:
+
+
    +
  • +

    country - An ISO 3166-1 alpha-2 country code.

    +
  • +
  • +

    limit - The maximum number of items to return. Default: 20. + Minimum: 1. Maximum: 50

    +
  • +
  • +

    offset - The index of the first item to return. Default: 0 + (the first object). Use with limit to get the next set of + items.

    +
  • +
+
+
+
+
+ +
+
+ next(result) +
+
+

returns the next result given a paged result

+
+
Parameters:
+
+
    +
  • +

    result - a previously returned paged result

    +
  • +
+
+
+
+
+ +
+
+ next_track(device_id=None) +
+
+

Skip user’s playback to next track.

+
+
Parameters:
+
+
    +
  • +

    device_id - device target for playback

    +
  • +
+
+
+
+
+ +
+
+ pause_playback(device_id=None) +
+
+

Pause user’s playback.

+
+
Parameters:
+
+
    +
  • +

    device_id - device target for playback

    +
  • +
+
+
+
+
+ +
+
+ playlist(playlist_id, fields=None, market=None, additional_types=('track',)) +
+
+

Gets playlist by id.

+
+
Parameters:
+
+
    +
  • +

    playlist - the id of the playlist

    +
  • +
  • +

    fields - which fields to return

    +
  • +
  • +
    +
    market - An ISO 3166-1 alpha-2 country code or the
    +
    +

    string from_token.

    +
    +
    +
  • +
  • +
    +
    additional_types - list of item types to return.
    +
    +

    valid types are: track and episode

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ playlist_add_items(playlist_id, items, position=None) +
+
+

Adds tracks/episodes to a playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    items - a list of track/episode URIs or URLs

    +
  • +
  • +

    position - the position to add the tracks

    +
  • +
+
+
+
+
+ +
+
+ playlist_change_details(playlist_id, name=None, public=None, collaborative=None, description=None) +
+
+

Changes a playlist’s name and/or public/private state, + collaborative state, and/or description

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    name - optional name of the playlist

    +
  • +
  • +

    public - optional is the playlist public

    +
  • +
  • +

    collaborative - optional is the playlist collaborative

    +
  • +
  • +

    description - optional description of the playlist

    +
  • +
+
+
+
+
+ +
+
+ playlist_cover_image(playlist_id) +
+
+

Get cover image of a playlist.

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the playlist ID, URI or URL

    +
  • +
+
+
+
+
+ +
+
+ playlist_is_following(playlist_id, user_ids) +
+
+

Check to see if the given users are following the given playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +
    +
    user_ids - the ids of the users that you want to check to see
    +
    +

    if they follow the playlist. Maximum: 5 ids.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ playlist_items(playlist_id, fields=None, limit=100, offset=0, market=None, additional_types=('track', + 'episode')) +
+
+

Get full details of the tracks and episodes of a playlist.

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the playlist ID, URI or URL

    +
  • +
  • +

    fields - which fields to return

    +
  • +
  • +

    limit - the maximum number of tracks to return

    +
  • +
  • +

    offset - the index of the first track to return

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
  • +
    +
    additional_types - list of item types to return.
    +
    +

    valid types are: track and episode

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ playlist_remove_all_occurrences_of_items(playlist_id, items, snapshot_id=None) +
+
+

Removes all occurrences of the given tracks/episodes from the given playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    items - list of track/episode ids to remove from the playlist

    +
  • +
  • +

    snapshot_id - optional id of the playlist snapshot

    +
  • +
+
+
+
+
+ +
+
+ playlist_remove_specific_occurrences_of_items(playlist_id, items, snapshot_id=None) +
+
+

Removes all occurrences of the given tracks from the given playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +
    +
    items - an array of objects containing Spotify URIs of the
    +
    +

    tracks/episodes to remove with their current positions in + the playlist. For example:

    +
    +
    +

    [ { “uri”:”4iV5W9uYEdYUVa79Axb7Rh”, “positions”:[2] }, + { “uri”:”1301WleyT98MSxVHPZCA6M”, “positions”:[7] } ]

    +
    +
    +
    +
    +
  • +
  • +

    snapshot_id - optional id of the playlist snapshot

    +
  • +
+
+
+
+
+ +
+
+ playlist_reorder_items(playlist_id, range_start, insert_before, range_length=1, snapshot_id=None) +
+
+

Reorder tracks in a playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    range_start - the position of the first track to be reordered

    +
  • +
  • +
    +
    range_length - optional the number of tracks to be reordered
    +
    +

    (default: 1)

    +
    +
    +
  • +
  • +
    +
    insert_before - the position where the tracks should be
    +
    +

    inserted

    +
    +
    +
  • +
  • +

    snapshot_id - optional playlist’s snapshot ID

    +
  • +
+
+
+
+
+ +
+
+ playlist_replace_items(playlist_id, items) +
+
+

Replace all tracks/episodes in a playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    items - list of track/episode ids to comprise playlist

    +
  • +
+
+
+
+
+ +
+
+ playlist_tracks(playlist_id, fields=None, limit=100, offset=0, market=None, additional_types=('track',)) +
+
+

Get full details of the tracks of a playlist.

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the playlist ID, URI or URL

    +
  • +
  • +

    fields - which fields to return

    +
  • +
  • +

    limit - the maximum number of tracks to return

    +
  • +
  • +

    offset - the index of the first track to return

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
  • +
    +
    additional_types - list of item types to return.
    +
    +

    valid types are: track and episode

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ playlist_upload_cover_image(playlist_id, image_b64) +
+
+

Replace the image used to represent a specific playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +
    +
    image_b64 - image data as a Base64 encoded JPEG image string
    +
    +

    (maximum payload size is 256 KB)

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ previous(result) +
+
+

returns the previous result given a paged result

+
+
Parameters:
+
+
    +
  • +

    result - a previously returned paged result

    +
  • +
+
+
+
+
+ +
+
+ previous_track(device_id=None) +
+
+

Skip user’s playback to previous track.

+
+
Parameters:
+
+
    +
  • +

    device_id - device target for playback

    +
  • +
+
+
+
+
+ +
+
+ queue() +
+
+

Gets the current user’s queue

+
+
+ +
+
+ recommendation_genre_seeds() +
+
+

Get a list of genres available for the recommendations function.

+
+
+ +
+
+ recommendations(seed_artists=None, seed_genres=None, seed_tracks=None, limit=20, country=None, **kwargs) +
+
+

Get a list of recommended tracks for one to five seeds. + (at least one of seed_artists, seed_tracks and seed_genres + are needed)

+
+
Parameters:
+
+
    +
  • +

    seed_artists - a list of artist IDs, URIs or URLs

    +
  • +
  • +

    seed_tracks - a list of track IDs, URIs or URLs

    +
  • +
  • +
    +
    seed_genres - a list of genre names. Available genres for
    +
    +

    recommendations can be found by calling + recommendation_genre_seeds

    +
    +
    +
  • +
  • +
    +
    country - An ISO 3166-1 alpha-2 country code. If provided,
    +
    +

    all results will be playable in this country.

    +
    +
    +
  • +
  • +
    +
    limit - The maximum number of items to return. Default: 20.
    +
    +

    Minimum: 1. Maximum: 100

    +
    +
    +
  • +
  • +
    +
    min/max/target_<attribute> - For the tuneable track
    +
    +

    attributes listed in the documentation, these values + provide filters and targeting on results.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ repeat(state, device_id=None) +
+
+

Set repeat mode for playback.

+
+
Parameters:
+
+
    +
  • +

    state - track, context, or off

    +
  • +
  • +

    device_id - device target for playback

    +
  • +
+
+
+
+
+ +
+
+ search(q, limit=10, offset=0, + type='track', market=None) +
+
+

searches for an item

+
+
Parameters:
+
+
    +
  • +
    +
    q - the search query (see how to write a query in the
    +
    +

    official documentation https://developer.spotify.com/documentation/web-api/reference/search/) + # noqa

    +
    +
    +
  • +
  • +
    +
    limit - the number of items to return (min = 1, default = 10, max = 50). The limit is + applied
    +
    +

    within each type, not on the total response.

    +
    +
    +
  • +
  • +

    offset - the index of the first item to return

    +
  • +
  • +
    +
    type - the types of items to return. One or more of ‘artist’, ‘album’,
    +
    +

    ‘track’, ‘playlist’, ‘show’, and ‘episode’. If multiple types are desired, + pass in a comma separated string; e.g., ‘track,album,episode’.

    +
    +
    +
  • +
  • +
    +
    market - An ISO 3166-1 alpha-2 country code or the string
    +
    +

    from_token.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ search_markets(q, limit=10, offset=0, + type='track', markets=None, total=None) +
+
+

(experimental) Searches multiple markets for an item

+
+
Parameters:
+
+
    +
  • +
    +
    q - the search query (see how to write a query in the
    +
    +

    official documentation https://developer.spotify.com/documentation/web-api/reference/search/) + # noqa

    +
    +
    +
  • +
  • +
    +
    limit - the number of items to return (min = 1, default = 10, max = 50). If a search + is to be done on multiple
    +
    +

    markets, then this limit is applied to each market. (e.g. search US, CA, MX each with + a limit of 10). + If multiple types are specified, this applies to each type.

    +
    +
    +
  • +
  • +

    offset - the index of the first item to return

    +
  • +
  • +
    +
    type - the types of items to return. One or more of ‘artist’, ‘album’,
    +
    +

    ‘track’, ‘playlist’, ‘show’, or ‘episode’. If multiple types are desired, pass in a + comma separated string.

    +
    +
    +
  • +
  • +

    markets - A list of ISO 3166-1 alpha-2 country codes. Search all country markets by + default.

    +
  • +
  • +

    total - the total number of results to return across multiple markets and types.

    +
  • +
+
+
+
+
+ +
+
+ seek_track(position_ms, device_id=None) +
+
+

Seek to position in current track.

+
+
Parameters:
+
+
    +
  • +

    position_ms - position in milliseconds to seek to

    +
  • +
  • +

    device_id - device target for playback

    +
  • +
+
+
+
+
+ +
+
+ set_auth(auth) +
+
+
+ +
+
+ show(show_id, market=None) +
+
+

returns a single show given the show’s ID, URIs or URL

+
+
Parameters:
+
+
    +
  • +

    show_id - the show ID, URI or URL

    +
  • +
  • +
    +
    market - an ISO 3166-1 alpha-2 country code.
    +
    +

    The show must be available in the given market. + If user-based authorization is in use, the user’s country + takes precedence. If neither market nor user country are + provided, the content is considered unavailable for the client.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ show_episodes(show_id, limit=50, offset=0, + market=None) +
+
+

Get Spotify catalog information about a show’s episodes

+
+
Parameters:
+
+
    +
  • +

    show_id - the show ID, URI or URL

    +
  • +
  • +

    limit - the number of items to return

    +
  • +
  • +

    offset - the index of the first item to return

    +
  • +
  • +
    +
    market - an ISO 3166-1 alpha-2 country code.
    +
    +

    Only episodes available in the given market will be returned. + If user-based authorization is in use, the user’s country + takes precedence. If neither market nor user country are + provided, the content is considered unavailable for the client.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ shows(shows, market=None) +
+
+

returns a list of shows given the show IDs, URIs, or URLs

+
+
Parameters:
+
+
    +
  • +

    shows - a list of show IDs, URIs or URLs

    +
  • +
  • +
    +
    market - an ISO 3166-1 alpha-2 country code.
    +
    +

    Only shows available in the given market will be returned. + If user-based authorization is in use, the user’s country + takes precedence. If neither market nor user country are + provided, the content is considered unavailable for the client.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ shuffle(state, device_id=None) +
+
+

Toggle playback shuffling.

+
+
Parameters:
+
+
    +
  • +

    state - true or false

    +
  • +
  • +

    device_id - device target for playback

    +
  • +
+
+
+
+
+ +
+
+ start_playback(device_id=None, context_uri=None, uris=None, offset=None, position_ms=None) +
+
+

Start or resume user’s playback.

+

Provide a context_uri to start playback of an album, + artist, or playlist.

+

Provide a uris list to start playback of one or more + tracks.

+

Provide offset as {“position”: <int>} or {“uri”: “<track uri>”} + to start playback at a particular offset.

+
+
Parameters:
+
+
    +
  • +

    device_id - device target for playback

    +
  • +
  • +

    context_uri - spotify context uri to play

    +
  • +
  • +

    uris - spotify track uris

    +
  • +
  • +

    offset - offset into context by index or track

    +
  • +
  • +
    +
    position_ms - (optional) indicates from what position to start playback.
    +
    +

    Must be a positive number. Passing in a position that is + greater than the length of the track will cause the player to + start playing the next song.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ track(track_id, market=None) +
+
+

returns a single track given the track’s ID, URI or URL

+
+
Parameters:
+
+
    +
  • +

    track_id - a spotify URI, URL or ID

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
+
+
+
+
+ +
+
+ tracks(tracks, market=None) +
+
+

returns a list of tracks given a list of track IDs, URIs, or URLs

+
+
Parameters:
+
+
    +
  • +

    tracks - a list of spotify URIs, URLs or IDs. Maximum: 50 IDs.

    +
  • +
  • +

    market - an ISO 3166-1 alpha-2 country code.

    +
  • +
+
+
+
+
+ +
+
+ transfer_playback(device_id, force_play=True) +
+
+

Transfer playback to another device. + Note that the API accepts a list of device ids, but only + actually supports one.

+
+
Parameters:
+
+
    +
  • +

    device_id - transfer playback to this device

    +
  • +
  • +
    +
    force_play - true: after transfer, play. false:
    +
    +

    keep current state.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ user(user) +
+
+

Gets basic profile information about a Spotify User

+
+
Parameters:
+
+
    +
  • +

    user - the id of the usr

    +
  • +
+
+
+
+
+ +
+
+ user_follow_artists(ids=[]) +
+
+

Follow one or more artists + Parameters:

+
+
+
    +
  • +

    ids - a list of artist IDs

    +
  • +
+
+
+
+
+ +
+
+ user_follow_users(ids=[]) +
+
+

Follow one or more users + Parameters:

+
+
+
    +
  • +

    ids - a list of user IDs

    +
  • +
+
+
+
+
+ +
+
+ user_playlist(user, playlist_id=None, fields=None, market=None) +
+
+
+ +
+
+ user_playlist_add_episodes(user, playlist_id, episodes, position=None) +
+
+
+ +
+
+ user_playlist_add_tracks(user, playlist_id, tracks, position=None) +
+
+
+ +
+
+ user_playlist_change_details(user, playlist_id, name=None, public=None, collaborative=None, description=None) +
+
+
+ +
+
+ user_playlist_create(user, name, public=True, collaborative=False, description='') +
+
+

Creates a playlist for a user

+
+
Parameters:
+
+
    +
  • +

    user - the id of the user

    +
  • +
  • +

    name - the name of the playlist

    +
  • +
  • +

    public - is the created playlist public

    +
  • +
  • +

    collaborative - is the created playlist collaborative

    +
  • +
  • +

    description - the description of the playlist

    +
  • +
+
+
+
+
+ +
+
+ user_playlist_follow_playlist(playlist_owner_id, playlist_id) +
+
+

Add the current authenticated user as a follower of a playlist.

+
+
Parameters:
+
+
    +
  • +

    playlist_owner_id - the user id of the playlist owner

    +
  • +
  • +

    playlist_id - the id of the playlist

    +
  • +
+
+
+
+
+ +
+
+ user_playlist_is_following(playlist_owner_id, playlist_id, user_ids) +
+
+

Check to see if the given users are following the given playlist

+
+
Parameters:
+
+
    +
  • +

    playlist_owner_id - the user id of the playlist owner

    +
  • +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +
    +
    user_ids - the ids of the users that you want to check to see
    +
    +

    if they follow the playlist. Maximum: 5 ids.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ user_playlist_remove_all_occurrences_of_tracks(user, playlist_id, tracks, snapshot_id=None) +
+
+

Removes all occurrences of the given tracks from the given playlist

+
+
Parameters:
+
+
    +
  • +

    user - the id of the user

    +
  • +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    tracks - the list of track ids to remove from the playlist

    +
  • +
  • +

    snapshot_id - optional id of the playlist snapshot

    +
  • +
+
+
+
+
+ +
+
+ user_playlist_remove_specific_occurrences_of_tracks(user, playlist_id, tracks, snapshot_id=None) +
+
+

Removes all occurrences of the given tracks from the given playlist

+
+
Parameters:
+
+
    +
  • +

    user - the id of the user

    +
  • +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +
    +
    tracks - an array of objects containing Spotify URIs of the
    +
    +

    tracks to remove with their current positions in the + playlist. For example:

    +
    +
    +

    [ { “uri”:”4iV5W9uYEdYUVa79Axb7Rh”, “positions”:[2] }, + { “uri”:”1301WleyT98MSxVHPZCA6M”, “positions”:[7] } ]

    +
    +
    +
    +
    +
  • +
  • +

    snapshot_id - optional id of the playlist snapshot

    +
  • +
+
+
+
+
+ +
+
+ user_playlist_reorder_tracks(user, playlist_id, range_start, insert_before, range_length=1, snapshot_id=None) +
+
+

Reorder tracks in a playlist from a user

+
+
Parameters:
+
+
    +
  • +

    user - the id of the user

    +
  • +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    range_start - the position of the first track to be reordered

    +
  • +
  • +
    +
    range_length - optional the number of tracks to be reordered
    +
    +

    (default: 1)

    +
    +
    +
  • +
  • +
    +
    insert_before - the position where the tracks should be
    +
    +

    inserted

    +
    +
    +
  • +
  • +

    snapshot_id - optional playlist’s snapshot ID

    +
  • +
+
+
+
+
+ +
+
+ user_playlist_replace_tracks(user, playlist_id, tracks) +
+
+

Replace all tracks in a playlist for a user

+
+
Parameters:
+
+
    +
  • +

    user - the id of the user

    +
  • +
  • +

    playlist_id - the id of the playlist

    +
  • +
  • +

    tracks - the list of track ids to add to the playlist

    +
  • +
+
+
+
+
+ +
+
+ user_playlist_tracks(user=None, playlist_id=None, fields=None, limit=100, offset=0, market=None) +
+
+
+ +
+
+ user_playlist_unfollow(user, playlist_id) +
+
+

Unfollows (deletes) a playlist for a user

+
+
Parameters:
+
+
    +
  • +

    user - the id of the user

    +
  • +
  • +

    name - the name of the playlist

    +
  • +
+
+
+
+
+ +
+
+ user_playlists(user, limit=50, offset=0) +
+
+

Gets playlists of a user

+
+
Parameters:
+
+
    +
  • +

    user - the id of the usr

    +
  • +
  • +

    limit - the number of items to return

    +
  • +
  • +

    offset - the index of the first item to return

    +
  • +
+
+
+
+
+ +
+
+ user_unfollow_artists(ids=[]) +
+
+

Unfollow one or more artists + Parameters:

+
+
+
    +
  • +

    ids - a list of artist IDs

    +
  • +
+
+
+
+
+ +
+
+ user_unfollow_users(ids=[]) +
+
+

Unfollow one or more users + Parameters:

+
+
+
    +
  • +

    ids - a list of user IDs

    +
  • +
+
+
+
+
+ +
+
+ volume(volume_percent, device_id=None) +
+
+

Set playback volume.

+
+
Parameters:
+
+
    +
  • +

    volume_percent - volume between 0 and 100

    +
  • +
  • +

    device_id - device target for playback

    +
  • +
+
+
+
+
+ +
+
+ +
+
+ exception spotipy.client.SpotifyException(http_status, code, msg, reason=None, headers=None) +
+
+

Bases: Exception

+
+
+ __init__(http_status, code, msg, reason=None, headers=None) +
+
+
+ +
+
+ +
+
+ +

oauth2 + Module

+
+
+ class spotipy.oauth2.SpotifyClientCredentials(client_id=None, client_secret=None, + proxies=None, + requests_session=True, requests_timeout=None, cache_handler=None) +
+
+

Bases: SpotifyAuthBase +

+
+
+ OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token' +
+
+
+ +
+
+ __init__(client_id=None, client_secret=None, proxies=None, requests_session=True, requests_timeout=None, cache_handler=None) +
+
+

Creates a Client Credentials Flow Manager.

+

The Client Credentials flow is used in server-to-server authentication. + Only endpoints that do not access user information can be accessed. + This means that endpoints that require authorization scopes cannot be accessed. + The advantage, however, of this authorization flow is that it does not require any + user interaction

+

You can either provide a client_id and client_secret to the + constructor or set SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET + environment variables

+
+
Parameters:
+
+
    +
  • +

    client_id: Must be supplied or set as environment variable

    +
  • +
  • +

    client_secret: Must be supplied or set as environment variable

    +
  • +
  • +

    proxies: Optional, proxy for the requests library to route through

    +
  • +
  • +

    requests_session: A Requests session

    +
  • +
  • +
    +
    requests_timeout: Optional, tell Requests to stop waiting for a response after
    +
    +

    a given number of seconds

    +
    +
    +
  • +
  • +
    +
    cache_handler: An instance of the CacheHandler class to handle
    +
    +

    getting and saving cached authorization tokens. + Optional, will otherwise use CacheFileHandler. + (takes precedence over cache_path and username)

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ get_access_token(as_dict=True, check_cache=True) +
+
+

If a valid access token is in memory, returns it + Else fetches a new token and returns it

+
+
+

Parameters: + - as_dict - a boolean indicating if returning the access token

+
+
+

as a token_info dictionary, otherwise it will be returned + as a string.

+
+
+
+
+
+
+ +
+
+ +
+
+ class spotipy.oauth2.SpotifyImplicitGrant(client_id=None, redirect_uri=None, + state=None, + scope=None, + cache_path=None, + username=None, + show_dialog=False, + cache_handler=None) +
+
+

Bases: SpotifyAuthBase +

+

Implements Implicit Grant Flow for client apps

+

This auth manager enables user and non-user endpoints with only + a client secret, redirect uri, and username. The user will need to + copy and paste a URI from the browser every hour.

+
+

Security Warning

+

The OAuth standard no longer recommends the Implicit Grant Flow for + client-side code. Spotify has implemented the OAuth-suggested PKCE + extension that removes the need for a client secret in the + Authentication Code flow. Use the SpotifyPKCE auth manager instead + of SpotifyImplicitGrant.

+

SpotifyPKCE contains all of the functionality of + SpotifyImplicitGrant, plus automatic response retrieval and + refreshable tokens. Only a few replacements need to be made:

+
    +
  • +

    get_auth_response()[‘access_token’] -> + get_access_token(get_authorization_code())

    +
  • +
  • +

    get_auth_response() -> + get_access_token(get_authorization_code()); get_cached_token()

    +
  • +
  • +

    parse_response_token(url)[‘access_token’] -> + get_access_token(parse_response_code(url))

    +
  • +
  • +

    parse_response_token(url) -> + get_access_token(parse_response_code(url)); get_cached_token()

    +
  • +
+

The security concern in the Implicit Grant flow is that the token is + returned in the URL and can be intercepted through the browser. A + request with an authorization code and proof of origin could not be + easily intercepted without a compromised network.

+
+
+ OAUTH_AUTHORIZE_URL = 'https://accounts.spotify.com/authorize' +
+
+
+ +
+
+ __init__(client_id=None, redirect_uri=None, state=None, scope=None, cache_path=None, username=None, show_dialog=False, cache_handler=None) +
+
+

Creates Auth Manager using the Implicit Grant flow

+

See help(SpotifyImplicitGrant) for full Security Warning

+
+

Parameters +

+
    +
  • +

    client_id: Must be supplied or set as environment variable

    +
  • +
  • +

    redirect_uri: Must be supplied or set as environment variable

    +
  • +
  • +

    state: May be supplied, no verification is performed

    +
  • +
  • +
    +
    scope: Optional, either a list of scopes or comma separated string of scopes.
    +
    +

    e.g, “playlist-read-private,playlist-read-collaborative”

    +
    +
    +
  • +
  • +
    +
    cache_handler: An instance of the CacheHandler class to handle
    +
    +

    getting and saving cached authorization tokens. + May be supplied, will otherwise use CacheFileHandler. + (takes precedence over cache_path and username)

    +
    +
    +
  • +
  • +
    +
    cache_path: (deprecated) May be supplied, will otherwise be generated
    +
    +

    (takes precedence over username)

    +
    +
    +
  • +
  • +
    +
    username: (deprecated) May be supplied or set as environment variable
    +
    +

    (will set cache_path to .cache-{username})

    +
    +
    +
  • +
  • +

    show_dialog: Interpreted as boolean

    +
  • +
+
+
+
+ +
+
+ get_access_token(state=None, response=None, check_cache=True) +
+
+

Gets Auth Token from cache (preferred) or user interaction

+
+

Parameters

+
    +
  • +

    state: May be given, overrides (without changing) self.state

    +
  • +
  • +

    response: URI with token, can break expiration checks

    +
  • +
  • +

    check_cache: Interpreted as boolean

    +
  • +
+
+
+
+ +
+
+ get_auth_response(state=None) +
+
+

Gets a new auth token with user interaction

+
+
+ +
+
+ get_authorize_url(state=None) +
+
+

Gets the URL to use to authorize this app

+
+
+ +
+
+ get_cached_token() +
+
+
+ +
+
+ static parse_auth_response_url(url) +
+
+
+ +
+
+ parse_response_token(url, state=None) +
+
+

Parse the response code in the given response url

+
+
+ +
+
+ validate_token(token_info) +
+
+
+ +
+
+
+ +
+
+ class spotipy.oauth2.SpotifyOAuth(client_id=None, client_secret=None, + redirect_uri=None, + state=None, + scope=None, + cache_path=None, + username=None, + proxies=None, + show_dialog=False, + requests_session=True, requests_timeout=None, open_browser=True, + cache_handler=None) +
+
+

Bases: SpotifyAuthBase +

+

Implements Authorization Code Flow for Spotify’s OAuth implementation.

+
+
+ OAUTH_AUTHORIZE_URL = 'https://accounts.spotify.com/authorize' +
+
+
+ +
+
+ OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token' +
+
+
+ +
+
+ __init__(client_id=None, client_secret=None, redirect_uri=None, state=None, scope=None, cache_path=None, username=None, proxies=None, show_dialog=False, requests_session=True, requests_timeout=None, open_browser=True, cache_handler=None) +
+
+

Creates a SpotifyOAuth object

+
+
Parameters:
+
+
    +
  • +

    client_id: Must be supplied or set as environment variable

    +
  • +
  • +

    client_secret: Must be supplied or set as environment variable

    +
  • +
  • +

    redirect_uri: Must be supplied or set as environment variable

    +
  • +
  • +

    state: Optional, no verification is performed

    +
  • +
  • +
    +
    scope: Optional, either a list of scopes or comma separated string of scopes.
    +
    +

    e.g, “playlist-read-private,playlist-read-collaborative”

    +
    +
    +
  • +
  • +
    +
    cache_path: (deprecated) Optional, will otherwise be generated
    +
    +

    (takes precedence over username)

    +
    +
    +
  • +
  • +
    +
    username: (deprecated) Optional or set as environment variable
    +
    +

    (will set cache_path to .cache-{username})

    +
    +
    +
  • +
  • +

    proxies: Optional, proxy for the requests library to route through

    +
  • +
  • +

    show_dialog: Optional, interpreted as boolean

    +
  • +
  • +

    requests_session: A Requests session

    +
  • +
  • +
    +
    requests_timeout: Optional, tell Requests to stop waiting for a response after
    +
    +

    a given number of seconds

    +
    +
    +
  • +
  • +
    +
    open_browser: Optional, whether or not the web browser should be opened to
    +
    +

    authorize a user

    +
    +
    +
  • +
  • +
    +
    cache_handler: An instance of the CacheHandler class to handle
    +
    +

    getting and saving cached authorization tokens. + Optional, will otherwise use CacheFileHandler. + (takes precedence over cache_path and username)

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ get_access_token(code=None, as_dict=True, check_cache=True) +
+
+

Gets the access token for the app given the code

+
+
Parameters:
+
+
    +
  • +

    code - the response code

    +
  • +
  • +
    +
    as_dict - a boolean indicating if returning the access token
    +
    +

    as a token_info dictionary, otherwise it will be returned + as a string.

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ get_auth_response(open_browser=None) +
+
+
+ +
+
+ get_authorization_code(response=None) +
+
+
+ +
+
+ get_authorize_url(state=None) +
+
+

Gets the URL to use to authorize this app

+
+
+ +
+
+ get_cached_token() +
+
+
+ +
+
+ static parse_auth_response_url(url) +
+
+
+ +
+
+ parse_response_code(url) +
+
+

Parse the response code in the given response url

+
+
Parameters:
+
+
    +
  • +

    url - the response url

    +
  • +
+
+
+
+
+ +
+
+ refresh_access_token(refresh_token) +
+
+
+ +
+
+ validate_token(token_info) +
+
+
+ +
+
+ +
+
+ exception spotipy.oauth2.SpotifyOauthError(message, error=None, error_description=None, + *args, **kwargs) +
+
+

Bases: Exception

+

Error during Auth Code or Implicit Grant flow

+
+
+ __init__(message, error=None, error_description=None, *args, **kwargs) +
+
+
+ +
+
+ +
+
+ class spotipy.oauth2.SpotifyPKCE(client_id=None, redirect_uri=None, + state=None, + scope=None, + cache_path=None, + username=None, + proxies=None, + requests_timeout=None, requests_session=True, open_browser=True, + cache_handler=None) +
+
+

Bases: SpotifyAuthBase +

+

Implements PKCE Authorization Flow for client apps

+

This auth manager enables user and non-user endpoints with only + a client ID, redirect URI, and username. When the app requests + an access token for the first time, the user is prompted to + authorize the new client app. After authorizing the app, the client + app is then given both access and refresh tokens. This is the + preferred way of authorizing a mobile/desktop client.

+
+
+ OAUTH_AUTHORIZE_URL = 'https://accounts.spotify.com/authorize' +
+
+
+ +
+
+ OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token' +
+
+
+ +
+
+ __init__(client_id=None, redirect_uri=None, state=None, scope=None, cache_path=None, username=None, proxies=None, requests_timeout=None, requests_session=True, open_browser=True, cache_handler=None) +
+
+

Creates Auth Manager with the PKCE Auth flow.

+
+
Parameters:
+
+
    +
  • +

    client_id: Must be supplied or set as environment variable

    +
  • +
  • +

    redirect_uri: Must be supplied or set as environment variable

    +
  • +
  • +

    state: Optional, no verification is performed

    +
  • +
  • +
    +
    scope: Optional, either a list of scopes or comma separated string of scopes.
    +
    +

    e.g, “playlist-read-private,playlist-read-collaborative”

    +
    +
    +
  • +
  • +
    +
    cache_path: (deprecated) Optional, will otherwise be generated
    +
    +

    (takes precedence over username)

    +
    +
    +
  • +
  • +
    +
    username: (deprecated) Optional or set as environment variable
    +
    +

    (will set cache_path to .cache-{username})

    +
    +
    +
  • +
  • +

    proxies: Optional, proxy for the requests library to route through

    +
  • +
  • +
    +
    requests_timeout: Optional, tell Requests to stop waiting for a response after
    +
    +

    a given number of seconds

    +
    +
    +
  • +
  • +

    requests_session: A Requests session

    +
  • +
  • +
    +
    open_browser: Optional, whether or not the web browser should be opened to
    +
    +

    authorize a user

    +
    +
    +
  • +
  • +
    +
    cache_handler: An instance of the CacheHandler class to handle
    +
    +

    getting and saving cached authorization tokens. + Optional, will otherwise use CacheFileHandler. + (takes precedence over cache_path and username)

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ get_access_token(code=None, check_cache=True) +
+
+

Gets the access token for the app

+

If the code is not given and no cached token is used, an + authentication window will be shown to the user to get a new + code.

+
+
Parameters:
+
+
    +
  • +

    code - the response code from authentication

    +
  • +
  • +
    +
    check_cache - if true, checks for a locally stored token
    +
    +

    before requesting a new token

    +
    +
    +
  • +
+
+
+
+
+ +
+
+ get_authorization_code(response=None) +
+
+
+ +
+
+ get_authorize_url(state=None) +
+
+

Gets the URL to use to authorize this app

+
+
+ +
+
+ get_cached_token() +
+
+
+ +
+
+ get_pkce_handshake_parameters() +
+
+
+ +
+
+ static parse_auth_response_url(url) +
+
+
+ +
+
+ parse_response_code(url) +
+
+

Parse the response code in the given response url

+
+
Parameters:
+
+
    +
  • +

    url - the response url

    +
  • +
+
+
+
+
+ +
+
+ refresh_access_token(refresh_token) +
+
+
+ +
+
+ validate_token(token_info) +
+
+
+ +
+
+ +
+
+ exception spotipy.oauth2.SpotifyStateError(local_state=None, remote_state=None, + message=None, + error=None, + error_description=None, *args, **kwargs) +
+
+

Bases: SpotifyOauthError +

+

The state sent and state received were different

+
+
+ __init__(local_state=None, remote_state=None, message=None, error=None, error_description=None, *args, **kwargs) +
+
+
+ +
+
+ +
+ +

util + Module

+

Shows a user’s playlists (need to be authenticated via oauth)

+
+
+ spotipy.util.prompt_for_user_token(username=None, scope=None, client_id=None, client_secret=None, redirect_uri=None, cache_path=None, oauth_manager=None, show_dialog=False) +
+
+
+ +
+
+
+

Support

+

You can ask questions about Spotipy on Stack Overflow. Don’t forget to add the + Spotipy tag, and any other relevant tags as well, before posting. +

+
+ +
+

If you think you’ve found a bug, let us know at + Spotify Issues +

+
+
+

Troubleshooting +

+

This section aims to address common issues that users may encounter while working with Spotipy and + provide practical solutions to resolve them.

+

Authentication errors: Make sure that you have correctly set up your credentials and are + using the correct authorization flow to avoid authenthication erros. Ensure that your client ID and client + secret are correct and that you have added the appropriate redirect URIs to your Spotify Developer + Dashboard.

+

Playlist creation errors: If you’re having trouble creating a playlist, check that your + user ID is correct, and that the user has the necessary permissions to create playlists. Additionally, + make sure that your code is formatted correctly, along with the fact that you are sending the appropriate + request to the Spotify API.

+

Search errors: If you’re having problems when searching for music, make sure that you + are providing the correct search query parameters. You should also check the Spotify API documentation to + ensure that the endpoint you’re using supports the search parameters you are providing.

+

API changes: Sometimes the Spotify API may change, causing errors in your application. + To fix this, check the Spotify API documentation to see if there are any changes that may affect your code + and update it accordingly.

+

Rate limiting: Making too many requests to the Spotify API within a short period of + time, will result in you hitting the rate limit. To prevent this, use caching and backoff mechanisms in + your code

+

Authorization errors: If you encounter authorization errors, make sure that you have + correctly set up your credentials and are using the correct authorization flow. You may also need to check + if your access token has expired and obtain a new one if necessary.

+
+
+

Contribute

+

Spotipy authored by Paul Lamere (plamere) with contributions by:

+
+
+ +
+
+

If you are a developer with Python experience, and you would like to contribute to Spotipy, please + be sure to follow the guidelines listed below:

+
+
Export the needed Environment variables:::
+
+

export SPOTIPY_CLIENT_ID=client_id_here + export SPOTIPY_CLIENT_SECRET=client_secret_here + export SPOTIPY_CLIENT_USERNAME=client_username_here # This is actually an id not spotify display name + export SPOTIPY_REDIRECT_URI=http://localhost:8080 # Make url is set in app you created to get your ID + and SECRET

+
+
Create virtual environment, install dependencies, run tests:::
+
+

$ virtualenv –python=python3.7 env + (env) $ pip install –user -e . + (env) $ python -m unittest discover -v tests

+
+
+

Lint

+
+
To automatically fix the code style:::
+
+

pip install autopep8 + autopep8 –in-place –aggressive –recursive .

+
+
To verify the code style:::
+
+

pip install flake8 + flake8 .

+
+
To make sure if the import lists are stored correctly:::
+
+

pip install isort + isort . -c -v

+
+
+

Publishing (by maintainer)

+
    +
  • +

    Bump version in setup.py

    +
  • +
  • +

    Bump and date changelog

    +
  • +
  • +

    Add to changelog:

    +
  • +
+
+
::
+
+

## Unreleased

+

// Add your changes here and then delete this line

+
+
+
    +
  • +

    Commit changes

    +
  • +
  • +

    Package to pypi:

    +
  • +
+
+
::
+
+

python setup.py sdist bdist_wheel + python3 setup.py sdist bdist_wheel + twine check dist/* + twine upload –repository-url https://upload.pypi.org/legacy/ –skip-existing + dist/.(whl|gz|zip)~dist/*linux.whl

+
+
+
    +
  • +

    Create github release https://github.com/plamere/spotipy/releases + with the changelog content for the version and a short name that describes the main addition

    +
  • +
  • +

    Build the documentation again to ensure it’s on the latest version

    +
  • +
+

Changelog

+

Don’t forget to add a short description of your change in the CHANGELOG!

+
+
+

License

+

(Taken from https://github.com/plamere/spotipy/blob/master/LICENSE.md): +

+
+
+
MIT License
+Copyright (c) 2021 Paul Lamere
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
+(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+
+
+

Indices and tables

+ +
+ + +
+
+
+
+ +
+
+ + + + + \ No newline at end of file From 792b335a220b435cf0b79b620bb11c6da21303c0 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Sun, 7 May 2023 15:28:12 +0100 Subject: [PATCH 04/18] Add files via upload --- docs/_sources/index.rst.txt | 492 ++++++++++++++ docs/_static/basic.css | 903 ++++++++++++++++++++++++++ docs/_static/classic.css | 269 ++++++++ docs/_static/default.css | 1 + docs/_static/doctools.js | 156 +++++ docs/_static/documentation_options.js | 14 + docs/_static/file.png | Bin 0 -> 286 bytes docs/_static/language_data.js | 199 ++++++ docs/_static/minus.png | Bin 0 -> 90 bytes docs/_static/plus.png | Bin 0 -> 90 bytes docs/_static/pygments.css | 74 +++ docs/_static/searchtools.js | 566 ++++++++++++++++ docs/_static/sidebar.js | 70 ++ docs/_static/sphinx_highlight.js | 144 ++++ docs/genindex.html | 596 +++++++++++++++++ docs/objects.inv | Bin 0 -> 1303 bytes docs/py-modindex.html | 113 ++++ docs/search.html | 102 +++ docs/searchindex.js | 1 + 19 files changed, 3700 insertions(+) create mode 100644 docs/_sources/index.rst.txt create mode 100644 docs/_static/basic.css create mode 100644 docs/_static/classic.css create mode 100644 docs/_static/default.css create mode 100644 docs/_static/doctools.js create mode 100644 docs/_static/documentation_options.js create mode 100644 docs/_static/file.png create mode 100644 docs/_static/language_data.js create mode 100644 docs/_static/minus.png create mode 100644 docs/_static/plus.png create mode 100644 docs/_static/pygments.css create mode 100644 docs/_static/searchtools.js create mode 100644 docs/_static/sidebar.js create mode 100644 docs/_static/sphinx_highlight.js create mode 100644 docs/genindex.html create mode 100644 docs/objects.inv create mode 100644 docs/py-modindex.html create mode 100644 docs/search.html create mode 100644 docs/searchindex.js diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt new file mode 100644 index 00000000..a2e28a2b --- /dev/null +++ b/docs/_sources/index.rst.txt @@ -0,0 +1,492 @@ +.. image:: images/spotify-web-api-doc.jpg + :width: 100 % + +Welcome to Spotipy! +=================================== + +*Spotipy* is a lightweight Python library for the `Spotify Web API +`_. With *Spotipy* +you get full access to all of the music data provided by the Spotify platform. + +Assuming you set the ``SPOTIPY_CLIENT_ID`` and ``SPOTIPY_CLIENT_SECRET`` +environment variables (here is a `video `_ explaining how to do so). For a longer tutorial with examples included, refer to this `video playlist `_. Below is a quick example of using *Spotipy* to list the +names of all the albums released by the artist 'Birdy':: + + import spotipy + from spotipy.oauth2 import SpotifyClientCredentials + + birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP' + spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) + + results = spotify.artist_albums(birdy_uri, album_type='album') + albums = results['items'] + while results['next']: + results = spotify.next(results) + albums.extend(results['items']) + + for album in albums: + print(album['name']) + +Here's another example showing how to get 30 second samples and cover art +for the top 10 tracks for Led Zeppelin:: + + import spotipy + from spotipy.oauth2 import SpotifyClientCredentials + + lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp' + + spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) + results = spotify.artist_top_tracks(lz_uri) + + for track in results['tracks'][:10]: + print('track : ' + track['name']) + print('audio : ' + track['preview_url']) + print('cover art: ' + track['album']['images'][0]['url']) + print() + +Finally, here's an example that will get the URL for an artist image given the +artist's name:: + + import spotipy + import sys + from spotipy.oauth2 import SpotifyClientCredentials + + spotify = spotipy.Spotify(auth_manager=SpotifyClientCredentials()) + + if len(sys.argv) > 1: + name = ' '.join(sys.argv[1:]) + else: + name = 'Radiohead' + + results = spotify.search(q='artist:' + name, type='artist') + items = results['artists']['items'] + if len(items) > 0: + artist = items[0] + print(artist['name'], artist['images'][0]['url']) + + +Features +======== + +*Spotipy* supports all of the features of the Spotify Web API including access +to all end points, and support for user authorization. For details on the +capabilities you are encouraged to review the `Spotify Web +API `_ documentation. + +Installation +============ + +**Installing Spotipy on Windows**: + +- Install Python: Download and install Python from the official Python website (https://www.python.org/downloads/). + +- Install Spotipy: Open a command prompt and run pip install spotipy. +Open command prompt and run the following:: + + pip install spotipy + +- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. + +**Installing Spotipy on macOS**: + + +- Install Homebrew: Install Homebrew, a package manager for macOS. + +- Run the followng command:: + + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + +- Install Python: Run brew install python in the terminal:: + + brew install python + +- Install Spotipy: Run pip install spotipy in the terminal:: + + pip install spotipy + +- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. + +**Installing Spotipy on Linux**: + +- Install Python: Use your Linux distribution's package manager to install Python using the following command:: + + sudo apt-get install python3 + +- Install pip: Use your Linux distribution's package manager to install pip using the command:: + + sudo apt-get install python3-pip + +- Install Spotipy: Run pip install spotipy in the terminal. + + pip install spotipy + +- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. + + + .. Install or upgrade *Spotipy* with:: + + pip install spotipy --upgrade + +You can get the source from github at https://github.com/plamere/spotipy + +Getting Started with Spotipy +=============== + +Before you can use Spotipy, there are a few things you need to do: + +Register your app: To make authorized calls to the Spotify Web API, you need to register your app and obtain a client ID and client secret. You can register your app at My Dashboard _. Make sure to keep your client ID and client secret secure. + +Choose an authorization flow: Spotipy supports two authorization flows: the Authorization Code flow and the Client Credentials flow. Choose the one that's suitable for your application. + - **Authorization Code flow** This method is suitable for long-running applications + which the user logs into once. It provides an access token that can be refreshed. + + .. note:: This method requires you to add a redirect URI to your application at + `My Dashboard `_. + See `Redirect URI`_ for more details. + + - **The Client Credentials flow** This is suitable for short-lived applications that don't require user permission. It makes it possible to authenticate your requests to the Spotify Web API and to obtain a higher rate limit than you would with the Authorization Code flow. + +Before you can use Spotipy's methods, you need to authorize your app by registering it at My Dashboard _. This will give you a *client id* and *client secret* that you'll need to use in your code. + + +Authorization Code Flow +======================= + +This flow is suitable for long-running applications in which the user grants +permission only once. It provides an access token that can be refreshed. +Since the token exchange involves sending your secret key, perform this on a +secure location, like a backend service, and not from a client such as a +browser or from a mobile app. + +Quick start +----------- + +To support the **Client Authorization Code Flow** *Spotipy* provides a +class SpotifyOAuth that can be used to authenticate requests like so:: + + import spotipy + from spotipy.oauth2 import SpotifyOAuth + + scope = "user-library-read" + + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) + + results = sp.current_user_saved_tracks() + for idx, item in enumerate(results['items']): + track = item['track'] + print(idx, track['artists'][0]['name'], " – ", track['name']) + +or if you are reluctant to immortalize your app credentials in your source code, +you can set environment variables like so (use ``$env:"credentials"`` instead of ``export`` +on Windows):: + + export SPOTIPY_CLIENT_ID='your-spotify-client-id' + export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret' + export SPOTIPY_REDIRECT_URI='your-app-redirect-url' + +Scopes +------ + +See `Using +Scopes `_ for information +about scopes. + +Redirect URI +------------ + +The **Authorization Code Flow** needs you to add a **redirect URI** +to your application at +`My Dashboard `_ +(navigate to your application and then *[Edit Settings]*). + +The ``redirect_uri`` argument or ``SPOTIPY_REDIRECT_URI`` environment variable +must match the redirect URI added to your application in your Dashboard. +The redirect URI can be any valid URI (it does not need to be accessible) +such as ``http://example.com``, ``http://localhost`` or ``http://127.0.0.1:9090``. + + .. note:: If you choose an `http`-scheme URL, and it's for `localhost` or + 127.0.0.1`, **AND** it specifies a port, then spotipy will instantiate + a server on the indicated response to receive the access token from the + response at the end of the oauth flow [see the code](https://github.com/plamere/spotipy/blob/master/spotipy/oauth2.py#L483-L490). + + +Client Credentials Flow +======================= + +The Client Credentials flow is used in server-to-server authentication. Only +endpoints that do not access user information can be accessed. The advantage here +in comparison with requests to the Web API made without an access token, +is that a higher rate limit is applied. + +As opposed to the Authorization Code Flow, you will not need to set ``SPOTIPY_REDIRECT_URI``, +which means you will never be redirected to the sign in page in your browser:: + + export SPOTIPY_CLIENT_ID='your-spotify-client-id' + export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret' + +To support the **Client Credentials Flow** *Spotipy* provides a +class SpotifyClientCredentials that can be used to authenticate requests like so:: + + + import spotipy + from spotipy.oauth2 import SpotifyClientCredentials + + auth_manager = SpotifyClientCredentials() + sp = spotipy.Spotify(auth_manager=auth_manager) + + playlists = sp.user_playlists('spotify') + while playlists: + for i, playlist in enumerate(playlists['items']): + print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'], playlist['name'])) + if playlists['next']: + playlists = sp.next(playlists) + else: + playlists = None + + +IDs URIs and URLs +================= + +*Spotipy* supports a number of different ID types: + + - **Spotify URI** - The resource identifier that you can enter, for example, in + the Spotify Desktop client's search box to locate an artist, album, or + track. Example: ``spotify:track:6rqhFgbbKwnb9MLmUQDhG6`` + - **Spotify URL** - An HTML link that opens a track, album, app, playlist or other + Spotify resource in a Spotify client. Example: + ``http://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6`` + - **Spotify ID** - A base-62 number that you can find at the end of the Spotify + URI (see above) for an artist, track, album, etc. Example: + ``6rqhFgbbKwnb9MLmUQDhG6`` + +In general, any *Spotipy* method that needs an artist, album, track or playlist ID +will accept ids in any of the above form + + +Customized token caching +======================== + +Tokens are refreshed automatically and stored by default in the project main folder. +As this might not suit everyone's needs, spotipy provides a way to create customized +cache handlers. + +https://github.com/plamere/spotipy/blob/master/spotipy/cache_handler.py + +The custom cache handler would need to be a class that inherits from the base +cache handler ``CacheHandler``. The default cache handler ``CacheFileHandler`` is a good example. +An instance of that new class can then be passed as a parameter when +creating ``SpotifyOAuth``, ``SpotifyPKCE`` or ``SpotifyImplicitGrant``. +The following handlers are available and defined in the URL above. + - ``CacheFileHandler`` + - ``MemoryCacheHandler`` + - ``DjangoSessionCacheHandler`` + - ``FlaskSessionCacheHandler`` + - ``RedisCacheHandler`` + +Feel free to contribute new cache handlers to the repo. + +User Guide +======================= + +In this section, we'll provide a step-by-step tutorial for using some of Spotipy's essential features, such as retrieving user data, and searching for music. + +**Retrieving User Data** + - Import the Spotipy module in your Python code:: + + import spotipy + + - Create a Spotipy object with authentication manager:: + + from spotipy.oauth2 import SpotifyOAuth + + sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id='', + client_secret='', + redirect_uri='')) + - Use the sp.current_user() method to retrieve the authenticated user's data:: + + user_data = sp.current_user() + + - Access various pieces of user data from the user_data dictionary, such as the user's display name:: + + display_name = user_data['display_name'] + +**Searching for Music** + - Use the sp.search() method to search for a track, artist, album or playlist:: + + results = sp.search(q='chocolate', type='track') + + - The results variable contains a dictionary with search results. You can access the list of tracks returned by the search by accessing results['tracks']['items']. + + - Each item in the list of tracks is a dictionary containing information about the track. For example, you can retrieve the track name using track_name = results['tracks']['items'][0]['name']. + + + +Examples +======================= + +There are many more examples of how to use *Spotipy* in the `Examples +Directory `_ on Github + +API Reference +============== + +:mod:`client` Module +======================= + +.. automodule:: spotipy.client + :members: + :undoc-members: + :special-members: __init__ + :show-inheritance: + +:mod:`oauth2` Module +======================= + +.. automodule:: spotipy.oauth2 + :members: + :undoc-members: + :special-members: __init__ + :show-inheritance: + +:mod:`util` Module +-------------------- + +.. automodule:: spotipy.util + :members: + :undoc-members: + :special-members: __init__ + :show-inheritance: + + +Support +======= +You can ask questions about Spotipy on Stack Overflow. Don’t forget to add the +*Spotipy* tag, and any other relevant tags as well, before posting. + + http://stackoverflow.com/questions/ask + +If you think you've found a bug, let us know at +`Spotify Issues `_ + + +Troubleshooting +======= + +This section aims to address common issues that users may encounter while working with Spotipy and provide practical solutions to resolve them. + +**Authentication errors**: Make sure that you have correctly set up your credentials and are using the correct authorization flow to avoid authenthication erros. Ensure that your client ID and client secret are correct and that you have added the appropriate redirect URIs to your Spotify Developer Dashboard. + +**Playlist creation errors**: If you're having trouble creating a playlist, check that your user ID is correct, and that the user has the necessary permissions to create playlists. Additionally, make sure that your code is formatted correctly, along with the fact that you are sending the appropriate request to the Spotify API. + +**Search errors**: If you're having problems when searching for music, make sure that you are providing the correct search query parameters. You should also check the Spotify API documentation to ensure that the endpoint you're using supports the search parameters you are providing. + +**API changes**: Sometimes the Spotify API may change, causing errors in your application. To fix this, check the Spotify API documentation to see if there are any changes that may affect your code and update it accordingly. + +**Rate limiting**: Making too many requests to the Spotify API within a short period of time, will result in you hitting the rate limit. To prevent this, use caching and backoff mechanisms in your code + +**Authorization errors**: If you encounter authorization errors, make sure that you have correctly set up your credentials and are using the correct authorization flow. You may also need to check if your access token has expired and obtain a new one if necessary. + +Contribute +========== + +Spotipy authored by Paul Lamere (plamere) with contributions by: + + - Daniel Beaudry (`danbeaudry on Github `_) + - Faruk Emre Sahin (`fsahin on Github `_) + - George (`rogueleaderr on Github `_) + - Henry Greville (`sethaurus on Github `_) + - Hugo van Kemanade (`hugovk on Github `_) + - José Manuel Pérez (`JMPerez on Github `_) + - Lucas Nunno (`lnunno on Github `_) + - Lynn Root (`econchick on Github `_) + - Matt Dennewitz (`mattdennewitz on Github `_) + - Matthew Duck (`mattduck on Github `_) + - Michael Thelin (`thelinmichael on Github `_) + - Ryan Choi (`ryankicks on Github `_) + - Simon Metson (`drsm79 on Github `_) + - Steve Winton (`swinton on Github `_) + - Tim Balzer (`timbalzer on Github `_) + - `corycorycory on Github `_ + - Nathan Coleman (`nathancoleman on Github `_) + - Michael Birtwell (`mbirtwell on Github `_) + - Harrison Hayes (`Harrison97 on Github `_) + - Stephane Bruckert (`stephanebruckert on Github `_) + - Ritiek Malhotra (`ritiek on Github `_) + +If you are a developer with Python experience, and you would like to contribute to Spotipy, please +be sure to follow the guidelines listed below: + +Export the needed Environment variables::: + export SPOTIPY_CLIENT_ID=client_id_here + export SPOTIPY_CLIENT_SECRET=client_secret_here + export SPOTIPY_CLIENT_USERNAME=client_username_here # This is actually an id not spotify display name + export SPOTIPY_REDIRECT_URI=http://localhost:8080 # Make url is set in app you created to get your ID and SECRET + +Create virtual environment, install dependencies, run tests::: + $ virtualenv --python=python3.7 env + (env) $ pip install --user -e . + (env) $ python -m unittest discover -v tests + +**Lint** + +To automatically fix the code style::: + pip install autopep8 + autopep8 --in-place --aggressive --recursive . + +To verify the code style::: + pip install flake8 + flake8 . + +To make sure if the import lists are stored correctly::: + pip install isort + isort . -c -v + +**Publishing (by maintainer)** + +- Bump version in setup.py +- Bump and date changelog +- Add to changelog: +:: + ## Unreleased + + // Add your changes here and then delete this line +- Commit changes +- Package to pypi: +:: + python setup.py sdist bdist_wheel + python3 setup.py sdist bdist_wheel + twine check dist/* + twine upload --repository-url https://upload.pypi.org/legacy/ --skip-existing dist/*.(whl|gz|zip)~dist/*linux*.whl +- Create github release https://github.com/plamere/spotipy/releases with the changelog content for the version and a short name that describes the main addition +- Build the documentation again to ensure it's on the latest version + +**Changelog** + +Don't forget to add a short description of your change in the `CHANGELOG `_! + + + +License +======= +(Taken from https://github.com/plamere/spotipy/blob/master/LICENSE.md):: + + MIT License + Copyright (c) 2021 Paul Lamere + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/_static/basic.css b/docs/_static/basic.css new file mode 100644 index 00000000..0b965991 --- /dev/null +++ b/docs/_static/basic.css @@ -0,0 +1,903 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_static/classic.css b/docs/_static/classic.css new file mode 100644 index 00000000..4c1370de --- /dev/null +++ b/docs/_static/classic.css @@ -0,0 +1,269 @@ +/* + * classic.css_t + * ~~~~~~~~~~~~~ + * + * Sphinx stylesheet -- classic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +html { + /* CSS hack for macOS's scrollbar (see #1125) */ + background-color: #FFFFFF; +} + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #11303d; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + display: flex; + background-color: #1c4e63; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.body { + background-color: #ffffff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-color: #133f52; + line-height: 30px; + color: #ffffff; +} + +div.related a { + color: #ffffff; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #ffffff; +} + +div.sphinxsidebar h4 { + font-family: 'Trebuchet MS', sans-serif; + color: #ffffff; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div.sphinxsidebar a { + color: #98dbcc; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + + + +/* -- hyperlink styles ------------------------------------------------------ */ + +a { + color: #355f7c; + text-decoration: none; +} + +a:visited { + color: #355f7c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + + + +/* -- body styles ----------------------------------------------------------- */ + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Trebuchet MS', sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 160%; } +div.body h3 { font-size: 140%; } +div.body h4 { font-size: 120%; } +div.body h5 { font-size: 110%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + text-align: justify; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.admonition p { + margin-bottom: 5px; +} + +div.admonition pre { + margin-bottom: 5px; +} + +div.admonition ul, div.admonition ol { + margin-bottom: 5px; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +nav.contents, +aside.topic, +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 5px; + background-color: unset; + color: unset; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +code { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} + +th, dl.field-list > dt { + background-color: #ede; +} + +.warning code { + background: #efc2c2; +} + +.note code { + background: #d6d6d6; +} + +.viewcode-back { + font-family: sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} + +div.code-block-caption { + color: #efefef; + background-color: #1c4e63; +} \ No newline at end of file diff --git a/docs/_static/default.css b/docs/_static/default.css new file mode 100644 index 00000000..81b93636 --- /dev/null +++ b/docs/_static/default.css @@ -0,0 +1 @@ +@import url("classic.css"); diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js new file mode 100644 index 00000000..d06a71d7 --- /dev/null +++ b/docs/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js new file mode 100644 index 00000000..9e67e77f --- /dev/null +++ b/docs/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '2.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/docs/_static/file.png b/docs/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/docs/_static/language_data.js b/docs/_static/language_data.js new file mode 100644 index 00000000..53c120fe --- /dev/null +++ b/docs/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, is available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/docs/_static/minus.png b/docs/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/docs/_static/plus.png b/docs/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/docs/_static/pygments.css b/docs/_static/pygments.css new file mode 100644 index 00000000..bc569267 --- /dev/null +++ b/docs/_static/pygments.css @@ -0,0 +1,74 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_static/searchtools.js b/docs/_static/searchtools.js new file mode 100644 index 00000000..97d56a74 --- /dev/null +++ b/docs/_static/searchtools.js @@ -0,0 +1,566 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = docUrlRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = docUrlRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/docs/_static/sidebar.js b/docs/_static/sidebar.js new file mode 100644 index 00000000..04e83376 --- /dev/null +++ b/docs/_static/sidebar.js @@ -0,0 +1,70 @@ +/* + * sidebar.js + * ~~~~~~~~~~ + * + * This script makes the Sphinx sidebar collapsible. + * + * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds + * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton + * used to collapse and expand the sidebar. + * + * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden + * and the width of the sidebar and the margin-left of the document + * are decreased. When the sidebar is expanded the opposite happens. + * This script saves a per-browser/per-session cookie used to + * remember the position of the sidebar among the pages. + * Once the browser is closed the cookie is deleted and the position + * reset to the default (expanded). + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +const initialiseSidebar = () => { + + + + + // global elements used by the functions. + const bodyWrapper = document.getElementsByClassName("bodywrapper")[0] + const sidebar = document.getElementsByClassName("sphinxsidebar")[0] + const sidebarWrapper = document.getElementsByClassName('sphinxsidebarwrapper')[0] + const sidebarButton = document.getElementById("sidebarbutton") + const sidebarArrow = sidebarButton.querySelector('span') + + // for some reason, the document has no sidebar; do not run into errors + if (typeof sidebar === "undefined") return; + + const flipArrow = element => element.innerText = (element.innerText === "»") ? "«" : "»" + + const collapse_sidebar = () => { + bodyWrapper.style.marginLeft = ".8em"; + sidebar.style.width = ".8em" + sidebarWrapper.style.display = "none" + flipArrow(sidebarArrow) + sidebarButton.title = _('Expand sidebar') + window.localStorage.setItem("sidebar", "collapsed") + } + + const expand_sidebar = () => { + bodyWrapper.style.marginLeft = "" + sidebar.style.removeProperty("width") + sidebarWrapper.style.display = "" + flipArrow(sidebarArrow) + sidebarButton.title = _('Collapse sidebar') + window.localStorage.setItem("sidebar", "expanded") + } + + sidebarButton.addEventListener("click", () => { + (sidebarWrapper.style.display === "none") ? expand_sidebar() : collapse_sidebar() + }) + + if (!window.localStorage.getItem("sidebar")) return + const value = window.localStorage.getItem("sidebar") + if (value === "collapsed") collapse_sidebar(); + else if (value === "expanded") expand_sidebar(); +} + +if (document.readyState !== "loading") initialiseSidebar() +else document.addEventListener("DOMContentLoaded", initialiseSidebar) \ No newline at end of file diff --git a/docs/_static/sphinx_highlight.js b/docs/_static/sphinx_highlight.js new file mode 100644 index 00000000..aae669d7 --- /dev/null +++ b/docs/_static/sphinx_highlight.js @@ -0,0 +1,144 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + parent.insertBefore( + span, + parent.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(SphinxHighlight.highlightSearchWords); +_ready(SphinxHighlight.initEscapeListener); diff --git a/docs/genindex.html b/docs/genindex.html new file mode 100644 index 00000000..498e4421 --- /dev/null +++ b/docs/genindex.html @@ -0,0 +1,596 @@ + + + + + + + Index — spotipy 2.0 documentation + + + + + + + + + + + + +
+
+
+
+ + +

Index

+ +
+ _ + | A + | C + | D + | E + | F + | G + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + +
+

_

+ + +
+ +

A

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + +
+ +

G

+ + + +
+ +

M

+ + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ + + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/objects.inv b/docs/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..9b23c413d35fa14d457e6cab9a5a8dabd7d11756 GIT binary patch literal 1303 zcmV+y1?c)CAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk&aBp;J zaCr(NAXa5^b7^mGIv_GGFbX3eRA^-&a%F8{X>Md?av*PJAarPHb0B7EY-J#6b0A}H zZE$jBb8}^6Aa!$TZf78RY-wUH3V7PJnN4rwHV}sI`4ukOYmBzXy)A;E4YqB9%`OV` zLeS*MCQOkkNjY(UeTSkfTipbGC;|94D-=j@3rwlI%)UO&;bp| z)CZse(nhq{gEfRK?}G0jr2XZ9oitXiEFdLpfn)}SleqT507JZINJVGm-V*0f`Q9aD zD6dQZWlF)U`UICF`VjDX=*9{cA*B~1qK{=B8FJBhYyHb)lsY(;m%hO>Ze1UkFWIsoTc*0g2Z_?K7_RnLkASJ#AvS<`;x6zE-6JqwP!x+WZaU)O&AY^Z>phV2g)=?{SSN}be;@82!ATzgUFlAMCd!~rRJ`( zfKlD|ks&3=4C-MWR#d)i!D*R{cVZ1L;L-umkqx5}I^1dq!U!^`4Oz%I_d#QA$Dd=OjX$MO zkCSF6KV1Egjxbj3w=nYL&Qa_P=RdfB;Sbmtezi2`G1I0w?ETcI(wv-0fU31p(x7U% zk_=VCRl*z!Z!U=3ld1A&2D6Dn4QD%VdrAR%|Ei$N=}?x!baAcvs_(f|Gx1C>ZfA&d z12{I|bI$Vf6<@Q9;DEdv8n_Ff@t=_;Zl3wPeTJ}n{P^|Duj0$&r~5y|*U!IQc*1aw zdX3f3vDP`)Qy7FW%lBJw*E1j5&KhOXFPLAXt8F$@kM_!c9zQ?)bx*e0oJzOXoKx9W zg_pk)2f)`|gjzr!%s(LdU~2%CRGWOBTVuqX3=!sIuF=hcorqPsx|7ym$w;O>ejF>P ztK4BwRda(=8ZQVH65WxCp6@^>9G>IMLD^x-S%bRp82cQJxUP>Np4$~pHFrD3O(c$~ z0yN0kR9OvdPt8~NA^31%HuRpH;U7<*?(VM+7Fkp+R-C|ip<)2>EKwm)95EH#`x_Y1 zjV2DyxhG7w#o7#OeH}M)3j+O9BI&|X;tgiCcyU5whKqqzCt3_BZm@VxD5eLCqx>ot z>65Wn6gK(wWfy$g5m?=xY!S2WM% N`IB73&A+!of_p&@b(H`B literal 0 HcmV?d00001 diff --git a/docs/py-modindex.html b/docs/py-modindex.html new file mode 100644 index 00000000..71c59501 --- /dev/null +++ b/docs/py-modindex.html @@ -0,0 +1,113 @@ + + + + + + + Python Module Index — spotipy 2.0 documentation + + + + + + + + + + + + + + + +
+
+
+
+ + +

Python Module Index

+ +
+ s +
+ + + + + + + + + + + + + + + + +
 
+ s
+ spotipy +
    + spotipy.client +
    + spotipy.oauth2 +
    + spotipy.util +
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/search.html b/docs/search.html new file mode 100644 index 00000000..a97601bf --- /dev/null +++ b/docs/search.html @@ -0,0 +1,102 @@ + + + + + + + Search — spotipy 2.0 documentation + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + + +
+ +
+ + +
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/searchindex.js b/docs/searchindex.js new file mode 100644 index 00000000..78fb8971 --- /dev/null +++ b/docs/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["index"], "filenames": ["index.rst"], "titles": ["Welcome to Spotipy!"], "terms": {"i": 0, "lightweight": 0, "python": 0, "librari": 0, "spotifi": 0, "web": 0, "With": 0, "you": 0, "full": 0, "access": 0, "all": 0, "music": 0, "data": 0, "provid": 0, "platform": 0, "assum": 0, "set": 0, "spotipy_client_id": 0, "spotipy_client_secret": 0, "environ": 0, "variabl": 0, "here": 0, "video": 0, "explain": 0, "how": 0, "do": 0, "so": 0, "For": 0, "longer": 0, "tutori": 0, "includ": 0, "thi": 0, "playlist": 0, "below": 0, "us": 0, "list": 0, "name": 0, "album": 0, "releas": 0, "artist": 0, "birdi": 0, "import": 0, "from": 0, "spotifyclientcredenti": 0, "birdy_uri": 0, "2wx2utcsvv5ons0inacecp": 0, "client_credentials_manag": 0, "result": 0, "artist_album": 0, "album_typ": 0, "item": 0, "while": 0, "next": 0, "extend": 0, "print": 0, "": 0, "anoth": 0, "show": 0, "30": 0, "second": 0, "sampl": 0, "cover": 0, "art": 0, "top": 0, "10": 0, "track": 0, "led": 0, "zeppelin": 0, "lz_uri": 0, "36qjpde2go2kgarlehcdtp": 0, "artist_top_track": 0, "audio": 0, "preview_url": 0, "imag": 0, "0": 0, "final": 0, "an": 0, "given": 0, "sy": 0, "auth_manag": 0, "len": 0, "argv": 0, "1": 0, "join": 0, "els": 0, "radiohead": 0, "search": 0, "q": 0, "type": 0, "end": 0, "point": 0, "detail": 0, "capabl": 0, "ar": 0, "encourag": 0, "review": 0, "document": 0, "window": 0, "download": 0, "offici": 0, "websit": 0, "http": 0, "www": 0, "org": 0, "open": 0, "command": 0, "prompt": 0, "run": 0, "pip": 0, "follow": 0, "authent": 0, "your": 0, "app": 0, "regist": 0, "develop": 0, "dashboard": 0, "obtain": 0, "secret": 0, "maco": 0, "homebrew": 0, "packag": 0, "manag": 0, "followng": 0, "bin": 0, "bash": 0, "c": 0, "curl": 0, "fssl": 0, "raw": 0, "githubusercont": 0, "com": 0, "head": 0, "sh": 0, "brew": 0, "termin": 0, "linux": 0, "distribut": 0, "sudo": 0, "apt": 0, "python3": 0, "can": 0, "sourc": 0, "github": 0, "plamer": 0, "befor": 0, "few": 0, "thing": 0, "need": 0, "To": 0, "make": 0, "call": 0, "my": 0, "applic": 0, "_": 0, "sure": 0, "keep": 0, "choos": 0, "two": 0, "one": 0, "suitabl": 0, "method": 0, "long": 0, "which": 0, "log": 0, "onc": 0, "It": 0, "refresh": 0, "requir": 0, "add": 0, "see": 0, "more": 0, "The": 0, "short": 0, "live": 0, "don": 0, "t": 0, "permiss": 0, "possibl": 0, "request": 0, "higher": 0, "rate": 0, "limit": 0, "than": 0, "would": 0, "give": 0, "ll": 0, "grant": 0, "onli": 0, "sinc": 0, "exchang": 0, "involv": 0, "send": 0, "kei": 0, "perform": 0, "locat": 0, "like": 0, "backend": 0, "servic": 0, "browser": 0, "mobil": 0, "class": 0, "spotifyoauth": 0, "read": 0, "sp": 0, "current_user_saved_track": 0, "idx": 0, "enumer": 0, "reluct": 0, "immort": 0, "env": 0, "instead": 0, "export": 0, "spotipy_redirect_uri": 0, "inform": 0, "about": 0, "navig": 0, "edit": 0, "redirect_uri": 0, "argument": 0, "must": 0, "match": 0, "ad": 0, "ani": 0, "valid": 0, "doe": 0, "localhost": 0, "127": 0, "9090": 0, "If": 0, "scheme": 0, "AND": 0, "specifi": 0, "port": 0, "instanti": 0, "server": 0, "respons": 0, "receiv": 0, "oauth": 0, "blob": 0, "master": 0, "py": 0, "l483": 0, "l490": 0, "endpoint": 0, "advantag": 0, "comparison": 0, "made": 0, "without": 0, "appli": 0, "As": 0, "oppos": 0, "mean": 0, "never": 0, "sign": 0, "page": 0, "user_playlist": 0, "4d": 0, "offset": 0, "none": 0, "number": 0, "differ": 0, "resourc": 0, "identifi": 0, "enter": 0, "desktop": 0, "box": 0, "6rqhfgbbkwnb9mlmuqdhg6": 0, "html": 0, "link": 0, "other": 0, "A": 0, "base": 0, "62": 0, "find": 0, "abov": 0, "etc": 0, "In": 0, "gener": 0, "accept": 0, "form": 0, "automat": 0, "store": 0, "default": 0, "project": 0, "main": 0, "folder": 0, "might": 0, "suit": 0, "everyon": 0, "wai": 0, "creat": 0, "handler": 0, "cache_handl": 0, "inherit": 0, "cachehandl": 0, "cachefilehandl": 0, "good": 0, "instanc": 0, "new": 0, "pass": 0, "when": 0, "spotifypkc": 0, "spotifyimplicitgr": 0, "avail": 0, "defin": 0, "memorycachehandl": 0, "djangosessioncachehandl": 0, "flasksessioncachehandl": 0, "rediscachehandl": 0, "feel": 0, "free": 0, "repo": 0, "section": 0, "we": 0, "step": 0, "some": 0, "essenti": 0, "retriev": 0, "object": 0, "client_id": 0, "your_client_id": 0, "client_secret": 0, "your_client_secret": 0, "your_redirect_uri": 0, "current_us": 0, "user_data": 0, "variou": 0, "piec": 0, "dictionari": 0, "displai": 0, "display_nam": 0, "chocol": 0, "contain": 0, "return": 0, "each": 0, "track_nam": 0, "There": 0, "mani": 0, "directori": 0, "simpl": 0, "thin": 0, "auth": 0, "requests_sess": 0, "true": 0, "oauth_manag": 0, "proxi": 0, "requests_timeout": 0, "5": 0, "status_forcelist": 0, "retri": 0, "3": 0, "status_retri": 0, "backoff_factor": 0, "languag": 0, "usag": 0, "urn": 0, "3jostutkeu2jkjvrdba5gu": 0, "__init__": 0, "option": 0, "session": 0, "truthi": 0, "valu": 0, "falsi": 0, "disabl": 0, "should": 0, "idea": 0, "enabl": 0, "reason": 0, "connect": 0, "pool": 0, "definit": 0, "doc": 0, "2": 0, "en": 0, "advanc": 0, "tell": 0, "stop": 0, "wait": 0, "after": 0, "what": 0, "statu": 0, "occur": 0, "total": 0, "allow": 0, "time": 0, "bad": 0, "backoff": 0, "factor": 0, "between": 0, "attempt": 0, "try": 0, "urllib3": 0, "readthedoc": 0, "io": 0, "latest": 0, "advertis": 0, "prefer": 0, "iso": 0, "639": 0, "wikipedia": 0, "wiki": 0, "list_of_iso_639": 0, "1_code": 0, "add_to_queu": 0, "device_id": 0, "song": 0, "queue": 0, "devic": 0, "current": 0, "plai": 0, "b": 0, "player": 0, "fail": 0, "restrict": 0, "violat": 0, "error": 0, "therefor": 0, "recommend": 0, "leav": 0, "activ": 0, "target": 0, "album_id": 0, "market": 0, "singl": 0, "3166": 0, "alpha": 0, "countri": 0, "album_track": 0, "50": 0, "catalog": 0, "index": 0, "first": 0, "artist_id": 0, "20": 0, "appears_on": 0, "compil": 0, "particular": 0, "artist_related_artist": 0, "similar": 0, "analysi": 0, "commun": 0, "listen": 0, "histori": 0, "u": 0, "audio_analysi": 0, "track_id": 0, "upon": 0, "its": 0, "audio_featur": 0, "multipl": 0, "maximum": 0, "100": 0, "properti": 0, "available_market": 0, "where": 0, "addit": 0, "special": 0, "territori": 0, "categori": 0, "local": 0, "desir": 0, "consist": 0, "underscor": 0, "minimum": 0, "category_id": 0, "info": 0, "category_playlist": 0, "specif": 0, "country_cod": 0, "au": 0, "AT": 0, "BE": 0, "bo": 0, "br": 0, "bg": 0, "ca": 0, "cl": 0, "co": 0, "cr": 0, "cy": 0, "cz": 0, "dk": 0, "ec": 0, "sv": 0, "ee": 0, "fi": 0, "fr": 0, "de": 0, "gr": 0, "gt": 0, "hn": 0, "hk": 0, "hu": 0, "ie": 0, "IT": 0, "jp": 0, "lv": 0, "li": 0, "lt": 0, "lu": 0, "mt": 0, "mx": 0, "mc": 0, "nl": 0, "nz": 0, "ni": 0, "NO": 0, "pa": 0, "pe": 0, "ph": 0, "pl": 0, "pt": 0, "sg": 0, "e": 0, "sk": 0, "se": 0, "ch": 0, "tw": 0, "tr": 0, "gb": 0, "ui": 0, "current_playback": 0, "additional_typ": 0, "playback": 0, "episod": 0, "podcast": 0, "profil": 0, "alia": 0, "me": 0, "current_user_follow_playlist": 0, "playlist_id": 0, "current_user_followed_artist": 0, "last": 0, "previou": 0, "current_user_following_artist": 0, "check": 0, "certain": 0, "boolean": 0, "respect": 0, "current_user_following_us": 0, "current_user_playing_track": 0, "current_user_playlist": 0, "hi": 0, "current_user_recently_plai": 0, "recent": 0, "entiti": 0, "unix": 0, "timestamp": 0, "millisecond": 0, "cursor": 0, "posit": 0, "cannot": 0, "current_user_saved_album": 0, "save": 0, "max_limit": 0, "current_user_saved_albums_add": 0, "current_user_saved_albums_contain": 0, "alreadi": 0, "current_user_saved_albums_delet": 0, "remov": 0, "current_user_saved_episod": 0, "current_user_saved_episodes_add": 0, "current_user_saved_episodes_contain": 0, "current_user_saved_episodes_delet": 0, "current_user_saved_show": 0, "current_user_saved_shows_add": 0, "current_user_saved_shows_contain": 0, "current_user_saved_shows_delet": 0, "current_user_saved_tracks_add": 0, "current_user_saved_tracks_contain": 0, "current_user_saved_tracks_delet": 0, "current_user_top_artist": 0, "time_rang": 0, "medium_term": 0, "over": 0, "frame": 0, "affin": 0, "comput": 0, "short_term": 0, "long_term": 0, "current_user_top_track": 0, "current_user_unfollow_playlist": 0, "unfollow": 0, "delet": 0, "currently_plai": 0, "default_retry_cod": 0, "429": 0, "500": 0, "502": 0, "503": 0, "504": 0, "episode_id": 0, "take": 0, "preced": 0, "neither": 0, "nor": 0, "content": 0, "consid": 0, "unavail": 0, "featured_playlist": 0, "lowercas": 0, "uppercas": 0, "8601": 0, "format": 0, "yyyi": 0, "mm": 0, "ddthh": 0, "ss": 0, "tailor": 0, "date": 0, "dai": 0, "max_retri": 0, "new_releas": 0, "previous": 0, "next_track": 0, "skip": 0, "pause_playback": 0, "paus": 0, "field": 0, "string": 0, "from_token": 0, "playlist_add_item": 0, "playlist_change_detail": 0, "public": 0, "collabor": 0, "descript": 0, "chang": 0, "privat": 0, "state": 0, "playlist_cover_imag": 0, "playlist_is_follow": 0, "user_id": 0, "want": 0, "thei": 0, "playlist_item": 0, "playlist_remove_all_occurrences_of_item": 0, "snapshot_id": 0, "occurr": 0, "snapshot": 0, "playlist_remove_specific_occurrences_of_item": 0, "arrai": 0, "4iv5w9uyedyuva79axb7rh": 0, "1301wleyt98msxvhpzca6m": 0, "7": 0, "playlist_reorder_item": 0, "range_start": 0, "insert_befor": 0, "range_length": 0, "reorder": 0, "insert": 0, "playlist_replace_item": 0, "replac": 0, "compris": 0, "playlist_track": 0, "playlist_upload_cover_imag": 0, "image_b64": 0, "repres": 0, "base64": 0, "encod": 0, "jpeg": 0, "payload": 0, "size": 0, "256": 0, "kb": 0, "previous_track": 0, "recommendation_genre_se": 0, "genr": 0, "function": 0, "seed_artist": 0, "seed_genr": 0, "seed_track": 0, "kwarg": 0, "five": 0, "seed": 0, "least": 0, "found": 0, "playabl": 0, "min": 0, "max": 0, "target_": 0, "attribut": 0, "tuneabl": 0, "filter": 0, "repeat": 0, "mode": 0, "context": 0, "off": 0, "queri": 0, "write": 0, "noqa": 0, "within": 0, "One": 0, "comma": 0, "separ": 0, "g": 0, "search_market": 0, "experiment": 0, "done": 0, "across": 0, "seek_track": 0, "position_m": 0, "seek": 0, "set_auth": 0, "show_id": 0, "show_episod": 0, "shuffl": 0, "toggl": 0, "fals": 0, "start_playback": 0, "context_uri": 0, "resum": 0, "int": 0, "greater": 0, "length": 0, "caus": 0, "transfer_playback": 0, "force_plai": 0, "transfer": 0, "note": 0, "actual": 0, "basic": 0, "usr": 0, "user_follow_artist": 0, "user_follow_us": 0, "user_playlist_add_episod": 0, "user_playlist_add_track": 0, "user_playlist_change_detail": 0, "user_playlist_cr": 0, "user_playlist_follow_playlist": 0, "playlist_owner_id": 0, "owner": 0, "user_playlist_is_follow": 0, "user_playlist_remove_all_occurrences_of_track": 0, "user_playlist_remove_specific_occurrences_of_track": 0, "user_playlist_reorder_track": 0, "user_playlist_replace_track": 0, "user_playlist_track": 0, "user_playlist_unfollow": 0, "user_unfollow_artist": 0, "user_unfollow_us": 0, "volum": 0, "volume_perc": 0, "except": 0, "spotifyexcept": 0, "http_statu": 0, "msg": 0, "header": 0, "spotifyauthbas": 0, "oauth_token_url": 0, "account": 0, "howev": 0, "interact": 0, "either": 0, "constructor": 0, "suppli": 0, "rout": 0, "through": 0, "handl": 0, "otherwis": 0, "cache_path": 0, "usernam": 0, "get_access_token": 0, "as_dict": 0, "check_cach": 0, "memori": 0, "fetch": 0, "token_info": 0, "show_dialog": 0, "implement": 0, "implicit": 0, "non": 0, "copi": 0, "past": 0, "everi": 0, "hour": 0, "standard": 0, "side": 0, "ha": 0, "suggest": 0, "pkce": 0, "extens": 0, "plu": 0, "get_auth_respons": 0, "access_token": 0, "get_authorization_cod": 0, "get_cached_token": 0, "parse_response_token": 0, "parse_response_cod": 0, "concern": 0, "intercept": 0, "proof": 0, "origin": 0, "could": 0, "easili": 0, "compromis": 0, "network": 0, "oauth_authorize_url": 0, "help": 0, "mai": 0, "verif": 0, "deprec": 0, "interpret": 0, "overrid": 0, "self": 0, "break": 0, "expir": 0, "get_authorize_url": 0, "static": 0, "parse_auth_response_url": 0, "pars": 0, "validate_token": 0, "open_brows": 0, "whether": 0, "refresh_access_token": 0, "refresh_token": 0, "spotifyoautherror": 0, "messag": 0, "error_descript": 0, "arg": 0, "dure": 0, "both": 0, "shown": 0, "get_pkce_handshake_paramet": 0, "spotifystateerror": 0, "local_st": 0, "remote_st": 0, "sent": 0, "were": 0, "via": 0, "prompt_for_user_token": 0, "ask": 0, "question": 0, "stack": 0, "overflow": 0, "forget": 0, "tag": 0, "relev": 0, "well": 0, "post": 0, "stackoverflow": 0, "think": 0, "ve": 0, "bug": 0, "let": 0, "know": 0, "issu": 0, "aim": 0, "address": 0, "common": 0, "encount": 0, "work": 0, "practic": 0, "solut": 0, "resolv": 0, "them": 0, "have": 0, "correctli": 0, "up": 0, "correct": 0, "avoid": 0, "authenth": 0, "erro": 0, "ensur": 0, "appropri": 0, "creation": 0, "re": 0, "troubl": 0, "necessari": 0, "addition": 0, "along": 0, "fact": 0, "problem": 0, "also": 0, "sometim": 0, "fix": 0, "affect": 0, "updat": 0, "accordingli": 0, "too": 0, "period": 0, "hit": 0, "prevent": 0, "mechan": 0, "paul": 0, "lamer": 0, "daniel": 0, "beaudri": 0, "danbeaudri": 0, "faruk": 0, "emr": 0, "sahin": 0, "fsahin": 0, "georg": 0, "rogueleaderr": 0, "henri": 0, "grevil": 0, "sethauru": 0, "hugo": 0, "van": 0, "kemanad": 0, "hugovk": 0, "jos\u00e9": 0, "manuel": 0, "p\u00e9rez": 0, "jmperez": 0, "luca": 0, "nunno": 0, "lnunno": 0, "lynn": 0, "root": 0, "econchick": 0, "matt": 0, "dennewitz": 0, "mattdennewitz": 0, "matthew": 0, "duck": 0, "mattduck": 0, "michael": 0, "thelin": 0, "thelinmichael": 0, "ryan": 0, "choi": 0, "ryankick": 0, "simon": 0, "metson": 0, "drsm79": 0, "steve": 0, "winton": 0, "swinton": 0, "tim": 0, "balzer": 0, "timbalz": 0, "corycorycori": 0, "nathan": 0, "coleman": 0, "nathancoleman": 0, "birtwel": 0, "mbirtwel": 0, "harrison": 0, "hay": 0, "harrison97": 0, "stephan": 0, "bruckert": 0, "stephanebruckert": 0, "ritiek": 0, "malhotra": 0, "experi": 0, "pleas": 0, "guidelin": 0, "client_id_her": 0, "client_secret_her": 0, "spotipy_client_usernam": 0, "client_username_her": 0, "8080": 0, "virtual": 0, "depend": 0, "test": 0, "virtualenv": 0, "m": 0, "unittest": 0, "discov": 0, "v": 0, "lint": 0, "style": 0, "autopep8": 0, "place": 0, "aggress": 0, "recurs": 0, "verifi": 0, "flake8": 0, "isort": 0, "publish": 0, "maintain": 0, "bump": 0, "version": 0, "setup": 0, "changelog": 0, "unreleas": 0, "line": 0, "commit": 0, "pypi": 0, "sdist": 0, "bdist_wheel": 0, "twine": 0, "dist": 0, "upload": 0, "repositori": 0, "legaci": 0, "exist": 0, "whl": 0, "gz": 0, "zip": 0, "describ": 0, "build": 0, "again": 0, "taken": 0, "md": 0, "mit": 0, "copyright": 0, "2021": 0, "herebi": 0, "charg": 0, "person": 0, "softwar": 0, "associ": 0, "file": 0, "deal": 0, "right": 0, "modifi": 0, "merg": 0, "sublicens": 0, "sell": 0, "permit": 0, "whom": 0, "furnish": 0, "subject": 0, "condit": 0, "notic": 0, "shall": 0, "substanti": 0, "portion": 0, "THE": 0, "AS": 0, "warranti": 0, "OF": 0, "kind": 0, "express": 0, "OR": 0, "impli": 0, "BUT": 0, "NOT": 0, "TO": 0, "merchant": 0, "fit": 0, "FOR": 0, "purpos": 0, "noninfring": 0, "IN": 0, "event": 0, "holder": 0, "liabl": 0, "claim": 0, "damag": 0, "liabil": 0, "action": 0, "contract": 0, "tort": 0, "aris": 0, "out": 0, "WITH": 0}, "objects": {"spotipy": [[0, 0, 0, "-", "client"], [0, 0, 0, "-", "oauth2"], [0, 0, 0, "-", "util"]], "spotipy.client": [[0, 1, 1, "", "Spotify"], [0, 5, 1, "", "SpotifyException"]], "spotipy.client.Spotify": [[0, 2, 1, "", "__init__"], [0, 2, 1, "", "add_to_queue"], [0, 2, 1, "", "album"], [0, 2, 1, "", "album_tracks"], [0, 2, 1, "", "albums"], [0, 2, 1, "", "artist"], [0, 2, 1, "", "artist_albums"], [0, 2, 1, "", "artist_related_artists"], [0, 2, 1, "", "artist_top_tracks"], [0, 2, 1, "", "artists"], [0, 2, 1, "", "audio_analysis"], [0, 2, 1, "", "audio_features"], [0, 3, 1, "", "auth_manager"], [0, 2, 1, "", "available_markets"], [0, 2, 1, "", "categories"], [0, 2, 1, "", "category"], [0, 2, 1, "", "category_playlists"], [0, 4, 1, "", "country_codes"], [0, 2, 1, "", "current_playback"], [0, 2, 1, "", "current_user"], [0, 2, 1, "", "current_user_follow_playlist"], [0, 2, 1, "", "current_user_followed_artists"], [0, 2, 1, "", "current_user_following_artists"], [0, 2, 1, "", "current_user_following_users"], [0, 2, 1, "", "current_user_playing_track"], [0, 2, 1, "", "current_user_playlists"], [0, 2, 1, "", "current_user_recently_played"], [0, 2, 1, "", "current_user_saved_albums"], [0, 2, 1, "", "current_user_saved_albums_add"], [0, 2, 1, "", "current_user_saved_albums_contains"], [0, 2, 1, "", "current_user_saved_albums_delete"], [0, 2, 1, "", "current_user_saved_episodes"], [0, 2, 1, "", "current_user_saved_episodes_add"], [0, 2, 1, "", "current_user_saved_episodes_contains"], [0, 2, 1, "", "current_user_saved_episodes_delete"], [0, 2, 1, "", "current_user_saved_shows"], [0, 2, 1, "", "current_user_saved_shows_add"], [0, 2, 1, "", "current_user_saved_shows_contains"], [0, 2, 1, "", "current_user_saved_shows_delete"], [0, 2, 1, "", "current_user_saved_tracks"], [0, 2, 1, "", "current_user_saved_tracks_add"], [0, 2, 1, "", "current_user_saved_tracks_contains"], [0, 2, 1, "", "current_user_saved_tracks_delete"], [0, 2, 1, "", "current_user_top_artists"], [0, 2, 1, "", "current_user_top_tracks"], [0, 2, 1, "", "current_user_unfollow_playlist"], [0, 2, 1, "", "currently_playing"], [0, 4, 1, "", "default_retry_codes"], [0, 2, 1, "", "devices"], [0, 2, 1, "", "episode"], [0, 2, 1, "", "episodes"], [0, 2, 1, "", "featured_playlists"], [0, 4, 1, "", "max_retries"], [0, 2, 1, "", "me"], [0, 2, 1, "", "new_releases"], [0, 2, 1, "", "next"], [0, 2, 1, "", "next_track"], [0, 2, 1, "", "pause_playback"], [0, 2, 1, "", "playlist"], [0, 2, 1, "", "playlist_add_items"], [0, 2, 1, "", "playlist_change_details"], [0, 2, 1, "", "playlist_cover_image"], [0, 2, 1, "", "playlist_is_following"], [0, 2, 1, "", "playlist_items"], [0, 2, 1, "", "playlist_remove_all_occurrences_of_items"], [0, 2, 1, "", "playlist_remove_specific_occurrences_of_items"], [0, 2, 1, "", "playlist_reorder_items"], [0, 2, 1, "", "playlist_replace_items"], [0, 2, 1, "", "playlist_tracks"], [0, 2, 1, "", "playlist_upload_cover_image"], [0, 2, 1, "", "previous"], [0, 2, 1, "", "previous_track"], [0, 2, 1, "", "queue"], [0, 2, 1, "", "recommendation_genre_seeds"], [0, 2, 1, "", "recommendations"], [0, 2, 1, "", "repeat"], [0, 2, 1, "", "search"], [0, 2, 1, "", "search_markets"], [0, 2, 1, "", "seek_track"], [0, 2, 1, "", "set_auth"], [0, 2, 1, "", "show"], [0, 2, 1, "", "show_episodes"], [0, 2, 1, "", "shows"], [0, 2, 1, "", "shuffle"], [0, 2, 1, "", "start_playback"], [0, 2, 1, "", "track"], [0, 2, 1, "", "tracks"], [0, 2, 1, "", "transfer_playback"], [0, 2, 1, "", "user"], [0, 2, 1, "", "user_follow_artists"], [0, 2, 1, "", "user_follow_users"], [0, 2, 1, "", "user_playlist"], [0, 2, 1, "", "user_playlist_add_episodes"], [0, 2, 1, "", "user_playlist_add_tracks"], [0, 2, 1, "", "user_playlist_change_details"], [0, 2, 1, "", "user_playlist_create"], [0, 2, 1, "", "user_playlist_follow_playlist"], [0, 2, 1, "", "user_playlist_is_following"], [0, 2, 1, "", "user_playlist_remove_all_occurrences_of_tracks"], [0, 2, 1, "", "user_playlist_remove_specific_occurrences_of_tracks"], [0, 2, 1, "", "user_playlist_reorder_tracks"], [0, 2, 1, "", "user_playlist_replace_tracks"], [0, 2, 1, "", "user_playlist_tracks"], [0, 2, 1, "", "user_playlist_unfollow"], [0, 2, 1, "", "user_playlists"], [0, 2, 1, "", "user_unfollow_artists"], [0, 2, 1, "", "user_unfollow_users"], [0, 2, 1, "", "volume"]], "spotipy.client.SpotifyException": [[0, 2, 1, "", "__init__"]], "spotipy.oauth2": [[0, 1, 1, "", "SpotifyClientCredentials"], [0, 1, 1, "", "SpotifyImplicitGrant"], [0, 1, 1, "", "SpotifyOAuth"], [0, 5, 1, "", "SpotifyOauthError"], [0, 1, 1, "", "SpotifyPKCE"], [0, 5, 1, "", "SpotifyStateError"]], "spotipy.oauth2.SpotifyClientCredentials": [[0, 4, 1, "", "OAUTH_TOKEN_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"]], "spotipy.oauth2.SpotifyImplicitGrant": [[0, 4, 1, "", "OAUTH_AUTHORIZE_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"], [0, 2, 1, "", "get_auth_response"], [0, 2, 1, "", "get_authorize_url"], [0, 2, 1, "", "get_cached_token"], [0, 2, 1, "", "parse_auth_response_url"], [0, 2, 1, "", "parse_response_token"], [0, 2, 1, "", "validate_token"]], "spotipy.oauth2.SpotifyOAuth": [[0, 4, 1, "", "OAUTH_AUTHORIZE_URL"], [0, 4, 1, "", "OAUTH_TOKEN_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"], [0, 2, 1, "", "get_auth_response"], [0, 2, 1, "", "get_authorization_code"], [0, 2, 1, "", "get_authorize_url"], [0, 2, 1, "", "get_cached_token"], [0, 2, 1, "", "parse_auth_response_url"], [0, 2, 1, "", "parse_response_code"], [0, 2, 1, "", "refresh_access_token"], [0, 2, 1, "", "validate_token"]], "spotipy.oauth2.SpotifyOauthError": [[0, 2, 1, "", "__init__"]], "spotipy.oauth2.SpotifyPKCE": [[0, 4, 1, "", "OAUTH_AUTHORIZE_URL"], [0, 4, 1, "", "OAUTH_TOKEN_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"], [0, 2, 1, "", "get_authorization_code"], [0, 2, 1, "", "get_authorize_url"], [0, 2, 1, "", "get_cached_token"], [0, 2, 1, "", "get_pkce_handshake_parameters"], [0, 2, 1, "", "parse_auth_response_url"], [0, 2, 1, "", "parse_response_code"], [0, 2, 1, "", "refresh_access_token"], [0, 2, 1, "", "validate_token"]], "spotipy.oauth2.SpotifyStateError": [[0, 2, 1, "", "__init__"]], "spotipy.util": [[0, 6, 1, "", "prompt_for_user_token"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:property", "4": "py:attribute", "5": "py:exception", "6": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "property", "Python property"], "4": ["py", "attribute", "Python attribute"], "5": ["py", "exception", "Python exception"], "6": ["py", "function", "Python function"]}, "titleterms": {"welcom": 0, "spotipi": 0, "featur": 0, "instal": 0, "get": 0, "start": 0, "author": 0, "code": 0, "flow": 0, "quick": 0, "scope": 0, "redirect": 0, "uri": 0, "client": 0, "credenti": 0, "id": 0, "url": 0, "custom": 0, "token": 0, "cach": 0, "user": 0, "guid": 0, "exampl": 0, "api": 0, "refer": 0, "modul": 0, "oauth2": 0, "secur": 0, "warn": 0, "paramet": 0, "util": 0, "support": 0, "troubleshoot": 0, "contribut": 0, "licens": 0, "indic": 0, "tabl": 0}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Welcome to Spotipy!": [[0, "welcome-to-spotipy"]], "Features": [[0, "features"]], "Installation": [[0, "installation"]], "Getting Started with Spotipy": [[0, "getting-started-with-spotipy"]], "Authorization Code Flow": [[0, "authorization-code-flow"]], "Quick start": [[0, "quick-start"]], "Scopes": [[0, "scopes"]], "Redirect URI": [[0, "redirect-uri"]], "Client Credentials Flow": [[0, "client-credentials-flow"]], "IDs URIs and URLs": [[0, "ids-uris-and-urls"]], "Customized token caching": [[0, "customized-token-caching"]], "User Guide": [[0, "user-guide"]], "Examples": [[0, "examples"]], "API Reference": [[0, "api-reference"]], "client Module": [[0, "module-spotipy.client"]], "oauth2 Module": [[0, "module-spotipy.oauth2"]], "Security Warning": [[0, "security-warning"]], "Parameters": [[0, "parameters"], [0, "id3"]], "util Module": [[0, "module-spotipy.util"]], "Support": [[0, "support"]], "Troubleshooting": [[0, "troubleshooting"]], "Contribute": [[0, "contribute"]], "License": [[0, "license"]], "Indices and tables": [[0, "indices-and-tables"]]}, "indexentries": {"oauth_authorize_url (spotipy.oauth2.spotifyimplicitgrant attribute)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.OAUTH_AUTHORIZE_URL"]], "oauth_authorize_url (spotipy.oauth2.spotifyoauth attribute)": [[0, "spotipy.oauth2.SpotifyOAuth.OAUTH_AUTHORIZE_URL"]], "oauth_authorize_url (spotipy.oauth2.spotifypkce attribute)": [[0, "spotipy.oauth2.SpotifyPKCE.OAUTH_AUTHORIZE_URL"]], "oauth_token_url (spotipy.oauth2.spotifyclientcredentials attribute)": [[0, "spotipy.oauth2.SpotifyClientCredentials.OAUTH_TOKEN_URL"]], "oauth_token_url (spotipy.oauth2.spotifyoauth attribute)": [[0, "spotipy.oauth2.SpotifyOAuth.OAUTH_TOKEN_URL"]], "oauth_token_url (spotipy.oauth2.spotifypkce attribute)": [[0, "spotipy.oauth2.SpotifyPKCE.OAUTH_TOKEN_URL"]], "spotify (class in spotipy.client)": [[0, "spotipy.client.Spotify"]], "spotifyclientcredentials (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyClientCredentials"]], "spotifyexception": [[0, "spotipy.client.SpotifyException"]], "spotifyimplicitgrant (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyImplicitGrant"]], "spotifyoauth (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyOAuth"]], "spotifyoautherror": [[0, "spotipy.oauth2.SpotifyOauthError"]], "spotifypkce (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyPKCE"]], "spotifystateerror": [[0, "spotipy.oauth2.SpotifyStateError"]], "__init__() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.__init__"]], "__init__() (spotipy.client.spotifyexception method)": [[0, "spotipy.client.SpotifyException.__init__"]], "__init__() (spotipy.oauth2.spotifyclientcredentials method)": [[0, "spotipy.oauth2.SpotifyClientCredentials.__init__"]], "__init__() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.__init__"]], "__init__() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.__init__"]], "__init__() (spotipy.oauth2.spotifyoautherror method)": [[0, "spotipy.oauth2.SpotifyOauthError.__init__"]], "__init__() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.__init__"]], "__init__() (spotipy.oauth2.spotifystateerror method)": [[0, "spotipy.oauth2.SpotifyStateError.__init__"]], "add_to_queue() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.add_to_queue"]], "album() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.album"]], "album_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.album_tracks"]], "albums() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.albums"]], "artist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist"]], "artist_albums() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist_albums"]], "artist_related_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist_related_artists"]], "artist_top_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist_top_tracks"]], "artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artists"]], "audio_analysis() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.audio_analysis"]], "audio_features() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.audio_features"]], "auth_manager (spotipy.client.spotify property)": [[0, "spotipy.client.Spotify.auth_manager"]], "available_markets() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.available_markets"]], "categories() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.categories"]], "category() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.category"]], "category_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.category_playlists"]], "country_codes (spotipy.client.spotify attribute)": [[0, "spotipy.client.Spotify.country_codes"]], "current_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_playback"]], "current_user() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user"]], "current_user_follow_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_follow_playlist"]], "current_user_followed_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_followed_artists"]], "current_user_following_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_following_artists"]], "current_user_following_users() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_following_users"]], "current_user_playing_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_playing_track"]], "current_user_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_playlists"]], "current_user_recently_played() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_recently_played"]], "current_user_saved_albums() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums"]], "current_user_saved_albums_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums_add"]], "current_user_saved_albums_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums_contains"]], "current_user_saved_albums_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums_delete"]], "current_user_saved_episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes"]], "current_user_saved_episodes_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes_add"]], "current_user_saved_episodes_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes_contains"]], "current_user_saved_episodes_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes_delete"]], "current_user_saved_shows() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows"]], "current_user_saved_shows_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows_add"]], "current_user_saved_shows_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows_contains"]], "current_user_saved_shows_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows_delete"]], "current_user_saved_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks"]], "current_user_saved_tracks_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks_add"]], "current_user_saved_tracks_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks_contains"]], "current_user_saved_tracks_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks_delete"]], "current_user_top_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_top_artists"]], "current_user_top_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_top_tracks"]], "current_user_unfollow_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_unfollow_playlist"]], "currently_playing() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.currently_playing"]], "default_retry_codes (spotipy.client.spotify attribute)": [[0, "spotipy.client.Spotify.default_retry_codes"]], "devices() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.devices"]], "episode() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.episode"]], "episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.episodes"]], "featured_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.featured_playlists"]], "get_access_token() (spotipy.oauth2.spotifyclientcredentials method)": [[0, "spotipy.oauth2.SpotifyClientCredentials.get_access_token"]], "get_access_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_access_token"]], "get_access_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_access_token"]], "get_access_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_access_token"]], "get_auth_response() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_auth_response"]], "get_auth_response() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_auth_response"]], "get_authorization_code() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_authorization_code"]], "get_authorization_code() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_authorization_code"]], "get_authorize_url() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_authorize_url"]], "get_authorize_url() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_authorize_url"]], "get_authorize_url() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_authorize_url"]], "get_cached_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_cached_token"]], "get_cached_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_cached_token"]], "get_cached_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_cached_token"]], "get_pkce_handshake_parameters() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_pkce_handshake_parameters"]], "max_retries (spotipy.client.spotify attribute)": [[0, "spotipy.client.Spotify.max_retries"]], "me() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.me"]], "module": [[0, "module-spotipy.client"], [0, "module-spotipy.oauth2"], [0, "module-spotipy.util"]], "new_releases() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.new_releases"]], "next() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.next"]], "next_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.next_track"]], "parse_auth_response_url() (spotipy.oauth2.spotifyimplicitgrant static method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.parse_auth_response_url"]], "parse_auth_response_url() (spotipy.oauth2.spotifyoauth static method)": [[0, "spotipy.oauth2.SpotifyOAuth.parse_auth_response_url"]], "parse_auth_response_url() (spotipy.oauth2.spotifypkce static method)": [[0, "spotipy.oauth2.SpotifyPKCE.parse_auth_response_url"]], "parse_response_code() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.parse_response_code"]], "parse_response_code() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.parse_response_code"]], "parse_response_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.parse_response_token"]], "pause_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.pause_playback"]], "playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist"]], "playlist_add_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_add_items"]], "playlist_change_details() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_change_details"]], "playlist_cover_image() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_cover_image"]], "playlist_is_following() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_is_following"]], "playlist_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_items"]], "playlist_remove_all_occurrences_of_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_remove_all_occurrences_of_items"]], "playlist_remove_specific_occurrences_of_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_remove_specific_occurrences_of_items"]], "playlist_reorder_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_reorder_items"]], "playlist_replace_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_replace_items"]], "playlist_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_tracks"]], "playlist_upload_cover_image() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_upload_cover_image"]], "previous() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.previous"]], "previous_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.previous_track"]], "prompt_for_user_token() (in module spotipy.util)": [[0, "spotipy.util.prompt_for_user_token"]], "queue() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.queue"]], "recommendation_genre_seeds() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.recommendation_genre_seeds"]], "recommendations() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.recommendations"]], "refresh_access_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.refresh_access_token"]], "refresh_access_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.refresh_access_token"]], "repeat() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.repeat"]], "search() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.search"]], "search_markets() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.search_markets"]], "seek_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.seek_track"]], "set_auth() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.set_auth"]], "show() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.show"]], "show_episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.show_episodes"]], "shows() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.shows"]], "shuffle() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.shuffle"]], "spotipy.client": [[0, "module-spotipy.client"]], "spotipy.oauth2": [[0, "module-spotipy.oauth2"]], "spotipy.util": [[0, "module-spotipy.util"]], "start_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.start_playback"]], "track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.track"]], "tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.tracks"]], "transfer_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.transfer_playback"]], "user() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user"]], "user_follow_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_follow_artists"]], "user_follow_users() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_follow_users"]], "user_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist"]], "user_playlist_add_episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_add_episodes"]], "user_playlist_add_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_add_tracks"]], "user_playlist_change_details() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_change_details"]], "user_playlist_create() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_create"]], "user_playlist_follow_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_follow_playlist"]], "user_playlist_is_following() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_is_following"]], "user_playlist_remove_all_occurrences_of_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_remove_all_occurrences_of_tracks"]], "user_playlist_remove_specific_occurrences_of_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_remove_specific_occurrences_of_tracks"]], "user_playlist_reorder_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_reorder_tracks"]], "user_playlist_replace_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_replace_tracks"]], "user_playlist_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_tracks"]], "user_playlist_unfollow() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_unfollow"]], "user_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlists"]], "user_unfollow_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_unfollow_artists"]], "user_unfollow_users() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_unfollow_users"]], "validate_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.validate_token"]], "validate_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.validate_token"]], "validate_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.validate_token"]], "volume() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.volume"]]}}) \ No newline at end of file From 35c0f57112b66f488360ba578eefa032731e5d7e Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 19:25:25 +0100 Subject: [PATCH 05/18] Update index.rst Removed User Guide section --- docs/index.rst | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 21aed212..9e43b3d8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -285,42 +285,6 @@ The following handlers are available and defined in the URL above. Feel free to contribute new cache handlers to the repo. -User Guide -======================= - -In this section, we'll provide a step-by-step tutorial for using some of Spotipy's essential features, such as retrieving user data, and searching for music. - -**Retrieving User Data** - - Import the Spotipy module in your Python code:: - - import spotipy - - - Create a Spotipy object with authentication manager:: - - from spotipy.oauth2 import SpotifyOAuth - - sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id='', - client_secret='', - redirect_uri='')) - - Use the sp.current_user() method to retrieve the authenticated user's data:: - - user_data = sp.current_user() - - - Access various pieces of user data from the user_data dictionary, such as the user's display name:: - - display_name = user_data['display_name'] - -**Searching for Music** - - Use the sp.search() method to search for a track, artist, album or playlist:: - - results = sp.search(q='chocolate', type='track') - - - The results variable contains a dictionary with search results. You can access the list of tracks returned by the search by accessing results['tracks']['items']. - - - Each item in the list of tracks is a dictionary containing information about the track. For example, you can retrieve the track name using track_name = results['tracks']['items'][0]['name']. - - - Examples ======================= From 34d51db0517bc844f663f96f1ec4573780ca238d Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 19:37:59 +0100 Subject: [PATCH 06/18] Update index.rst fixed linux install guide --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 9e43b3d8..0528ea16 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -116,7 +116,7 @@ Open command prompt and run the following:: sudo apt-get install python3-pip -- Install Spotipy: Run pip install spotipy in the terminal. +- Install Spotipy: Run pip install spotipy in the terminal:: pip install spotipy From ab64b92fba2ac36f3aff528615f3103f82be3b3f Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:10:02 +0100 Subject: [PATCH 07/18] Delete docs/_static directory --- docs/_static/basic.css | 903 -------------------------- docs/_static/classic.css | 269 -------- docs/_static/default.css | 1 - docs/_static/doctools.js | 156 ----- docs/_static/documentation_options.js | 14 - docs/_static/file.png | Bin 286 -> 0 bytes docs/_static/language_data.js | 199 ------ docs/_static/minus.png | Bin 90 -> 0 bytes docs/_static/plus.png | Bin 90 -> 0 bytes docs/_static/pygments.css | 74 --- docs/_static/searchtools.js | 566 ---------------- docs/_static/sidebar.js | 70 -- docs/_static/sphinx_highlight.js | 144 ---- 13 files changed, 2396 deletions(-) delete mode 100644 docs/_static/basic.css delete mode 100644 docs/_static/classic.css delete mode 100644 docs/_static/default.css delete mode 100644 docs/_static/doctools.js delete mode 100644 docs/_static/documentation_options.js delete mode 100644 docs/_static/file.png delete mode 100644 docs/_static/language_data.js delete mode 100644 docs/_static/minus.png delete mode 100644 docs/_static/plus.png delete mode 100644 docs/_static/pygments.css delete mode 100644 docs/_static/searchtools.js delete mode 100644 docs/_static/sidebar.js delete mode 100644 docs/_static/sphinx_highlight.js diff --git a/docs/_static/basic.css b/docs/_static/basic.css deleted file mode 100644 index 0b965991..00000000 --- a/docs/_static/basic.css +++ /dev/null @@ -1,903 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li p.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 360px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, figure.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -nav.contents, -aside.topic, -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -nav.contents, -aside.topic, -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -nav.contents > :last-child, -aside.topic > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -nav.contents::after, -aside.topic::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -aside.footnote > span, -div.citation > span { - float: left; -} -aside.footnote > span:last-of-type, -div.citation > span:last-of-type { - padding-right: 0.5em; -} -aside.footnote > p { - margin-left: 2em; -} -div.citation > p { - margin-left: 4em; -} -aside.footnote > p:last-of-type, -div.citation > p:last-of-type { - margin-bottom: 0em; -} -aside.footnote > p:last-of-type:after, -div.citation > p:last-of-type:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0 0.5em; - content: ":"; - display: inline-block; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; - white-space: nowrap; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/_static/classic.css b/docs/_static/classic.css deleted file mode 100644 index 4c1370de..00000000 --- a/docs/_static/classic.css +++ /dev/null @@ -1,269 +0,0 @@ -/* - * classic.css_t - * ~~~~~~~~~~~~~ - * - * Sphinx stylesheet -- classic theme. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -html { - /* CSS hack for macOS's scrollbar (see #1125) */ - background-color: #FFFFFF; -} - -body { - font-family: sans-serif; - font-size: 100%; - background-color: #11303d; - color: #000; - margin: 0; - padding: 0; -} - -div.document { - display: flex; - background-color: #1c4e63; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 230px; -} - -div.body { - background-color: #ffffff; - color: #000000; - padding: 0 20px 30px 20px; -} - -div.footer { - color: #ffffff; - width: 100%; - padding: 9px 0 9px 0; - text-align: center; - font-size: 75%; -} - -div.footer a { - color: #ffffff; - text-decoration: underline; -} - -div.related { - background-color: #133f52; - line-height: 30px; - color: #ffffff; -} - -div.related a { - color: #ffffff; -} - -div.sphinxsidebar { -} - -div.sphinxsidebar h3 { - font-family: 'Trebuchet MS', sans-serif; - color: #ffffff; - font-size: 1.4em; - font-weight: normal; - margin: 0; - padding: 0; -} - -div.sphinxsidebar h3 a { - color: #ffffff; -} - -div.sphinxsidebar h4 { - font-family: 'Trebuchet MS', sans-serif; - color: #ffffff; - font-size: 1.3em; - font-weight: normal; - margin: 5px 0 0 0; - padding: 0; -} - -div.sphinxsidebar p { - color: #ffffff; -} - -div.sphinxsidebar p.topless { - margin: 5px 10px 10px 10px; -} - -div.sphinxsidebar ul { - margin: 10px; - padding: 0; - color: #ffffff; -} - -div.sphinxsidebar a { - color: #98dbcc; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - - - -/* -- hyperlink styles ------------------------------------------------------ */ - -a { - color: #355f7c; - text-decoration: none; -} - -a:visited { - color: #355f7c; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - - - -/* -- body styles ----------------------------------------------------------- */ - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Trebuchet MS', sans-serif; - background-color: #f2f2f2; - font-weight: normal; - color: #20435c; - border-bottom: 1px solid #ccc; - margin: 20px -20px 10px -20px; - padding: 3px 0 3px 10px; -} - -div.body h1 { margin-top: 0; font-size: 200%; } -div.body h2 { font-size: 160%; } -div.body h3 { font-size: 140%; } -div.body h4 { font-size: 120%; } -div.body h5 { font-size: 110%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #c60f0f; - font-size: 0.8em; - padding: 0 4px 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - background-color: #c60f0f; - color: white; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - text-align: justify; - line-height: 130%; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -div.admonition p { - margin-bottom: 5px; -} - -div.admonition pre { - margin-bottom: 5px; -} - -div.admonition ul, div.admonition ol { - margin-bottom: 5px; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -nav.contents, -aside.topic, -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre { - padding: 5px; - background-color: unset; - color: unset; - line-height: 120%; - border: 1px solid #ac9; - border-left: none; - border-right: none; -} - -code { - background-color: #ecf0f3; - padding: 0 1px 0 1px; - font-size: 0.95em; -} - -th, dl.field-list > dt { - background-color: #ede; -} - -.warning code { - background: #efc2c2; -} - -.note code { - background: #d6d6d6; -} - -.viewcode-back { - font-family: sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} - -div.code-block-caption { - color: #efefef; - background-color: #1c4e63; -} \ No newline at end of file diff --git a/docs/_static/default.css b/docs/_static/default.css deleted file mode 100644 index 81b93636..00000000 --- a/docs/_static/default.css +++ /dev/null @@ -1 +0,0 @@ -@import url("classic.css"); diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js deleted file mode 100644 index d06a71d7..00000000 --- a/docs/_static/doctools.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Base JavaScript utilities for all Sphinx HTML documentation. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ -"use strict"; - -const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ - "TEXTAREA", - "INPUT", - "SELECT", - "BUTTON", -]); - -const _ready = (callback) => { - if (document.readyState !== "loading") { - callback(); - } else { - document.addEventListener("DOMContentLoaded", callback); - } -}; - -/** - * Small JavaScript module for the documentation. - */ -const Documentation = { - init: () => { - Documentation.initDomainIndexTable(); - Documentation.initOnKeyListeners(); - }, - - /** - * i18n support - */ - TRANSLATIONS: {}, - PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), - LOCALE: "unknown", - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext: (string) => { - const translated = Documentation.TRANSLATIONS[string]; - switch (typeof translated) { - case "undefined": - return string; // no translation - case "string": - return translated; // translation exists - default: - return translated[0]; // (singular, plural) translation tuple exists - } - }, - - ngettext: (singular, plural, n) => { - const translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated !== "undefined") - return translated[Documentation.PLURAL_EXPR(n)]; - return n === 1 ? singular : plural; - }, - - addTranslations: (catalog) => { - Object.assign(Documentation.TRANSLATIONS, catalog.messages); - Documentation.PLURAL_EXPR = new Function( - "n", - `return (${catalog.plural_expr})` - ); - Documentation.LOCALE = catalog.locale; - }, - - /** - * helper function to focus on search bar - */ - focusSearchBar: () => { - document.querySelectorAll("input[name=q]")[0]?.focus(); - }, - - /** - * Initialise the domain index toggle buttons - */ - initDomainIndexTable: () => { - const toggler = (el) => { - const idNumber = el.id.substr(7); - const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); - if (el.src.substr(-9) === "minus.png") { - el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; - toggledRows.forEach((el) => (el.style.display = "none")); - } else { - el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; - toggledRows.forEach((el) => (el.style.display = "")); - } - }; - - const togglerElements = document.querySelectorAll("img.toggler"); - togglerElements.forEach((el) => - el.addEventListener("click", (event) => toggler(event.currentTarget)) - ); - togglerElements.forEach((el) => (el.style.display = "")); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); - }, - - initOnKeyListeners: () => { - // only install a listener if it is really needed - if ( - !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && - !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS - ) - return; - - document.addEventListener("keydown", (event) => { - // bail for input elements - if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; - // bail with special keys - if (event.altKey || event.ctrlKey || event.metaKey) return; - - if (!event.shiftKey) { - switch (event.key) { - case "ArrowLeft": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const prevLink = document.querySelector('link[rel="prev"]'); - if (prevLink && prevLink.href) { - window.location.href = prevLink.href; - event.preventDefault(); - } - break; - case "ArrowRight": - if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; - - const nextLink = document.querySelector('link[rel="next"]'); - if (nextLink && nextLink.href) { - window.location.href = nextLink.href; - event.preventDefault(); - } - break; - } - } - - // some keyboard layouts may need Shift to get / - switch (event.key) { - case "/": - if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; - Documentation.focusSearchBar(); - event.preventDefault(); - } - }); - }, -}; - -// quick alias for translations -const _ = Documentation.gettext; - -_ready(Documentation.init); diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js deleted file mode 100644 index 9e67e77f..00000000 --- a/docs/_static/documentation_options.js +++ /dev/null @@ -1,14 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '2.0', - LANGUAGE: 'en', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false, - SHOW_SEARCH_SUMMARY: true, - ENABLE_SEARCH_SHORTCUTS: true, -}; \ No newline at end of file diff --git a/docs/_static/file.png b/docs/_static/file.png deleted file mode 100644 index a858a410e4faa62ce324d814e4b816fff83a6fb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( diff --git a/docs/_static/language_data.js b/docs/_static/language_data.js deleted file mode 100644 index 53c120fe..00000000 --- a/docs/_static/language_data.js +++ /dev/null @@ -1,199 +0,0 @@ -/* - * language_data.js - * ~~~~~~~~~~~~~~~~ - * - * This script contains the language-specific data used by searchtools.js, - * namely the list of stopwords, stemmer, scorer and splitter. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; - - -/* Non-minified version is copied as a separate JS file, is available */ - -/** - * Porter Stemmer - */ -var Stemmer = function() { - - var step2list = { - ational: 'ate', - tional: 'tion', - enci: 'ence', - anci: 'ance', - izer: 'ize', - bli: 'ble', - alli: 'al', - entli: 'ent', - eli: 'e', - ousli: 'ous', - ization: 'ize', - ation: 'ate', - ator: 'ate', - alism: 'al', - iveness: 'ive', - fulness: 'ful', - ousness: 'ous', - aliti: 'al', - iviti: 'ive', - biliti: 'ble', - logi: 'log' - }; - - var step3list = { - icate: 'ic', - ative: '', - alize: 'al', - iciti: 'ic', - ical: 'ic', - ful: '', - ness: '' - }; - - var c = "[^aeiou]"; // consonant - var v = "[aeiouy]"; // vowel - var C = c + "[^aeiouy]*"; // consonant sequence - var V = v + "[aeiou]*"; // vowel sequence - - var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 - var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 - var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 - var s_v = "^(" + C + ")?" + v; // vowel in stem - - this.stemWord = function (w) { - var stem; - var suffix; - var firstch; - var origword = w; - - if (w.length < 3) - return w; - - var re; - var re2; - var re3; - var re4; - - firstch = w.substr(0,1); - if (firstch == "y") - w = firstch.toUpperCase() + w.substr(1); - - // Step 1a - re = /^(.+?)(ss|i)es$/; - re2 = /^(.+?)([^s])s$/; - - if (re.test(w)) - w = w.replace(re,"$1$2"); - else if (re2.test(w)) - w = w.replace(re2,"$1$2"); - - // Step 1b - re = /^(.+?)eed$/; - re2 = /^(.+?)(ed|ing)$/; - if (re.test(w)) { - var fp = re.exec(w); - re = new RegExp(mgr0); - if (re.test(fp[1])) { - re = /.$/; - w = w.replace(re,""); - } - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1]; - re2 = new RegExp(s_v); - if (re2.test(stem)) { - w = stem; - re2 = /(at|bl|iz)$/; - re3 = new RegExp("([^aeiouylsz])\\1$"); - re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re2.test(w)) - w = w + "e"; - else if (re3.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - else if (re4.test(w)) - w = w + "e"; - } - } - - // Step 1c - re = /^(.+?)y$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(s_v); - if (re.test(stem)) - w = stem + "i"; - } - - // Step 2 - re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step2list[suffix]; - } - - // Step 3 - re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = new RegExp(mgr0); - if (re.test(stem)) - w = stem + step3list[suffix]; - } - - // Step 4 - re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; - re2 = /^(.+?)(s|t)(ion)$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - if (re.test(stem)) - w = stem; - } - else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1] + fp[2]; - re2 = new RegExp(mgr1); - if (re2.test(stem)) - w = stem; - } - - // Step 5 - re = /^(.+?)e$/; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = new RegExp(mgr1); - re2 = new RegExp(meq1); - re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) - w = stem; - } - re = /ll$/; - re2 = new RegExp(mgr1); - if (re.test(w) && re2.test(w)) { - re = /.$/; - w = w.replace(re,""); - } - - // and turn initial Y back to y - if (firstch == "y") - w = firstch.toLowerCase() + w.substr(1); - return w; - } -} - diff --git a/docs/_static/minus.png b/docs/_static/minus.png deleted file mode 100644 index d96755fdaf8bb2214971e0db9c1fd3077d7c419d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK diff --git a/docs/_static/plus.png b/docs/_static/plus.png deleted file mode 100644 index 7107cec93a979b9a5f64843235a16651d563ce2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz diff --git a/docs/_static/pygments.css b/docs/_static/pygments.css deleted file mode 100644 index bc569267..00000000 --- a/docs/_static/pygments.css +++ /dev/null @@ -1,74 +0,0 @@ -pre { line-height: 125%; } -td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.highlight .hll { background-color: #ffffcc } -.highlight { background: #eeffcc; } -.highlight .c { color: #408090; font-style: italic } /* Comment */ -.highlight .err { border: 1px solid #FF0000 } /* Error */ -.highlight .k { color: #007020; font-weight: bold } /* Keyword */ -.highlight .o { color: #666666 } /* Operator */ -.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #007020 } /* Comment.Preproc */ -.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ -.highlight .gd { color: #A00000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #333333 } /* Generic.Output */ -.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #0044DD } /* Generic.Traceback */ -.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #007020 } /* Keyword.Pseudo */ -.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #902000 } /* Keyword.Type */ -.highlight .m { color: #208050 } /* Literal.Number */ -.highlight .s { color: #4070a0 } /* Literal.String */ -.highlight .na { color: #4070a0 } /* Name.Attribute */ -.highlight .nb { color: #007020 } /* Name.Builtin */ -.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ -.highlight .no { color: #60add5 } /* Name.Constant */ -.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ -.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #007020 } /* Name.Exception */ -.highlight .nf { color: #06287e } /* Name.Function */ -.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ -.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #bb60d5 } /* Name.Variable */ -.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mb { color: #208050 } /* Literal.Number.Bin */ -.highlight .mf { color: #208050 } /* Literal.Number.Float */ -.highlight .mh { color: #208050 } /* Literal.Number.Hex */ -.highlight .mi { color: #208050 } /* Literal.Number.Integer */ -.highlight .mo { color: #208050 } /* Literal.Number.Oct */ -.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ -.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ -.highlight .sc { color: #4070a0 } /* Literal.String.Char */ -.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ -.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ -.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ -.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ -.highlight .sx { color: #c65d09 } /* Literal.String.Other */ -.highlight .sr { color: #235388 } /* Literal.String.Regex */ -.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ -.highlight .ss { color: #517918 } /* Literal.String.Symbol */ -.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #06287e } /* Name.Function.Magic */ -.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ -.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ -.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ -.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ -.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/_static/searchtools.js b/docs/_static/searchtools.js deleted file mode 100644 index 97d56a74..00000000 --- a/docs/_static/searchtools.js +++ /dev/null @@ -1,566 +0,0 @@ -/* - * searchtools.js - * ~~~~~~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for the full-text search. - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ -"use strict"; - -/** - * Simple result scoring code. - */ -if (typeof Scorer === "undefined") { - var Scorer = { - // Implement the following function to further tweak the score for each result - // The function takes a result array [docname, title, anchor, descr, score, filename] - // and returns the new score. - /* - score: result => { - const [docname, title, anchor, descr, score, filename] = result - return score - }, - */ - - // query matches the full name of an object - objNameMatch: 11, - // or matches in the last dotted part of the object name - objPartialMatch: 6, - // Additive scores depending on the priority of the object - objPrio: { - 0: 15, // used to be importantResults - 1: 5, // used to be objectResults - 2: -5, // used to be unimportantResults - }, - // Used when the priority is not in the mapping. - objPrioDefault: 0, - - // query found in title - title: 15, - partialTitle: 7, - // query found in terms - term: 5, - partialTerm: 2, - }; -} - -const _removeChildren = (element) => { - while (element && element.lastChild) element.removeChild(element.lastChild); -}; - -/** - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping - */ -const _escapeRegExp = (string) => - string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string - -const _displayItem = (item, searchTerms) => { - const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; - const docUrlRoot = DOCUMENTATION_OPTIONS.URL_ROOT; - const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; - const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; - const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; - - const [docName, title, anchor, descr, score, _filename] = item; - - let listItem = document.createElement("li"); - let requestUrl; - let linkUrl; - if (docBuilder === "dirhtml") { - // dirhtml builder - let dirname = docName + "/"; - if (dirname.match(/\/index\/$/)) - dirname = dirname.substring(0, dirname.length - 6); - else if (dirname === "index/") dirname = ""; - requestUrl = docUrlRoot + dirname; - linkUrl = requestUrl; - } else { - // normal html builders - requestUrl = docUrlRoot + docName + docFileSuffix; - linkUrl = docName + docLinkSuffix; - } - let linkEl = listItem.appendChild(document.createElement("a")); - linkEl.href = linkUrl + anchor; - linkEl.dataset.score = score; - linkEl.innerHTML = title; - if (descr) - listItem.appendChild(document.createElement("span")).innerHTML = - " (" + descr + ")"; - else if (showSearchSummary) - fetch(requestUrl) - .then((responseData) => responseData.text()) - .then((data) => { - if (data) - listItem.appendChild( - Search.makeSearchSummary(data, searchTerms) - ); - }); - Search.output.appendChild(listItem); -}; -const _finishSearch = (resultCount) => { - Search.stopPulse(); - Search.title.innerText = _("Search Results"); - if (!resultCount) - Search.status.innerText = Documentation.gettext( - "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." - ); - else - Search.status.innerText = _( - `Search finished, found ${resultCount} page(s) matching the search query.` - ); -}; -const _displayNextItem = ( - results, - resultCount, - searchTerms -) => { - // results left, load the summary and display it - // this is intended to be dynamic (don't sub resultsCount) - if (results.length) { - _displayItem(results.pop(), searchTerms); - setTimeout( - () => _displayNextItem(results, resultCount, searchTerms), - 5 - ); - } - // search finished, update title and status message - else _finishSearch(resultCount); -}; - -/** - * Default splitQuery function. Can be overridden in ``sphinx.search`` with a - * custom function per language. - * - * The regular expression works by splitting the string on consecutive characters - * that are not Unicode letters, numbers, underscores, or emoji characters. - * This is the same as ``\W+`` in Python, preserving the surrogate pair area. - */ -if (typeof splitQuery === "undefined") { - var splitQuery = (query) => query - .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) - .filter(term => term) // remove remaining empty strings -} - -/** - * Search Module - */ -const Search = { - _index: null, - _queued_query: null, - _pulse_status: -1, - - htmlToText: (htmlString) => { - const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); - htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); - const docContent = htmlElement.querySelector('[role="main"]'); - if (docContent !== undefined) return docContent.textContent; - console.warn( - "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." - ); - return ""; - }, - - init: () => { - const query = new URLSearchParams(window.location.search).get("q"); - document - .querySelectorAll('input[name="q"]') - .forEach((el) => (el.value = query)); - if (query) Search.performSearch(query); - }, - - loadIndex: (url) => - (document.body.appendChild(document.createElement("script")).src = url), - - setIndex: (index) => { - Search._index = index; - if (Search._queued_query !== null) { - const query = Search._queued_query; - Search._queued_query = null; - Search.query(query); - } - }, - - hasIndex: () => Search._index !== null, - - deferQuery: (query) => (Search._queued_query = query), - - stopPulse: () => (Search._pulse_status = -1), - - startPulse: () => { - if (Search._pulse_status >= 0) return; - - const pulse = () => { - Search._pulse_status = (Search._pulse_status + 1) % 4; - Search.dots.innerText = ".".repeat(Search._pulse_status); - if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); - }; - pulse(); - }, - - /** - * perform a search for something (or wait until index is loaded) - */ - performSearch: (query) => { - // create the required interface elements - const searchText = document.createElement("h2"); - searchText.textContent = _("Searching"); - const searchSummary = document.createElement("p"); - searchSummary.classList.add("search-summary"); - searchSummary.innerText = ""; - const searchList = document.createElement("ul"); - searchList.classList.add("search"); - - const out = document.getElementById("search-results"); - Search.title = out.appendChild(searchText); - Search.dots = Search.title.appendChild(document.createElement("span")); - Search.status = out.appendChild(searchSummary); - Search.output = out.appendChild(searchList); - - const searchProgress = document.getElementById("search-progress"); - // Some themes don't use the search progress node - if (searchProgress) { - searchProgress.innerText = _("Preparing search..."); - } - Search.startPulse(); - - // index already loaded, the browser was quick! - if (Search.hasIndex()) Search.query(query); - else Search.deferQuery(query); - }, - - /** - * execute search (requires search index to be loaded) - */ - query: (query) => { - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const titles = Search._index.titles; - const allTitles = Search._index.alltitles; - const indexEntries = Search._index.indexentries; - - // stem the search terms and add them to the correct list - const stemmer = new Stemmer(); - const searchTerms = new Set(); - const excludedTerms = new Set(); - const highlightTerms = new Set(); - const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); - splitQuery(query.trim()).forEach((queryTerm) => { - const queryTermLower = queryTerm.toLowerCase(); - - // maybe skip this "word" - // stopwords array is from language_data.js - if ( - stopwords.indexOf(queryTermLower) !== -1 || - queryTerm.match(/^\d+$/) - ) - return; - - // stem the word - let word = stemmer.stemWord(queryTermLower); - // select the correct list - if (word[0] === "-") excludedTerms.add(word.substr(1)); - else { - searchTerms.add(word); - highlightTerms.add(queryTermLower); - } - }); - - if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js - localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) - } - - // console.debug("SEARCH: searching for:"); - // console.info("required: ", [...searchTerms]); - // console.info("excluded: ", [...excludedTerms]); - - // array of [docname, title, anchor, descr, score, filename] - let results = []; - _removeChildren(document.getElementById("search-progress")); - - const queryLower = query.toLowerCase(); - for (const [title, foundTitles] of Object.entries(allTitles)) { - if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { - for (const [file, id] of foundTitles) { - let score = Math.round(100 * queryLower.length / title.length) - results.push([ - docNames[file], - titles[file] !== title ? `${titles[file]} > ${title}` : title, - id !== null ? "#" + id : "", - null, - score, - filenames[file], - ]); - } - } - } - - // search for explicit entries in index directives - for (const [entry, foundEntries] of Object.entries(indexEntries)) { - if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { - for (const [file, id] of foundEntries) { - let score = Math.round(100 * queryLower.length / entry.length) - results.push([ - docNames[file], - titles[file], - id ? "#" + id : "", - null, - score, - filenames[file], - ]); - } - } - } - - // lookup as object - objectTerms.forEach((term) => - results.push(...Search.performObjectSearch(term, objectTerms)) - ); - - // lookup as search terms in fulltext - results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); - - // let the scorer override scores with a custom scoring function - if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); - - // now sort the results by score (in opposite order of appearance, since the - // display function below uses pop() to retrieve items) and then - // alphabetically - results.sort((a, b) => { - const leftScore = a[4]; - const rightScore = b[4]; - if (leftScore === rightScore) { - // same score: sort alphabetically - const leftTitle = a[1].toLowerCase(); - const rightTitle = b[1].toLowerCase(); - if (leftTitle === rightTitle) return 0; - return leftTitle > rightTitle ? -1 : 1; // inverted is intentional - } - return leftScore > rightScore ? 1 : -1; - }); - - // remove duplicate search results - // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept - let seen = new Set(); - results = results.reverse().reduce((acc, result) => { - let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); - if (!seen.has(resultStr)) { - acc.push(result); - seen.add(resultStr); - } - return acc; - }, []); - - results = results.reverse(); - - // for debugging - //Search.lastresults = results.slice(); // a copy - // console.info("search results:", Search.lastresults); - - // print the results - _displayNextItem(results, results.length, searchTerms); - }, - - /** - * search for object names - */ - performObjectSearch: (object, objectTerms) => { - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const objects = Search._index.objects; - const objNames = Search._index.objnames; - const titles = Search._index.titles; - - const results = []; - - const objectSearchCallback = (prefix, match) => { - const name = match[4] - const fullname = (prefix ? prefix + "." : "") + name; - const fullnameLower = fullname.toLowerCase(); - if (fullnameLower.indexOf(object) < 0) return; - - let score = 0; - const parts = fullnameLower.split("."); - - // check for different match types: exact matches of full name or - // "last name" (i.e. last dotted part) - if (fullnameLower === object || parts.slice(-1)[0] === object) - score += Scorer.objNameMatch; - else if (parts.slice(-1)[0].indexOf(object) > -1) - score += Scorer.objPartialMatch; // matches in last name - - const objName = objNames[match[1]][2]; - const title = titles[match[0]]; - - // If more than one term searched for, we require other words to be - // found in the name/title/description - const otherTerms = new Set(objectTerms); - otherTerms.delete(object); - if (otherTerms.size > 0) { - const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); - if ( - [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) - ) - return; - } - - let anchor = match[3]; - if (anchor === "") anchor = fullname; - else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; - - const descr = objName + _(", in ") + title; - - // add custom score for some objects according to scorer - if (Scorer.objPrio.hasOwnProperty(match[2])) - score += Scorer.objPrio[match[2]]; - else score += Scorer.objPrioDefault; - - results.push([ - docNames[match[0]], - fullname, - "#" + anchor, - descr, - score, - filenames[match[0]], - ]); - }; - Object.keys(objects).forEach((prefix) => - objects[prefix].forEach((array) => - objectSearchCallback(prefix, array) - ) - ); - return results; - }, - - /** - * search for full-text terms in the index - */ - performTermsSearch: (searchTerms, excludedTerms) => { - // prepare search - const terms = Search._index.terms; - const titleTerms = Search._index.titleterms; - const filenames = Search._index.filenames; - const docNames = Search._index.docnames; - const titles = Search._index.titles; - - const scoreMap = new Map(); - const fileMap = new Map(); - - // perform the search on the required terms - searchTerms.forEach((word) => { - const files = []; - const arr = [ - { files: terms[word], score: Scorer.term }, - { files: titleTerms[word], score: Scorer.title }, - ]; - // add support for partial matches - if (word.length > 2) { - const escapedWord = _escapeRegExp(word); - Object.keys(terms).forEach((term) => { - if (term.match(escapedWord) && !terms[word]) - arr.push({ files: terms[term], score: Scorer.partialTerm }); - }); - Object.keys(titleTerms).forEach((term) => { - if (term.match(escapedWord) && !titleTerms[word]) - arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); - }); - } - - // no match but word was a required one - if (arr.every((record) => record.files === undefined)) return; - - // found search word in contents - arr.forEach((record) => { - if (record.files === undefined) return; - - let recordFiles = record.files; - if (recordFiles.length === undefined) recordFiles = [recordFiles]; - files.push(...recordFiles); - - // set score for the word in each file - recordFiles.forEach((file) => { - if (!scoreMap.has(file)) scoreMap.set(file, {}); - scoreMap.get(file)[word] = record.score; - }); - }); - - // create the mapping - files.forEach((file) => { - if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) - fileMap.get(file).push(word); - else fileMap.set(file, [word]); - }); - }); - - // now check if the files don't contain excluded terms - const results = []; - for (const [file, wordList] of fileMap) { - // check if all requirements are matched - - // as search terms with length < 3 are discarded - const filteredTermCount = [...searchTerms].filter( - (term) => term.length > 2 - ).length; - if ( - wordList.length !== searchTerms.size && - wordList.length !== filteredTermCount - ) - continue; - - // ensure that none of the excluded terms is in the search result - if ( - [...excludedTerms].some( - (term) => - terms[term] === file || - titleTerms[term] === file || - (terms[term] || []).includes(file) || - (titleTerms[term] || []).includes(file) - ) - ) - break; - - // select one (max) score for the file. - const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); - // add result to the result list - results.push([ - docNames[file], - titles[file], - "", - null, - score, - filenames[file], - ]); - } - return results; - }, - - /** - * helper function to return a node containing the - * search summary for a given text. keywords is a list - * of stemmed words. - */ - makeSearchSummary: (htmlText, keywords) => { - const text = Search.htmlToText(htmlText); - if (text === "") return null; - - const textLower = text.toLowerCase(); - const actualStartPosition = [...keywords] - .map((k) => textLower.indexOf(k.toLowerCase())) - .filter((i) => i > -1) - .slice(-1)[0]; - const startWithContext = Math.max(actualStartPosition - 120, 0); - - const top = startWithContext === 0 ? "" : "..."; - const tail = startWithContext + 240 < text.length ? "..." : ""; - - let summary = document.createElement("p"); - summary.classList.add("context"); - summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; - - return summary; - }, -}; - -_ready(Search.init); diff --git a/docs/_static/sidebar.js b/docs/_static/sidebar.js deleted file mode 100644 index 04e83376..00000000 --- a/docs/_static/sidebar.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * sidebar.js - * ~~~~~~~~~~ - * - * This script makes the Sphinx sidebar collapsible. - * - * .sphinxsidebar contains .sphinxsidebarwrapper. This script adds - * in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton - * used to collapse and expand the sidebar. - * - * When the sidebar is collapsed the .sphinxsidebarwrapper is hidden - * and the width of the sidebar and the margin-left of the document - * are decreased. When the sidebar is expanded the opposite happens. - * This script saves a per-browser/per-session cookie used to - * remember the position of the sidebar among the pages. - * Once the browser is closed the cookie is deleted and the position - * reset to the default (expanded). - * - * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -const initialiseSidebar = () => { - - - - - // global elements used by the functions. - const bodyWrapper = document.getElementsByClassName("bodywrapper")[0] - const sidebar = document.getElementsByClassName("sphinxsidebar")[0] - const sidebarWrapper = document.getElementsByClassName('sphinxsidebarwrapper')[0] - const sidebarButton = document.getElementById("sidebarbutton") - const sidebarArrow = sidebarButton.querySelector('span') - - // for some reason, the document has no sidebar; do not run into errors - if (typeof sidebar === "undefined") return; - - const flipArrow = element => element.innerText = (element.innerText === "»") ? "«" : "»" - - const collapse_sidebar = () => { - bodyWrapper.style.marginLeft = ".8em"; - sidebar.style.width = ".8em" - sidebarWrapper.style.display = "none" - flipArrow(sidebarArrow) - sidebarButton.title = _('Expand sidebar') - window.localStorage.setItem("sidebar", "collapsed") - } - - const expand_sidebar = () => { - bodyWrapper.style.marginLeft = "" - sidebar.style.removeProperty("width") - sidebarWrapper.style.display = "" - flipArrow(sidebarArrow) - sidebarButton.title = _('Collapse sidebar') - window.localStorage.setItem("sidebar", "expanded") - } - - sidebarButton.addEventListener("click", () => { - (sidebarWrapper.style.display === "none") ? expand_sidebar() : collapse_sidebar() - }) - - if (!window.localStorage.getItem("sidebar")) return - const value = window.localStorage.getItem("sidebar") - if (value === "collapsed") collapse_sidebar(); - else if (value === "expanded") expand_sidebar(); -} - -if (document.readyState !== "loading") initialiseSidebar() -else document.addEventListener("DOMContentLoaded", initialiseSidebar) \ No newline at end of file diff --git a/docs/_static/sphinx_highlight.js b/docs/_static/sphinx_highlight.js deleted file mode 100644 index aae669d7..00000000 --- a/docs/_static/sphinx_highlight.js +++ /dev/null @@ -1,144 +0,0 @@ -/* Highlighting utilities for Sphinx HTML documentation. */ -"use strict"; - -const SPHINX_HIGHLIGHT_ENABLED = true - -/** - * highlight a given string on a node by wrapping it in - * span elements with the given class name. - */ -const _highlight = (node, addItems, text, className) => { - if (node.nodeType === Node.TEXT_NODE) { - const val = node.nodeValue; - const parent = node.parentNode; - const pos = val.toLowerCase().indexOf(text); - if ( - pos >= 0 && - !parent.classList.contains(className) && - !parent.classList.contains("nohighlight") - ) { - let span; - - const closestNode = parent.closest("body, svg, foreignObject"); - const isInSVG = closestNode && closestNode.matches("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.classList.add(className); - } - - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - parent.insertBefore( - span, - parent.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling - ) - ); - node.nodeValue = val.substr(0, pos); - - if (isInSVG) { - const rect = document.createElementNS( - "http://www.w3.org/2000/svg", - "rect" - ); - const bbox = parent.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute("class", className); - addItems.push({ parent: parent, target: rect }); - } - } - } else if (node.matches && !node.matches("button, select, textarea")) { - node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); - } -}; -const _highlightText = (thisNode, text, className) => { - let addItems = []; - _highlight(thisNode, addItems, text, className); - addItems.forEach((obj) => - obj.parent.insertAdjacentElement("beforebegin", obj.target) - ); -}; - -/** - * Small JavaScript module for the documentation. - */ -const SphinxHighlight = { - - /** - * highlight the search words provided in localstorage in the text - */ - highlightSearchWords: () => { - if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight - - // get and clear terms from localstorage - const url = new URL(window.location); - const highlight = - localStorage.getItem("sphinx_highlight_terms") - || url.searchParams.get("highlight") - || ""; - localStorage.removeItem("sphinx_highlight_terms") - url.searchParams.delete("highlight"); - window.history.replaceState({}, "", url); - - // get individual terms from highlight string - const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); - if (terms.length === 0) return; // nothing to do - - // There should never be more than one element matching "div.body" - const divBody = document.querySelectorAll("div.body"); - const body = divBody.length ? divBody[0] : document.querySelector("body"); - window.setTimeout(() => { - terms.forEach((term) => _highlightText(body, term, "highlighted")); - }, 10); - - const searchBox = document.getElementById("searchbox"); - if (searchBox === null) return; - searchBox.appendChild( - document - .createRange() - .createContextualFragment( - '" - ) - ); - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords: () => { - document - .querySelectorAll("#searchbox .highlight-link") - .forEach((el) => el.remove()); - document - .querySelectorAll("span.highlighted") - .forEach((el) => el.classList.remove("highlighted")); - localStorage.removeItem("sphinx_highlight_terms") - }, - - initEscapeListener: () => { - // only install a listener if it is really needed - if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; - - document.addEventListener("keydown", (event) => { - // bail for input elements - if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; - // bail with special keys - if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; - if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { - SphinxHighlight.hideSearchWords(); - event.preventDefault(); - } - }); - }, -}; - -_ready(SphinxHighlight.highlightSearchWords); -_ready(SphinxHighlight.initEscapeListener); From d0ef32012cb8942ddbd622e8ce9dc510db833d99 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:10:53 +0100 Subject: [PATCH 08/18] Delete docs/_sources directory --- docs/_sources/index.rst.txt | 492 ------------------------------------ 1 file changed, 492 deletions(-) delete mode 100644 docs/_sources/index.rst.txt diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt deleted file mode 100644 index a2e28a2b..00000000 --- a/docs/_sources/index.rst.txt +++ /dev/null @@ -1,492 +0,0 @@ -.. image:: images/spotify-web-api-doc.jpg - :width: 100 % - -Welcome to Spotipy! -=================================== - -*Spotipy* is a lightweight Python library for the `Spotify Web API -`_. With *Spotipy* -you get full access to all of the music data provided by the Spotify platform. - -Assuming you set the ``SPOTIPY_CLIENT_ID`` and ``SPOTIPY_CLIENT_SECRET`` -environment variables (here is a `video `_ explaining how to do so). For a longer tutorial with examples included, refer to this `video playlist `_. Below is a quick example of using *Spotipy* to list the -names of all the albums released by the artist 'Birdy':: - - import spotipy - from spotipy.oauth2 import SpotifyClientCredentials - - birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP' - spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) - - results = spotify.artist_albums(birdy_uri, album_type='album') - albums = results['items'] - while results['next']: - results = spotify.next(results) - albums.extend(results['items']) - - for album in albums: - print(album['name']) - -Here's another example showing how to get 30 second samples and cover art -for the top 10 tracks for Led Zeppelin:: - - import spotipy - from spotipy.oauth2 import SpotifyClientCredentials - - lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp' - - spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials()) - results = spotify.artist_top_tracks(lz_uri) - - for track in results['tracks'][:10]: - print('track : ' + track['name']) - print('audio : ' + track['preview_url']) - print('cover art: ' + track['album']['images'][0]['url']) - print() - -Finally, here's an example that will get the URL for an artist image given the -artist's name:: - - import spotipy - import sys - from spotipy.oauth2 import SpotifyClientCredentials - - spotify = spotipy.Spotify(auth_manager=SpotifyClientCredentials()) - - if len(sys.argv) > 1: - name = ' '.join(sys.argv[1:]) - else: - name = 'Radiohead' - - results = spotify.search(q='artist:' + name, type='artist') - items = results['artists']['items'] - if len(items) > 0: - artist = items[0] - print(artist['name'], artist['images'][0]['url']) - - -Features -======== - -*Spotipy* supports all of the features of the Spotify Web API including access -to all end points, and support for user authorization. For details on the -capabilities you are encouraged to review the `Spotify Web -API `_ documentation. - -Installation -============ - -**Installing Spotipy on Windows**: - -- Install Python: Download and install Python from the official Python website (https://www.python.org/downloads/). - -- Install Spotipy: Open a command prompt and run pip install spotipy. -Open command prompt and run the following:: - - pip install spotipy - -- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. - -**Installing Spotipy on macOS**: - - -- Install Homebrew: Install Homebrew, a package manager for macOS. - -- Run the followng command:: - - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - -- Install Python: Run brew install python in the terminal:: - - brew install python - -- Install Spotipy: Run pip install spotipy in the terminal:: - - pip install spotipy - -- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. - -**Installing Spotipy on Linux**: - -- Install Python: Use your Linux distribution's package manager to install Python using the following command:: - - sudo apt-get install python3 - -- Install pip: Use your Linux distribution's package manager to install pip using the command:: - - sudo apt-get install python3-pip - -- Install Spotipy: Run pip install spotipy in the terminal. - - pip install spotipy - -- Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID and client secret. - - - .. Install or upgrade *Spotipy* with:: - - pip install spotipy --upgrade - -You can get the source from github at https://github.com/plamere/spotipy - -Getting Started with Spotipy -=============== - -Before you can use Spotipy, there are a few things you need to do: - -Register your app: To make authorized calls to the Spotify Web API, you need to register your app and obtain a client ID and client secret. You can register your app at My Dashboard _. Make sure to keep your client ID and client secret secure. - -Choose an authorization flow: Spotipy supports two authorization flows: the Authorization Code flow and the Client Credentials flow. Choose the one that's suitable for your application. - - **Authorization Code flow** This method is suitable for long-running applications - which the user logs into once. It provides an access token that can be refreshed. - - .. note:: This method requires you to add a redirect URI to your application at - `My Dashboard `_. - See `Redirect URI`_ for more details. - - - **The Client Credentials flow** This is suitable for short-lived applications that don't require user permission. It makes it possible to authenticate your requests to the Spotify Web API and to obtain a higher rate limit than you would with the Authorization Code flow. - -Before you can use Spotipy's methods, you need to authorize your app by registering it at My Dashboard _. This will give you a *client id* and *client secret* that you'll need to use in your code. - - -Authorization Code Flow -======================= - -This flow is suitable for long-running applications in which the user grants -permission only once. It provides an access token that can be refreshed. -Since the token exchange involves sending your secret key, perform this on a -secure location, like a backend service, and not from a client such as a -browser or from a mobile app. - -Quick start ------------ - -To support the **Client Authorization Code Flow** *Spotipy* provides a -class SpotifyOAuth that can be used to authenticate requests like so:: - - import spotipy - from spotipy.oauth2 import SpotifyOAuth - - scope = "user-library-read" - - sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope)) - - results = sp.current_user_saved_tracks() - for idx, item in enumerate(results['items']): - track = item['track'] - print(idx, track['artists'][0]['name'], " – ", track['name']) - -or if you are reluctant to immortalize your app credentials in your source code, -you can set environment variables like so (use ``$env:"credentials"`` instead of ``export`` -on Windows):: - - export SPOTIPY_CLIENT_ID='your-spotify-client-id' - export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret' - export SPOTIPY_REDIRECT_URI='your-app-redirect-url' - -Scopes ------- - -See `Using -Scopes `_ for information -about scopes. - -Redirect URI ------------- - -The **Authorization Code Flow** needs you to add a **redirect URI** -to your application at -`My Dashboard `_ -(navigate to your application and then *[Edit Settings]*). - -The ``redirect_uri`` argument or ``SPOTIPY_REDIRECT_URI`` environment variable -must match the redirect URI added to your application in your Dashboard. -The redirect URI can be any valid URI (it does not need to be accessible) -such as ``http://example.com``, ``http://localhost`` or ``http://127.0.0.1:9090``. - - .. note:: If you choose an `http`-scheme URL, and it's for `localhost` or - 127.0.0.1`, **AND** it specifies a port, then spotipy will instantiate - a server on the indicated response to receive the access token from the - response at the end of the oauth flow [see the code](https://github.com/plamere/spotipy/blob/master/spotipy/oauth2.py#L483-L490). - - -Client Credentials Flow -======================= - -The Client Credentials flow is used in server-to-server authentication. Only -endpoints that do not access user information can be accessed. The advantage here -in comparison with requests to the Web API made without an access token, -is that a higher rate limit is applied. - -As opposed to the Authorization Code Flow, you will not need to set ``SPOTIPY_REDIRECT_URI``, -which means you will never be redirected to the sign in page in your browser:: - - export SPOTIPY_CLIENT_ID='your-spotify-client-id' - export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret' - -To support the **Client Credentials Flow** *Spotipy* provides a -class SpotifyClientCredentials that can be used to authenticate requests like so:: - - - import spotipy - from spotipy.oauth2 import SpotifyClientCredentials - - auth_manager = SpotifyClientCredentials() - sp = spotipy.Spotify(auth_manager=auth_manager) - - playlists = sp.user_playlists('spotify') - while playlists: - for i, playlist in enumerate(playlists['items']): - print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'], playlist['name'])) - if playlists['next']: - playlists = sp.next(playlists) - else: - playlists = None - - -IDs URIs and URLs -================= - -*Spotipy* supports a number of different ID types: - - - **Spotify URI** - The resource identifier that you can enter, for example, in - the Spotify Desktop client's search box to locate an artist, album, or - track. Example: ``spotify:track:6rqhFgbbKwnb9MLmUQDhG6`` - - **Spotify URL** - An HTML link that opens a track, album, app, playlist or other - Spotify resource in a Spotify client. Example: - ``http://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6`` - - **Spotify ID** - A base-62 number that you can find at the end of the Spotify - URI (see above) for an artist, track, album, etc. Example: - ``6rqhFgbbKwnb9MLmUQDhG6`` - -In general, any *Spotipy* method that needs an artist, album, track or playlist ID -will accept ids in any of the above form - - -Customized token caching -======================== - -Tokens are refreshed automatically and stored by default in the project main folder. -As this might not suit everyone's needs, spotipy provides a way to create customized -cache handlers. - -https://github.com/plamere/spotipy/blob/master/spotipy/cache_handler.py - -The custom cache handler would need to be a class that inherits from the base -cache handler ``CacheHandler``. The default cache handler ``CacheFileHandler`` is a good example. -An instance of that new class can then be passed as a parameter when -creating ``SpotifyOAuth``, ``SpotifyPKCE`` or ``SpotifyImplicitGrant``. -The following handlers are available and defined in the URL above. - - ``CacheFileHandler`` - - ``MemoryCacheHandler`` - - ``DjangoSessionCacheHandler`` - - ``FlaskSessionCacheHandler`` - - ``RedisCacheHandler`` - -Feel free to contribute new cache handlers to the repo. - -User Guide -======================= - -In this section, we'll provide a step-by-step tutorial for using some of Spotipy's essential features, such as retrieving user data, and searching for music. - -**Retrieving User Data** - - Import the Spotipy module in your Python code:: - - import spotipy - - - Create a Spotipy object with authentication manager:: - - from spotipy.oauth2 import SpotifyOAuth - - sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id='', - client_secret='', - redirect_uri='')) - - Use the sp.current_user() method to retrieve the authenticated user's data:: - - user_data = sp.current_user() - - - Access various pieces of user data from the user_data dictionary, such as the user's display name:: - - display_name = user_data['display_name'] - -**Searching for Music** - - Use the sp.search() method to search for a track, artist, album or playlist:: - - results = sp.search(q='chocolate', type='track') - - - The results variable contains a dictionary with search results. You can access the list of tracks returned by the search by accessing results['tracks']['items']. - - - Each item in the list of tracks is a dictionary containing information about the track. For example, you can retrieve the track name using track_name = results['tracks']['items'][0]['name']. - - - -Examples -======================= - -There are many more examples of how to use *Spotipy* in the `Examples -Directory `_ on Github - -API Reference -============== - -:mod:`client` Module -======================= - -.. automodule:: spotipy.client - :members: - :undoc-members: - :special-members: __init__ - :show-inheritance: - -:mod:`oauth2` Module -======================= - -.. automodule:: spotipy.oauth2 - :members: - :undoc-members: - :special-members: __init__ - :show-inheritance: - -:mod:`util` Module --------------------- - -.. automodule:: spotipy.util - :members: - :undoc-members: - :special-members: __init__ - :show-inheritance: - - -Support -======= -You can ask questions about Spotipy on Stack Overflow. Don’t forget to add the -*Spotipy* tag, and any other relevant tags as well, before posting. - - http://stackoverflow.com/questions/ask - -If you think you've found a bug, let us know at -`Spotify Issues `_ - - -Troubleshooting -======= - -This section aims to address common issues that users may encounter while working with Spotipy and provide practical solutions to resolve them. - -**Authentication errors**: Make sure that you have correctly set up your credentials and are using the correct authorization flow to avoid authenthication erros. Ensure that your client ID and client secret are correct and that you have added the appropriate redirect URIs to your Spotify Developer Dashboard. - -**Playlist creation errors**: If you're having trouble creating a playlist, check that your user ID is correct, and that the user has the necessary permissions to create playlists. Additionally, make sure that your code is formatted correctly, along with the fact that you are sending the appropriate request to the Spotify API. - -**Search errors**: If you're having problems when searching for music, make sure that you are providing the correct search query parameters. You should also check the Spotify API documentation to ensure that the endpoint you're using supports the search parameters you are providing. - -**API changes**: Sometimes the Spotify API may change, causing errors in your application. To fix this, check the Spotify API documentation to see if there are any changes that may affect your code and update it accordingly. - -**Rate limiting**: Making too many requests to the Spotify API within a short period of time, will result in you hitting the rate limit. To prevent this, use caching and backoff mechanisms in your code - -**Authorization errors**: If you encounter authorization errors, make sure that you have correctly set up your credentials and are using the correct authorization flow. You may also need to check if your access token has expired and obtain a new one if necessary. - -Contribute -========== - -Spotipy authored by Paul Lamere (plamere) with contributions by: - - - Daniel Beaudry (`danbeaudry on Github `_) - - Faruk Emre Sahin (`fsahin on Github `_) - - George (`rogueleaderr on Github `_) - - Henry Greville (`sethaurus on Github `_) - - Hugo van Kemanade (`hugovk on Github `_) - - José Manuel Pérez (`JMPerez on Github `_) - - Lucas Nunno (`lnunno on Github `_) - - Lynn Root (`econchick on Github `_) - - Matt Dennewitz (`mattdennewitz on Github `_) - - Matthew Duck (`mattduck on Github `_) - - Michael Thelin (`thelinmichael on Github `_) - - Ryan Choi (`ryankicks on Github `_) - - Simon Metson (`drsm79 on Github `_) - - Steve Winton (`swinton on Github `_) - - Tim Balzer (`timbalzer on Github `_) - - `corycorycory on Github `_ - - Nathan Coleman (`nathancoleman on Github `_) - - Michael Birtwell (`mbirtwell on Github `_) - - Harrison Hayes (`Harrison97 on Github `_) - - Stephane Bruckert (`stephanebruckert on Github `_) - - Ritiek Malhotra (`ritiek on Github `_) - -If you are a developer with Python experience, and you would like to contribute to Spotipy, please -be sure to follow the guidelines listed below: - -Export the needed Environment variables::: - export SPOTIPY_CLIENT_ID=client_id_here - export SPOTIPY_CLIENT_SECRET=client_secret_here - export SPOTIPY_CLIENT_USERNAME=client_username_here # This is actually an id not spotify display name - export SPOTIPY_REDIRECT_URI=http://localhost:8080 # Make url is set in app you created to get your ID and SECRET - -Create virtual environment, install dependencies, run tests::: - $ virtualenv --python=python3.7 env - (env) $ pip install --user -e . - (env) $ python -m unittest discover -v tests - -**Lint** - -To automatically fix the code style::: - pip install autopep8 - autopep8 --in-place --aggressive --recursive . - -To verify the code style::: - pip install flake8 - flake8 . - -To make sure if the import lists are stored correctly::: - pip install isort - isort . -c -v - -**Publishing (by maintainer)** - -- Bump version in setup.py -- Bump and date changelog -- Add to changelog: -:: - ## Unreleased - - // Add your changes here and then delete this line -- Commit changes -- Package to pypi: -:: - python setup.py sdist bdist_wheel - python3 setup.py sdist bdist_wheel - twine check dist/* - twine upload --repository-url https://upload.pypi.org/legacy/ --skip-existing dist/*.(whl|gz|zip)~dist/*linux*.whl -- Create github release https://github.com/plamere/spotipy/releases with the changelog content for the version and a short name that describes the main addition -- Build the documentation again to ensure it's on the latest version - -**Changelog** - -Don't forget to add a short description of your change in the `CHANGELOG `_! - - - -License -======= -(Taken from https://github.com/plamere/spotipy/blob/master/LICENSE.md):: - - MIT License - Copyright (c) 2021 Paul Lamere - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - From 7c9984789d8f14518898cbfafb3868a3ae5cb2ac Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:11:13 +0100 Subject: [PATCH 09/18] Delete genindex.html --- docs/genindex.html | 596 --------------------------------------------- 1 file changed, 596 deletions(-) delete mode 100644 docs/genindex.html diff --git a/docs/genindex.html b/docs/genindex.html deleted file mode 100644 index 498e4421..00000000 --- a/docs/genindex.html +++ /dev/null @@ -1,596 +0,0 @@ - - - - - - - Index — spotipy 2.0 documentation - - - - - - - - - - - - -
-
-
-
- - -

Index

- -
- _ - | A - | C - | D - | E - | F - | G - | M - | N - | O - | P - | Q - | R - | S - | T - | U - | V - -
-

_

- - -
- -

A

- - - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - - -
- -

F

- - -
- -

G

- - - -
- -

M

- - -
- -

N

- - - -
- -

O

- - - -
- -

P

- - - -
- -

Q

- - -
- -

R

- - - -
- -

S

- - - -
- -

T

- - - -
- -

U

- - - -
- -

V

- - - -
- - - -
-
-
-
- -
-
- - - - \ No newline at end of file From 53372a838d9595c8a5e4660e0bbed8699bd41af9 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:11:33 +0100 Subject: [PATCH 10/18] Delete index.html --- docs/index.html | 6114 ----------------------------------------------- 1 file changed, 6114 deletions(-) delete mode 100644 docs/index.html diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 4263fcae..00000000 --- a/docs/index.html +++ /dev/null @@ -1,6114 +0,0 @@ - - - - - - - - - - Welcome to Spotipy! — spotipy 2.0 documentation - - - - - - - - - - - - - - -
-
-
-
- - _images/spotify-web-api-doc.jpg -
-

Welcome to Spotipy!

-

Spotipy is a lightweight Python library for the Spotify Web API. With Spotipy - you get full access to all of the music data provided by the Spotify platform.

-

Assuming you set the SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET - environment variables (here is a video explaining how to do so). For a longer tutorial with - examples included, refer to this video - playlist. Below is a quick example of using Spotipy to list the - names of all the albums released by the artist ‘Birdy’:

-
-
-
import spotipy
-from spotipy.oauth2 import SpotifyClientCredentials
-
-birdy_uri = 'spotify:artist:2WX2uTcsvV5OnS0inACecP'
-spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials())
-
-results = spotify.artist_albums(birdy_uri, album_type='album')
-albums = results['items']
-while results['next']:
-    results = spotify.next(results)
-    albums.extend(results['items'])
-
-for album in albums:
-    print(album['name'])
-
-
-
-

Here’s another example showing how to get 30 second samples and cover art - for the top 10 tracks for Led Zeppelin:

-
-
-
import spotipy
-from spotipy.oauth2 import SpotifyClientCredentials
-
-lz_uri = 'spotify:artist:36QJpDe2go2KgaRleHCDTp'
-
-spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials())
-results = spotify.artist_top_tracks(lz_uri)
-
-for track in results['tracks'][:10]:
-    print('track    : ' + track['name'])
-    print('audio    : ' + track['preview_url'])
-    print('cover art: ' + track['album']['images'][0]['url'])
-    print()
-
-
-
-

Finally, here’s an example that will get the URL for an artist image given the - artist’s name:

-
-
-
import spotipy
-import sys
-from spotipy.oauth2 import SpotifyClientCredentials
-
-spotify = spotipy.Spotify(auth_manager=SpotifyClientCredentials())
-
-if len(sys.argv) > 1:
-    name = ' '.join(sys.argv[1:])
-else:
-    name = 'Radiohead'
-
-results = spotify.search(q='artist:' + name, type='artist')
-items = results['artists']['items']
-if len(items) > 0:
-    artist = items[0]
-    print(artist['name'], artist['images'][0]['url'])
-
-
-
-
-
-

Features

-

Spotipy supports all of the features of the Spotify Web API including access - to all end points, and support for user authorization. For details on the - capabilities you are encouraged to review the Spotify Web - API documentation.

-
-
-

Installation

-

Installing Spotipy on Windows:

-
    -
  • -

    Install Python: Download and install Python from the official Python website (https://www.python.org/downloads/).

    -
  • -
  • -

    Install Spotipy: Open a command prompt and run pip install spotipy.

    -
  • -
-

Open command prompt and run the following:

-
-
-
pip install spotipy
-
-
-
-
    -
  • -

    Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID - and client secret.

    -
  • -
-

Installing Spotipy on macOS:

-
    -
  • -

    Install Homebrew: Install Homebrew, a package manager for macOS.

    -
  • -
  • -

    Run the followng command:

    -
    -
    -
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    -
    -
    -
    -
  • -
  • -

    Install Python: Run brew install python in the terminal:

    -
    -
    -
    brew install python
    -
    -
    -
    -
  • -
  • -

    Install Spotipy: Run pip install spotipy in the terminal:

    -
    -
    -
    pip install spotipy
    -
    -
    -
    -
  • -
  • -

    Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID - and client secret.

    -
  • -
-

Installing Spotipy on Linux:

-
    -
  • -

    Install Python: Use your Linux distribution’s package manager to install Python using the following - command:

    -
    -
    -
    sudo apt-get install python3
    -
    -
    -
    -
  • -
  • -

    Install pip: Use your Linux distribution’s package manager to install pip using the command:

    -
    -
    -
    sudo apt-get install python3-pip
    -
    -
    -
    -
  • -
  • -

    Install Spotipy: Run pip install spotipy in the terminal.

    -
    -
    -

    pip install spotipy

    -
    -
    -
  • -
  • -

    Authenticate your app: Register your app on the Spotify Developer Dashboard and obtain a client ID - and client secret.

    -
  • -
-
-
-
-

You can get the source from github at https://github.com/plamere/spotipy

-
-
-

Getting Started with Spotipy

-

Before you can use Spotipy, there are a few things you need to do:

-

Register your app: To make authorized calls to the Spotify Web API, you need to register your app and - obtain a client ID and client secret. You can register your app at My Dashboard <https://developer.spotify.com/dashboard/applications>_. - Make sure to keep your client ID and client secret secure.

-
-
Choose an authorization flow: Spotipy supports two authorization flows: the Authorization Code flow - and the Client Credentials flow. Choose the one that’s suitable for your application.
-
-
    -
  • -

    Authorization Code flow This method is suitable for long-running applications - which the user logs into once. It provides an access token that can be refreshed.

    -
  • -
-
-
-
-

Note

-

This method requires you to add a redirect URI to your application at - My - Dashboard. - See Redirect URI for more details. -

-
-
-
-
    -
  • -

    The Client Credentials flow This is suitable for short-lived applications that - don’t require user permission. It makes it possible to authenticate your requests to the Spotify - Web API and to obtain a higher rate limit than you would with the Authorization Code flow.

    -
  • -
-
-
-

Before you can use Spotipy’s methods, you need to authorize your app by registering it at My Dashboard - <https://developer.spotify.com/dashboard/applications>_. - This will give you a client id and client secret that you’ll need to use in your code. -

-
-
-

Authorization Code Flow

-

This flow is suitable for long-running applications in which the user grants - permission only once. It provides an access token that can be refreshed. - Since the token exchange involves sending your secret key, perform this on a - secure location, like a backend service, and not from a client such as a - browser or from a mobile app.

-
-

Quick start

-

To support the Client Authorization Code Flow Spotipy provides a - class SpotifyOAuth that can be used to authenticate requests like so:

-
-
-
import spotipy
-from spotipy.oauth2 import SpotifyOAuth
-
-scope = "user-library-read"
-
-sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
-
-results = sp.current_user_saved_tracks()
-for idx, item in enumerate(results['items']):
-    track = item['track']
-    print(idx, track['artists'][0]['name'], " – ", track['name'])
-
-
-
-

or if you are reluctant to immortalize your app credentials in your source code, - you can set environment variables like so (use $env:"credentials" - instead of export - on Windows):

-
-
-
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
-export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
-export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
-
-
-
-
-
-

Scopes

-

See Using - Scopes for information - about scopes.

-
-
-

Redirect URI

-

The Authorization Code Flow needs you to add a redirect URI - to your application at - My - Dashboard - (navigate to your application and then [Edit Settings]). -

-

The redirect_uri argument or - SPOTIPY_REDIRECT_URI - environment variable - must match the redirect URI added to your application in your Dashboard. - The redirect URI can be any valid URI (it does not need to be accessible) - such as http://example.com, - http://localhost or http://127.0.0.1:9090. -

-
-
-
-

Note

-

If you choose an http-scheme URL, and it’s for localhost or - 127.0.0.1`, AND it specifies a port, then spotipy will instantiate

-
-

a server on the indicated response to receive the access token from the - response at the end of the oauth flow [see the code](https://github.com/plamere/spotipy/blob/master/spotipy/oauth2.py#L483-L490). -

-
-
-
-
-
-

Client Credentials Flow

-

The Client Credentials flow is used in server-to-server authentication. Only - endpoints that do not access user information can be accessed. The advantage here - in comparison with requests to the Web API made without an access token, - is that a higher rate limit is applied.

-

As opposed to the Authorization Code Flow, you will not need to set SPOTIPY_REDIRECT_URI, - which means you will never be redirected to the sign in page in your browser:

-
-
-
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
-export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
-
-
-
-

To support the Client Credentials Flow Spotipy provides a - class SpotifyClientCredentials that can be used to authenticate requests like so:

-
-
-
import spotipy
-from spotipy.oauth2 import SpotifyClientCredentials
-
-auth_manager = SpotifyClientCredentials()
-sp = spotipy.Spotify(auth_manager=auth_manager)
-
-playlists = sp.user_playlists('spotify')
-while playlists:
-    for i, playlist in enumerate(playlists['items']):
-        print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'],  playlist['name']))
-    if playlists['next']:
-        playlists = sp.next(playlists)
-    else:
-        playlists = None
-
-
-
-
-
-

IDs URIs and URLs -

-

Spotipy supports a number of different ID types:

-
-
-
    -
  • -

    Spotify URI - The resource identifier that you can enter, for example, in - the Spotify Desktop client’s search box to locate an artist, album, or - track. Example: spotify:track:6rqhFgbbKwnb9MLmUQDhG6 -

    -
  • -
  • -

    Spotify URL - An HTML link that opens a track, album, app, playlist or other - Spotify resource in a Spotify client. Example: - http://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6 -

    -
  • -
  • -

    Spotify ID - A base-62 number that you can find at the end of the Spotify - URI (see above) for an artist, track, album, etc. Example: - 6rqhFgbbKwnb9MLmUQDhG6 -

    -
  • -
-
-
-

In general, any Spotipy method that needs an artist, album, track or playlist ID - will accept ids in any of the above form

-
-
-

Customized token caching

-

Tokens are refreshed automatically and stored by default in the project main folder. - As this might not suit everyone’s needs, spotipy provides a way to create customized - cache handlers.

-

https://github.com/plamere/spotipy/blob/master/spotipy/cache_handler.py -

-

The custom cache handler would need to be a class that inherits from the base - cache handler CacheHandler. The - default cache handler CacheFileHandler is a good example. - An instance of that new class can then be passed as a parameter when - creating SpotifyOAuth, SpotifyPKCE or SpotifyImplicitGrant. - The following handlers are available and defined in the URL above.

-
-
-
    -
  • -

    CacheFileHandler

    -
  • -
  • -

    MemoryCacheHandler

    -
  • -
  • -

    DjangoSessionCacheHandler -

    -
  • -
  • -

    FlaskSessionCacheHandler -

    -
  • -
  • -

    RedisCacheHandler

    -
  • -
-
-
-

Feel free to contribute new cache handlers to the repo.

-
-
-

User Guide

-

In this section, we’ll provide a step-by-step tutorial for using some of Spotipy’s essential features, - such as retrieving user data, and searching for music.

-
-
Retrieving User Data
-
-
    -
  • -

    Import the Spotipy module in your Python code:

    -
    -
    -
    import spotipy
    -
    -
    -
    -
  • -
  • -

    Create a Spotipy object with authentication manager:

    -
    -
    -
    from spotipy.oauth2 import SpotifyOAuth
    -
    -sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id='<your_client_id>',
    -                                         client_secret='<your_client_secret>',
    -                                         redirect_uri='<your_redirect_uri>'))
    -
    -
    -
    -
  • -
  • -

    Use the sp.current_user() method to retrieve the authenticated user’s data:

    -
    -
    -
    user_data = sp.current_user()
    -
    -
    -
    -
  • -
  • -

    Access various pieces of user data from the user_data dictionary, such as the user’s display - name:

    -
    -
    -
    display_name = user_data['display_name']
    -
    -
    -
    -
  • -
-
-
Searching for Music
-
-
    -
  • -

    Use the sp.search() method to search for a track, artist, album or playlist:

    -
    -
    -
    results = sp.search(q='chocolate', type='track')
    -
    -
    -
    -
  • -
  • -

    The results variable contains a dictionary with search results. You can access the list of tracks - returned by the search by accessing results[‘tracks’][‘items’].

    -
  • -
  • -

    Each item in the list of tracks is a dictionary containing information about the track. For - example, you can retrieve the track name using track_name = results[‘tracks’][‘items’][0][‘name’]. -

    -
  • -
-
-
-
-
-

Examples

-

There are many more examples of how to use Spotipy in the Examples - Directory on Github

-
-
-

API Reference

-
-
- -

client - Module

-

A simple and thin Python library for the Spotify Web API

-
-
- class spotipy.client.Spotify(auth=None, - requests_session=True, client_credentials_manager=None, - oauth_manager=None, - auth_manager=None, - proxies=None, - requests_timeout=5, status_forcelist=None, retries=3, status_retries=3, backoff_factor=0.3, - language=None) -
-
-

Bases: object

-

Example usage:

-
-
-
import spotipy
-
-urn = 'spotify:artist:3jOstUTkEu2JkjvRdBA5Gu'
-sp = spotipy.Spotify()
-
-artist = sp.artist(urn)
-print(artist)
-
-user = sp.user('plamere')
-print(user)
-
-
-
-
-
- __init__(auth=None, requests_session=True, client_credentials_manager=None, oauth_manager=None, auth_manager=None, proxies=None, requests_timeout=5, - status_forcelist=None, retries=3, status_retries=3, - backoff_factor=0.3, language=None) -
-
-

Creates a Spotify API client.

-
-
Parameters:
-
-
    -
  • -

    auth – An access token (optional)

    -
  • -
  • -

    requests_session – A Requests session object or a truthy value to create - one. - A falsy value disables sessions. - It should generally be a good idea to keep sessions enabled - for performance reasons (connection pooling).

    -
  • -
  • -

    client_credentials_manager – SpotifyClientCredentials object

    -
  • -
  • -

    oauth_manager – SpotifyOAuth object

    -
  • -
  • -

    auth_manager – SpotifyOauth, SpotifyClientCredentials, - or SpotifyImplicitGrant object

    -
  • -
  • -

    proxies – Definition of proxies (optional). - See Requests doc https://2.python-requests.org/en/master/user/advanced/#proxies -

    -
  • -
  • -

    requests_timeout – Tell Requests to stop waiting for a response after a - given - number of seconds

    -
  • -
  • -

    status_forcelist – Tell requests what type of status codes retries - should occur on

    -
  • -
  • -

    retries – Total number of retries to allow

    -
  • -
  • -

    status_retries – Number of times to retry on bad status codes

    -
  • -
  • -

    backoff_factor – A backoff factor to apply between attempts after the - second try - See urllib3 https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html -

    -
  • -
  • -

    language – The language parameter advertises what language the user - prefers to see. - See ISO-639-1 language code: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes -

    -
  • -
-
-
-
-
- -
-
- add_to_queue(uri, device_id=None) -
-
-

Adds a song to the end of a user’s queue

-

If device A is currently playing music and you try to add to the queue - and pass in the id for device B, you will get a - ‘Player command failed: Restriction violated’ error - I therefore recommend leaving device_id as None so that the active device is targeted

-
-
Parameters:
-
-
    -
  • -

    uri – song uri, id, or url

    -
  • -
  • -

    device_id – the id of a Spotify device. - If None, then the active device is used.

    -
  • -
-
-
-
-
- -
-
- album(album_id, market=None) -
-
-

returns a single album given the album’s ID, URIs or URL

-
-
Parameters:
-
-
    -
  • -

    album_id - the album ID, URI or URL

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code

    -
  • -
-
-
-
-
- -
-
- album_tracks(album_id, limit=50, offset=0, - market=None) -
-
-

Get Spotify catalog information about an album’s tracks

-
-
Parameters:
-
-
    -
  • -

    album_id - the album ID, URI or URL

    -
  • -
  • -

    limit - the number of items to return

    -
  • -
  • -

    offset - the index of the first item to return

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
-
-
-
-
- -
-
- albums(albums, market=None) -
-
-

returns a list of albums given the album IDs, URIs, or URLs

-
-
Parameters:
-
-
    -
  • -

    albums - a list of album IDs, URIs or URLs

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code

    -
  • -
-
-
-
-
- -
-
- artist(artist_id) -
-
-

returns a single artist given the artist’s ID, URI or URL

-
-
Parameters:
-
-
    -
  • -

    artist_id - an artist ID, URI or URL

    -
  • -
-
-
-
-
- -
-
- artist_albums(artist_id, album_type=None, country=None, limit=20, offset=0) -
-
-

Get Spotify catalog information about an artist’s albums

-
-
Parameters:
-
-
    -
  • -

    artist_id - the artist ID, URI or URL

    -
  • -
  • -

    album_type - ‘album’, ‘single’, ‘appears_on’, ‘compilation’

    -
  • -
  • -

    country - limit the response to one particular country.

    -
  • -
  • -

    limit - the number of albums to return

    -
  • -
  • -

    offset - the index of the first album to return

    -
  • -
-
-
-
-
- -
- -
-

Get Spotify catalog information about artists similar to an - identified artist. Similarity is based on analysis of the - Spotify community’s listening history.

-
-
Parameters:
-
-
    -
  • -

    artist_id - the artist ID, URI or URL

    -
  • -
-
-
-
-
- -
-
- artist_top_tracks(artist_id, country='US') -
-
-

Get Spotify catalog information about an artist’s top 10 tracks - by country.

-
-
Parameters:
-
-
    -
  • -

    artist_id - the artist ID, URI or URL

    -
  • -
  • -

    country - limit the response to one particular country.

    -
  • -
-
-
-
-
- -
-
- artists(artists) -
-
-

returns a list of artists given the artist IDs, URIs, or URLs

-
-
Parameters:
-
-
    -
  • -

    artists - a list of artist IDs, URIs or URLs

    -
  • -
-
-
-
-
- -
-
- audio_analysis(track_id) -
-
-

Get audio analysis for a track based upon its Spotify ID - Parameters:

-
-
-
    -
  • -

    track_id - a track URI, URL or ID

    -
  • -
-
-
-
-
- -
-
- audio_features(tracks=[]) -
-
-

Get audio features for one or multiple tracks based upon their Spotify IDs - Parameters:

-
-
-
    -
  • -

    tracks - a list of track URIs, URLs or IDs, maximum: 100 ids

    -
  • -
-
-
-
-
- -
-
- property auth_manager -
-
-
- -
-
- available_markets() -
-
-

Get the list of markets where Spotify is available. - Returns a list of the countries in which Spotify is available, identified by their - ISO 3166-1 alpha-2 country code with additional country codes for special territories.

-
-
- -
-
- categories(country=None, locale=None, limit=20, offset=0) -
-
-

Get a list of categories

-
-
Parameters:
-
-
    -
  • -

    country - An ISO 3166-1 alpha-2 country code.

    -
  • -
  • -

    locale - The desired language, consisting of an ISO 639-1 alpha-2 - language code and an ISO 3166-1 alpha-2 country code, joined - by an underscore.

    -
  • -
  • -

    limit - The maximum number of items to return. Default: 20. - Minimum: 1. Maximum: 50

    -
  • -
  • -

    offset - The index of the first item to return. Default: 0 - (the first object). Use with limit to get the next set of - items.

    -
  • -
-
-
-
-
- -
-
- category(category_id, country=None, locale=None) -
-
-

Get info about a category

-
-
Parameters:
-
-
    -
  • -

    category_id - The Spotify category ID for the category.

    -
  • -
  • -

    country - An ISO 3166-1 alpha-2 country code.

    -
  • -
  • -

    locale - The desired language, consisting of an ISO 639-1 alpha-2 - language code and an ISO 3166-1 alpha-2 country code, joined - by an underscore.

    -
  • -
-
-
-
-
- -
-
- category_playlists(category_id=None, country=None, limit=20, offset=0) -
-
-

Get a list of playlists for a specific Spotify category

-
-
Parameters:
-
-
    -
  • -

    category_id - The Spotify category ID for the category.

    -
  • -
  • -

    country - An ISO 3166-1 alpha-2 country code.

    -
  • -
  • -

    limit - The maximum number of items to return. Default: 20. - Minimum: 1. Maximum: 50

    -
  • -
  • -

    offset - The index of the first item to return. Default: 0 - (the first object). Use with limit to get the next set of - items.

    -
  • -
-
-
-
-
- -
-
- country_codes = ['AD', 'AR', 'AU', 'AT', 'BE', 'BO', 'BR', 'BG', 'CA', 'CL', 'CO', 'CR', 'CY', 'CZ', 'DK', 'DO', 'EC', 'SV', 'EE', 'FI', 'FR', 'DE', 'GR', 'GT', 'HN', 'HK', 'HU', 'IS', 'ID', 'IE', 'IT', 'JP', 'LV', 'LI', 'LT', 'LU', 'MY', 'MT', 'MX', 'MC', 'NL', 'NZ', 'NI', 'NO', 'PA', 'PY', 'PE', 'PH', 'PL', 'PT', 'SG', 'ES', 'SK', 'SE', 'CH', 'TW', 'TR', 'GB', 'US', 'UY'] -
-
-
- -
-
- current_playback(market=None, additional_types=None) -
-
-

Get information about user’s current playback.

-
-
Parameters:
-
-
    -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
  • -

    additional_types - episode to get podcast track information

    -
  • -
-
-
-
-
- -
-
- current_user() -
-
-

Get detailed profile information about the current user. - An alias for the ‘me’ method.

-
-
- -
-
- current_user_follow_playlist(playlist_id) -
-
-

Add the current authenticated user as a follower of a playlist.

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
-
-
-
-
- -
-
- current_user_followed_artists(limit=20, after=None) -
-
-

Gets a list of the artists followed by the current authorized user

-
-
Parameters:
-
-
    -
  • -

    limit - the number of artists to return

    -
  • -
  • -
    -
    after - the last artist ID retrieved from the previous
    -
    -

    request

    -
    -
    -
  • -
-
-
-
-
- -
-
- current_user_following_artists(ids=None) -
-
-

Check if the current user is following certain artists

-

Returns list of booleans respective to ids

-
-
Parameters:
-
-
    -
  • -

    ids - a list of artist URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_following_users(ids=None) -
-
-

Check if the current user is following certain users

-

Returns list of booleans respective to ids

-
-
Parameters:
-
-
    -
  • -

    ids - a list of user URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_playing_track() -
-
-

Get information about the current users currently playing track.

-
-
- -
-
- current_user_playlists(limit=50, offset=0) -
-
-

Get current user playlists without required getting his profile - Parameters:

-
-
-
    -
  • -

    limit - the number of items to return

    -
  • -
  • -

    offset - the index of the first item to return

    -
  • -
-
-
-
-
- -
-
- current_user_recently_played(limit=50, after=None, before=None) -
-
-

Get the current user’s recently played tracks

-
-
Parameters:
-
-
    -
  • -

    limit - the number of entities to return

    -
  • -
  • -
    -
    after - unix timestamp in milliseconds. Returns all items
    -
    -

    after (but not including) this cursor position. - Cannot be used if before is specified.

    -
    -
    -
  • -
  • -
    -
    before - unix timestamp in milliseconds. Returns all items
    -
    -

    before (but not including) this cursor position. - Cannot be used if after is specified

    -
    -
    -
  • -
-
-
-
-
- -
-
- current_user_saved_albums(limit=20, offset=0, - market=None) -
-
-

Gets a list of the albums saved in the current authorized user’s - “Your Music” library

-
-
Parameters:
-
-
    -
  • -

    limit - the number of albums to return (MAX_LIMIT=50)

    -
  • -
  • -

    offset - the index of the first album to return

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
-
-
-
-
- -
-
- current_user_saved_albums_add(albums=[]) -
-
-

Add one or more albums to the current user’s - “Your Music” library. - Parameters:

-
-
-
    -
  • -

    albums - a list of album URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_albums_contains(albums=[]) -
-
-

Check if one or more albums is already saved in - the current Spotify user’s “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    albums - a list of album URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_albums_delete(albums=[]) -
-
-

Remove one or more albums from the current user’s - “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    albums - a list of album URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_episodes(limit=20, offset=0, - market=None) -
-
-

Gets a list of the episodes saved in the current authorized user’s - “Your Music” library

-
-
Parameters:
-
-
    -
  • -

    limit - the number of episodes to return

    -
  • -
  • -

    offset - the index of the first episode to return

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code

    -
  • -
-
-
-
-
- -
-
- current_user_saved_episodes_add(episodes=None) -
-
-

Add one or more episodes to the current user’s - “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    episodes - a list of episode URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_episodes_contains(episodes=None) -
-
-

Check if one or more episodes is already saved in - the current Spotify user’s “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    episodes - a list of episode URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_episodes_delete(episodes=None) -
-
-

Remove one or more episodes from the current user’s - “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    episodes - a list of episode URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_shows(limit=20, offset=0, - market=None) -
-
-

Gets a list of the shows saved in the current authorized user’s - “Your Music” library

-
-
Parameters:
-
-
    -
  • -

    limit - the number of shows to return

    -
  • -
  • -

    offset - the index of the first show to return

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code

    -
  • -
-
-
-
-
- -
-
- current_user_saved_shows_add(shows=[]) -
-
-

Add one or more albums to the current user’s - “Your Music” library. - Parameters:

-
-
-
    -
  • -

    shows - a list of show URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_shows_contains(shows=[]) -
-
-

Check if one or more shows is already saved in - the current Spotify user’s “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    shows - a list of show URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_shows_delete(shows=[]) -
-
-

Remove one or more shows from the current user’s - “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    shows - a list of show URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_tracks(limit=20, offset=0, - market=None) -
-
-

Gets a list of the tracks saved in the current authorized user’s - “Your Music” library

-
-
Parameters:
-
-
    -
  • -

    limit - the number of tracks to return

    -
  • -
  • -

    offset - the index of the first track to return

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code

    -
  • -
-
-
-
-
- -
-
- current_user_saved_tracks_add(tracks=None) -
-
-

Add one or more tracks to the current user’s - “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    tracks - a list of track URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_tracks_contains(tracks=None) -
-
-

Check if one or more tracks is already saved in - the current Spotify user’s “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    tracks - a list of track URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_saved_tracks_delete(tracks=None) -
-
-

Remove one or more tracks from the current user’s - “Your Music” library.

-
-
Parameters:
-
-
    -
  • -

    tracks - a list of track URIs, URLs or IDs

    -
  • -
-
-
-
-
- -
-
- current_user_top_artists(limit=20, offset=0, - time_range='medium_term') -
-
-

Get the current user’s top artists

-
-
Parameters:
-
-
    -
  • -

    limit - the number of entities to return

    -
  • -
  • -

    offset - the index of the first entity to return

    -
  • -
  • -

    time_range - Over what time frame are the affinities computed - Valid-values: short_term, medium_term, long_term

    -
  • -
-
-
-
-
- -
-
- current_user_top_tracks(limit=20, offset=0, - time_range='medium_term') -
-
-

Get the current user’s top tracks

-
-
Parameters:
-
-
    -
  • -

    limit - the number of entities to return

    -
  • -
  • -

    offset - the index of the first entity to return

    -
  • -
  • -

    time_range - Over what time frame are the affinities computed - Valid-values: short_term, medium_term, long_term

    -
  • -
-
-
-
-
- -
-
- current_user_unfollow_playlist(playlist_id) -
-
-

Unfollows (deletes) a playlist for the current authenticated - user

-
-
Parameters:
-
-
    -
  • -

    name - the name of the playlist

    -
  • -
-
-
-
-
- -
-
- currently_playing(market=None, additional_types=None) -
-
-

Get user’s currently playing track.

-
-
Parameters:
-
-
    -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
  • -

    additional_types - episode to get podcast track information

    -
  • -
-
-
-
-
- -
-
- default_retry_codes = (429, 500, 502, 503, 504) -
-
-
- -
-
- devices() -
-
-

Get a list of user’s available devices.

-
-
- -
-
- episode(episode_id, market=None) -
-
-

returns a single episode given the episode’s ID, URIs or URL

-
-
Parameters:
-
-
    -
  • -

    episode_id - the episode ID, URI or URL

    -
  • -
  • -
    -
    market - an ISO 3166-1 alpha-2 country code.
    -
    -

    The episode must be available in the given market. - If user-based authorization is in use, the user’s country - takes precedence. If neither market nor user country are - provided, the content is considered unavailable for the client.

    -
    -
    -
  • -
-
-
-
-
- -
-
- episodes(episodes, market=None) -
-
-

returns a list of episodes given the episode IDs, URIs, or URLs

-
-
Parameters:
-
-
    -
  • -

    episodes - a list of episode IDs, URIs or URLs

    -
  • -
  • -
    -
    market - an ISO 3166-1 alpha-2 country code.
    -
    -

    Only episodes available in the given market will be returned. - If user-based authorization is in use, the user’s country - takes precedence. If neither market nor user country are - provided, the content is considered unavailable for the client.

    -
    -
    -
  • -
-
-
-
-
- -
-
- featured_playlists(locale=None, country=None, timestamp=None, limit=20, offset=0) -
-
-

Get a list of Spotify featured playlists

-
-
Parameters:
-
-
    -
  • -

    locale - The desired language, consisting of a lowercase ISO - 639-1 alpha-2 language code and an uppercase ISO 3166-1 alpha-2 - country code, joined by an underscore.

    -
  • -
  • -

    country - An ISO 3166-1 alpha-2 country code.

    -
  • -
  • -

    timestamp - A timestamp in ISO 8601 format: - yyyy-MM-ddTHH:mm:ss. Use this parameter to specify the user’s - local time to get results tailored for that specific date and - time in the day

    -
  • -
  • -

    limit - The maximum number of items to return. Default: 20. - Minimum: 1. Maximum: 50

    -
  • -
  • -

    offset - The index of the first item to return. Default: 0 - (the first object). Use with limit to get the next set of - items.

    -
  • -
-
-
-
-
- -
-
- max_retries = 3 -
-
-
- -
-
- me() -
-
-

Get detailed profile information about the current user. - An alias for the ‘current_user’ method.

-
-
- -
-
- new_releases(country=None, limit=20, offset=0) -
-
-

Get a list of new album releases featured in Spotify

-
-
Parameters:
-
-
    -
  • -

    country - An ISO 3166-1 alpha-2 country code.

    -
  • -
  • -

    limit - The maximum number of items to return. Default: 20. - Minimum: 1. Maximum: 50

    -
  • -
  • -

    offset - The index of the first item to return. Default: 0 - (the first object). Use with limit to get the next set of - items.

    -
  • -
-
-
-
-
- -
-
- next(result) -
-
-

returns the next result given a paged result

-
-
Parameters:
-
-
    -
  • -

    result - a previously returned paged result

    -
  • -
-
-
-
-
- -
-
- next_track(device_id=None) -
-
-

Skip user’s playback to next track.

-
-
Parameters:
-
-
    -
  • -

    device_id - device target for playback

    -
  • -
-
-
-
-
- -
-
- pause_playback(device_id=None) -
-
-

Pause user’s playback.

-
-
Parameters:
-
-
    -
  • -

    device_id - device target for playback

    -
  • -
-
-
-
-
- -
-
- playlist(playlist_id, fields=None, market=None, additional_types=('track',)) -
-
-

Gets playlist by id.

-
-
Parameters:
-
-
    -
  • -

    playlist - the id of the playlist

    -
  • -
  • -

    fields - which fields to return

    -
  • -
  • -
    -
    market - An ISO 3166-1 alpha-2 country code or the
    -
    -

    string from_token.

    -
    -
    -
  • -
  • -
    -
    additional_types - list of item types to return.
    -
    -

    valid types are: track and episode

    -
    -
    -
  • -
-
-
-
-
- -
-
- playlist_add_items(playlist_id, items, position=None) -
-
-

Adds tracks/episodes to a playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    items - a list of track/episode URIs or URLs

    -
  • -
  • -

    position - the position to add the tracks

    -
  • -
-
-
-
-
- -
-
- playlist_change_details(playlist_id, name=None, public=None, collaborative=None, description=None) -
-
-

Changes a playlist’s name and/or public/private state, - collaborative state, and/or description

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    name - optional name of the playlist

    -
  • -
  • -

    public - optional is the playlist public

    -
  • -
  • -

    collaborative - optional is the playlist collaborative

    -
  • -
  • -

    description - optional description of the playlist

    -
  • -
-
-
-
-
- -
-
- playlist_cover_image(playlist_id) -
-
-

Get cover image of a playlist.

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the playlist ID, URI or URL

    -
  • -
-
-
-
-
- -
-
- playlist_is_following(playlist_id, user_ids) -
-
-

Check to see if the given users are following the given playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -
    -
    user_ids - the ids of the users that you want to check to see
    -
    -

    if they follow the playlist. Maximum: 5 ids.

    -
    -
    -
  • -
-
-
-
-
- -
-
- playlist_items(playlist_id, fields=None, limit=100, offset=0, market=None, additional_types=('track', - 'episode')) -
-
-

Get full details of the tracks and episodes of a playlist.

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the playlist ID, URI or URL

    -
  • -
  • -

    fields - which fields to return

    -
  • -
  • -

    limit - the maximum number of tracks to return

    -
  • -
  • -

    offset - the index of the first track to return

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
  • -
    -
    additional_types - list of item types to return.
    -
    -

    valid types are: track and episode

    -
    -
    -
  • -
-
-
-
-
- -
-
- playlist_remove_all_occurrences_of_items(playlist_id, items, snapshot_id=None) -
-
-

Removes all occurrences of the given tracks/episodes from the given playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    items - list of track/episode ids to remove from the playlist

    -
  • -
  • -

    snapshot_id - optional id of the playlist snapshot

    -
  • -
-
-
-
-
- -
-
- playlist_remove_specific_occurrences_of_items(playlist_id, items, snapshot_id=None) -
-
-

Removes all occurrences of the given tracks from the given playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -
    -
    items - an array of objects containing Spotify URIs of the
    -
    -

    tracks/episodes to remove with their current positions in - the playlist. For example:

    -
    -
    -

    [ { “uri”:”4iV5W9uYEdYUVa79Axb7Rh”, “positions”:[2] }, - { “uri”:”1301WleyT98MSxVHPZCA6M”, “positions”:[7] } ]

    -
    -
    -
    -
    -
  • -
  • -

    snapshot_id - optional id of the playlist snapshot

    -
  • -
-
-
-
-
- -
-
- playlist_reorder_items(playlist_id, range_start, insert_before, range_length=1, snapshot_id=None) -
-
-

Reorder tracks in a playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    range_start - the position of the first track to be reordered

    -
  • -
  • -
    -
    range_length - optional the number of tracks to be reordered
    -
    -

    (default: 1)

    -
    -
    -
  • -
  • -
    -
    insert_before - the position where the tracks should be
    -
    -

    inserted

    -
    -
    -
  • -
  • -

    snapshot_id - optional playlist’s snapshot ID

    -
  • -
-
-
-
-
- -
-
- playlist_replace_items(playlist_id, items) -
-
-

Replace all tracks/episodes in a playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    items - list of track/episode ids to comprise playlist

    -
  • -
-
-
-
-
- -
-
- playlist_tracks(playlist_id, fields=None, limit=100, offset=0, market=None, additional_types=('track',)) -
-
-

Get full details of the tracks of a playlist.

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the playlist ID, URI or URL

    -
  • -
  • -

    fields - which fields to return

    -
  • -
  • -

    limit - the maximum number of tracks to return

    -
  • -
  • -

    offset - the index of the first track to return

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
  • -
    -
    additional_types - list of item types to return.
    -
    -

    valid types are: track and episode

    -
    -
    -
  • -
-
-
-
-
- -
-
- playlist_upload_cover_image(playlist_id, image_b64) -
-
-

Replace the image used to represent a specific playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -
    -
    image_b64 - image data as a Base64 encoded JPEG image string
    -
    -

    (maximum payload size is 256 KB)

    -
    -
    -
  • -
-
-
-
-
- -
-
- previous(result) -
-
-

returns the previous result given a paged result

-
-
Parameters:
-
-
    -
  • -

    result - a previously returned paged result

    -
  • -
-
-
-
-
- -
-
- previous_track(device_id=None) -
-
-

Skip user’s playback to previous track.

-
-
Parameters:
-
-
    -
  • -

    device_id - device target for playback

    -
  • -
-
-
-
-
- -
-
- queue() -
-
-

Gets the current user’s queue

-
-
- -
-
- recommendation_genre_seeds() -
-
-

Get a list of genres available for the recommendations function.

-
-
- -
-
- recommendations(seed_artists=None, seed_genres=None, seed_tracks=None, limit=20, country=None, **kwargs) -
-
-

Get a list of recommended tracks for one to five seeds. - (at least one of seed_artists, seed_tracks and seed_genres - are needed)

-
-
Parameters:
-
-
    -
  • -

    seed_artists - a list of artist IDs, URIs or URLs

    -
  • -
  • -

    seed_tracks - a list of track IDs, URIs or URLs

    -
  • -
  • -
    -
    seed_genres - a list of genre names. Available genres for
    -
    -

    recommendations can be found by calling - recommendation_genre_seeds

    -
    -
    -
  • -
  • -
    -
    country - An ISO 3166-1 alpha-2 country code. If provided,
    -
    -

    all results will be playable in this country.

    -
    -
    -
  • -
  • -
    -
    limit - The maximum number of items to return. Default: 20.
    -
    -

    Minimum: 1. Maximum: 100

    -
    -
    -
  • -
  • -
    -
    min/max/target_<attribute> - For the tuneable track
    -
    -

    attributes listed in the documentation, these values - provide filters and targeting on results.

    -
    -
    -
  • -
-
-
-
-
- -
-
- repeat(state, device_id=None) -
-
-

Set repeat mode for playback.

-
-
Parameters:
-
-
    -
  • -

    state - track, context, or off

    -
  • -
  • -

    device_id - device target for playback

    -
  • -
-
-
-
-
- -
-
- search(q, limit=10, offset=0, - type='track', market=None) -
-
-

searches for an item

-
-
Parameters:
-
-
    -
  • -
    -
    q - the search query (see how to write a query in the
    -
    -

    official documentation https://developer.spotify.com/documentation/web-api/reference/search/) - # noqa

    -
    -
    -
  • -
  • -
    -
    limit - the number of items to return (min = 1, default = 10, max = 50). The limit is - applied
    -
    -

    within each type, not on the total response.

    -
    -
    -
  • -
  • -

    offset - the index of the first item to return

    -
  • -
  • -
    -
    type - the types of items to return. One or more of ‘artist’, ‘album’,
    -
    -

    ‘track’, ‘playlist’, ‘show’, and ‘episode’. If multiple types are desired, - pass in a comma separated string; e.g., ‘track,album,episode’.

    -
    -
    -
  • -
  • -
    -
    market - An ISO 3166-1 alpha-2 country code or the string
    -
    -

    from_token.

    -
    -
    -
  • -
-
-
-
-
- -
-
- search_markets(q, limit=10, offset=0, - type='track', markets=None, total=None) -
-
-

(experimental) Searches multiple markets for an item

-
-
Parameters:
-
-
    -
  • -
    -
    q - the search query (see how to write a query in the
    -
    -

    official documentation https://developer.spotify.com/documentation/web-api/reference/search/) - # noqa

    -
    -
    -
  • -
  • -
    -
    limit - the number of items to return (min = 1, default = 10, max = 50). If a search - is to be done on multiple
    -
    -

    markets, then this limit is applied to each market. (e.g. search US, CA, MX each with - a limit of 10). - If multiple types are specified, this applies to each type.

    -
    -
    -
  • -
  • -

    offset - the index of the first item to return

    -
  • -
  • -
    -
    type - the types of items to return. One or more of ‘artist’, ‘album’,
    -
    -

    ‘track’, ‘playlist’, ‘show’, or ‘episode’. If multiple types are desired, pass in a - comma separated string.

    -
    -
    -
  • -
  • -

    markets - A list of ISO 3166-1 alpha-2 country codes. Search all country markets by - default.

    -
  • -
  • -

    total - the total number of results to return across multiple markets and types.

    -
  • -
-
-
-
-
- -
-
- seek_track(position_ms, device_id=None) -
-
-

Seek to position in current track.

-
-
Parameters:
-
-
    -
  • -

    position_ms - position in milliseconds to seek to

    -
  • -
  • -

    device_id - device target for playback

    -
  • -
-
-
-
-
- -
-
- set_auth(auth) -
-
-
- -
-
- show(show_id, market=None) -
-
-

returns a single show given the show’s ID, URIs or URL

-
-
Parameters:
-
-
    -
  • -

    show_id - the show ID, URI or URL

    -
  • -
  • -
    -
    market - an ISO 3166-1 alpha-2 country code.
    -
    -

    The show must be available in the given market. - If user-based authorization is in use, the user’s country - takes precedence. If neither market nor user country are - provided, the content is considered unavailable for the client.

    -
    -
    -
  • -
-
-
-
-
- -
-
- show_episodes(show_id, limit=50, offset=0, - market=None) -
-
-

Get Spotify catalog information about a show’s episodes

-
-
Parameters:
-
-
    -
  • -

    show_id - the show ID, URI or URL

    -
  • -
  • -

    limit - the number of items to return

    -
  • -
  • -

    offset - the index of the first item to return

    -
  • -
  • -
    -
    market - an ISO 3166-1 alpha-2 country code.
    -
    -

    Only episodes available in the given market will be returned. - If user-based authorization is in use, the user’s country - takes precedence. If neither market nor user country are - provided, the content is considered unavailable for the client.

    -
    -
    -
  • -
-
-
-
-
- -
-
- shows(shows, market=None) -
-
-

returns a list of shows given the show IDs, URIs, or URLs

-
-
Parameters:
-
-
    -
  • -

    shows - a list of show IDs, URIs or URLs

    -
  • -
  • -
    -
    market - an ISO 3166-1 alpha-2 country code.
    -
    -

    Only shows available in the given market will be returned. - If user-based authorization is in use, the user’s country - takes precedence. If neither market nor user country are - provided, the content is considered unavailable for the client.

    -
    -
    -
  • -
-
-
-
-
- -
-
- shuffle(state, device_id=None) -
-
-

Toggle playback shuffling.

-
-
Parameters:
-
-
    -
  • -

    state - true or false

    -
  • -
  • -

    device_id - device target for playback

    -
  • -
-
-
-
-
- -
-
- start_playback(device_id=None, context_uri=None, uris=None, offset=None, position_ms=None) -
-
-

Start or resume user’s playback.

-

Provide a context_uri to start playback of an album, - artist, or playlist.

-

Provide a uris list to start playback of one or more - tracks.

-

Provide offset as {“position”: <int>} or {“uri”: “<track uri>”} - to start playback at a particular offset.

-
-
Parameters:
-
-
    -
  • -

    device_id - device target for playback

    -
  • -
  • -

    context_uri - spotify context uri to play

    -
  • -
  • -

    uris - spotify track uris

    -
  • -
  • -

    offset - offset into context by index or track

    -
  • -
  • -
    -
    position_ms - (optional) indicates from what position to start playback.
    -
    -

    Must be a positive number. Passing in a position that is - greater than the length of the track will cause the player to - start playing the next song.

    -
    -
    -
  • -
-
-
-
-
- -
-
- track(track_id, market=None) -
-
-

returns a single track given the track’s ID, URI or URL

-
-
Parameters:
-
-
    -
  • -

    track_id - a spotify URI, URL or ID

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
-
-
-
-
- -
-
- tracks(tracks, market=None) -
-
-

returns a list of tracks given a list of track IDs, URIs, or URLs

-
-
Parameters:
-
-
    -
  • -

    tracks - a list of spotify URIs, URLs or IDs. Maximum: 50 IDs.

    -
  • -
  • -

    market - an ISO 3166-1 alpha-2 country code.

    -
  • -
-
-
-
-
- -
-
- transfer_playback(device_id, force_play=True) -
-
-

Transfer playback to another device. - Note that the API accepts a list of device ids, but only - actually supports one.

-
-
Parameters:
-
-
    -
  • -

    device_id - transfer playback to this device

    -
  • -
  • -
    -
    force_play - true: after transfer, play. false:
    -
    -

    keep current state.

    -
    -
    -
  • -
-
-
-
-
- -
-
- user(user) -
-
-

Gets basic profile information about a Spotify User

-
-
Parameters:
-
-
    -
  • -

    user - the id of the usr

    -
  • -
-
-
-
-
- -
-
- user_follow_artists(ids=[]) -
-
-

Follow one or more artists - Parameters:

-
-
-
    -
  • -

    ids - a list of artist IDs

    -
  • -
-
-
-
-
- -
-
- user_follow_users(ids=[]) -
-
-

Follow one or more users - Parameters:

-
-
-
    -
  • -

    ids - a list of user IDs

    -
  • -
-
-
-
-
- -
-
- user_playlist(user, playlist_id=None, fields=None, market=None) -
-
-
- -
-
- user_playlist_add_episodes(user, playlist_id, episodes, position=None) -
-
-
- -
-
- user_playlist_add_tracks(user, playlist_id, tracks, position=None) -
-
-
- -
-
- user_playlist_change_details(user, playlist_id, name=None, public=None, collaborative=None, description=None) -
-
-
- -
-
- user_playlist_create(user, name, public=True, collaborative=False, description='') -
-
-

Creates a playlist for a user

-
-
Parameters:
-
-
    -
  • -

    user - the id of the user

    -
  • -
  • -

    name - the name of the playlist

    -
  • -
  • -

    public - is the created playlist public

    -
  • -
  • -

    collaborative - is the created playlist collaborative

    -
  • -
  • -

    description - the description of the playlist

    -
  • -
-
-
-
-
- -
-
- user_playlist_follow_playlist(playlist_owner_id, playlist_id) -
-
-

Add the current authenticated user as a follower of a playlist.

-
-
Parameters:
-
-
    -
  • -

    playlist_owner_id - the user id of the playlist owner

    -
  • -
  • -

    playlist_id - the id of the playlist

    -
  • -
-
-
-
-
- -
-
- user_playlist_is_following(playlist_owner_id, playlist_id, user_ids) -
-
-

Check to see if the given users are following the given playlist

-
-
Parameters:
-
-
    -
  • -

    playlist_owner_id - the user id of the playlist owner

    -
  • -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -
    -
    user_ids - the ids of the users that you want to check to see
    -
    -

    if they follow the playlist. Maximum: 5 ids.

    -
    -
    -
  • -
-
-
-
-
- -
-
- user_playlist_remove_all_occurrences_of_tracks(user, playlist_id, tracks, snapshot_id=None) -
-
-

Removes all occurrences of the given tracks from the given playlist

-
-
Parameters:
-
-
    -
  • -

    user - the id of the user

    -
  • -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    tracks - the list of track ids to remove from the playlist

    -
  • -
  • -

    snapshot_id - optional id of the playlist snapshot

    -
  • -
-
-
-
-
- -
-
- user_playlist_remove_specific_occurrences_of_tracks(user, playlist_id, tracks, snapshot_id=None) -
-
-

Removes all occurrences of the given tracks from the given playlist

-
-
Parameters:
-
-
    -
  • -

    user - the id of the user

    -
  • -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -
    -
    tracks - an array of objects containing Spotify URIs of the
    -
    -

    tracks to remove with their current positions in the - playlist. For example:

    -
    -
    -

    [ { “uri”:”4iV5W9uYEdYUVa79Axb7Rh”, “positions”:[2] }, - { “uri”:”1301WleyT98MSxVHPZCA6M”, “positions”:[7] } ]

    -
    -
    -
    -
    -
  • -
  • -

    snapshot_id - optional id of the playlist snapshot

    -
  • -
-
-
-
-
- -
-
- user_playlist_reorder_tracks(user, playlist_id, range_start, insert_before, range_length=1, snapshot_id=None) -
-
-

Reorder tracks in a playlist from a user

-
-
Parameters:
-
-
    -
  • -

    user - the id of the user

    -
  • -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    range_start - the position of the first track to be reordered

    -
  • -
  • -
    -
    range_length - optional the number of tracks to be reordered
    -
    -

    (default: 1)

    -
    -
    -
  • -
  • -
    -
    insert_before - the position where the tracks should be
    -
    -

    inserted

    -
    -
    -
  • -
  • -

    snapshot_id - optional playlist’s snapshot ID

    -
  • -
-
-
-
-
- -
-
- user_playlist_replace_tracks(user, playlist_id, tracks) -
-
-

Replace all tracks in a playlist for a user

-
-
Parameters:
-
-
    -
  • -

    user - the id of the user

    -
  • -
  • -

    playlist_id - the id of the playlist

    -
  • -
  • -

    tracks - the list of track ids to add to the playlist

    -
  • -
-
-
-
-
- -
-
- user_playlist_tracks(user=None, playlist_id=None, fields=None, limit=100, offset=0, market=None) -
-
-
- -
-
- user_playlist_unfollow(user, playlist_id) -
-
-

Unfollows (deletes) a playlist for a user

-
-
Parameters:
-
-
    -
  • -

    user - the id of the user

    -
  • -
  • -

    name - the name of the playlist

    -
  • -
-
-
-
-
- -
-
- user_playlists(user, limit=50, offset=0) -
-
-

Gets playlists of a user

-
-
Parameters:
-
-
    -
  • -

    user - the id of the usr

    -
  • -
  • -

    limit - the number of items to return

    -
  • -
  • -

    offset - the index of the first item to return

    -
  • -
-
-
-
-
- -
-
- user_unfollow_artists(ids=[]) -
-
-

Unfollow one or more artists - Parameters:

-
-
-
    -
  • -

    ids - a list of artist IDs

    -
  • -
-
-
-
-
- -
-
- user_unfollow_users(ids=[]) -
-
-

Unfollow one or more users - Parameters:

-
-
-
    -
  • -

    ids - a list of user IDs

    -
  • -
-
-
-
-
- -
-
- volume(volume_percent, device_id=None) -
-
-

Set playback volume.

-
-
Parameters:
-
-
    -
  • -

    volume_percent - volume between 0 and 100

    -
  • -
  • -

    device_id - device target for playback

    -
  • -
-
-
-
-
- -
-
- -
-
- exception spotipy.client.SpotifyException(http_status, code, msg, reason=None, headers=None) -
-
-

Bases: Exception

-
-
- __init__(http_status, code, msg, reason=None, headers=None) -
-
-
- -
-
- -
-
- -

oauth2 - Module

-
-
- class spotipy.oauth2.SpotifyClientCredentials(client_id=None, client_secret=None, - proxies=None, - requests_session=True, requests_timeout=None, cache_handler=None) -
-
-

Bases: SpotifyAuthBase -

-
-
- OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token' -
-
-
- -
-
- __init__(client_id=None, client_secret=None, proxies=None, requests_session=True, requests_timeout=None, cache_handler=None) -
-
-

Creates a Client Credentials Flow Manager.

-

The Client Credentials flow is used in server-to-server authentication. - Only endpoints that do not access user information can be accessed. - This means that endpoints that require authorization scopes cannot be accessed. - The advantage, however, of this authorization flow is that it does not require any - user interaction

-

You can either provide a client_id and client_secret to the - constructor or set SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET - environment variables

-
-
Parameters:
-
-
    -
  • -

    client_id: Must be supplied or set as environment variable

    -
  • -
  • -

    client_secret: Must be supplied or set as environment variable

    -
  • -
  • -

    proxies: Optional, proxy for the requests library to route through

    -
  • -
  • -

    requests_session: A Requests session

    -
  • -
  • -
    -
    requests_timeout: Optional, tell Requests to stop waiting for a response after
    -
    -

    a given number of seconds

    -
    -
    -
  • -
  • -
    -
    cache_handler: An instance of the CacheHandler class to handle
    -
    -

    getting and saving cached authorization tokens. - Optional, will otherwise use CacheFileHandler. - (takes precedence over cache_path and username)

    -
    -
    -
  • -
-
-
-
-
- -
-
- get_access_token(as_dict=True, check_cache=True) -
-
-

If a valid access token is in memory, returns it - Else fetches a new token and returns it

-
-
-

Parameters: - - as_dict - a boolean indicating if returning the access token

-
-
-

as a token_info dictionary, otherwise it will be returned - as a string.

-
-
-
-
-
-
- -
-
- -
-
- class spotipy.oauth2.SpotifyImplicitGrant(client_id=None, redirect_uri=None, - state=None, - scope=None, - cache_path=None, - username=None, - show_dialog=False, - cache_handler=None) -
-
-

Bases: SpotifyAuthBase -

-

Implements Implicit Grant Flow for client apps

-

This auth manager enables user and non-user endpoints with only - a client secret, redirect uri, and username. The user will need to - copy and paste a URI from the browser every hour.

-
-

Security Warning

-

The OAuth standard no longer recommends the Implicit Grant Flow for - client-side code. Spotify has implemented the OAuth-suggested PKCE - extension that removes the need for a client secret in the - Authentication Code flow. Use the SpotifyPKCE auth manager instead - of SpotifyImplicitGrant.

-

SpotifyPKCE contains all of the functionality of - SpotifyImplicitGrant, plus automatic response retrieval and - refreshable tokens. Only a few replacements need to be made:

-
    -
  • -

    get_auth_response()[‘access_token’] -> - get_access_token(get_authorization_code())

    -
  • -
  • -

    get_auth_response() -> - get_access_token(get_authorization_code()); get_cached_token()

    -
  • -
  • -

    parse_response_token(url)[‘access_token’] -> - get_access_token(parse_response_code(url))

    -
  • -
  • -

    parse_response_token(url) -> - get_access_token(parse_response_code(url)); get_cached_token()

    -
  • -
-

The security concern in the Implicit Grant flow is that the token is - returned in the URL and can be intercepted through the browser. A - request with an authorization code and proof of origin could not be - easily intercepted without a compromised network.

-
-
- OAUTH_AUTHORIZE_URL = 'https://accounts.spotify.com/authorize' -
-
-
- -
-
- __init__(client_id=None, redirect_uri=None, state=None, scope=None, cache_path=None, username=None, show_dialog=False, cache_handler=None) -
-
-

Creates Auth Manager using the Implicit Grant flow

-

See help(SpotifyImplicitGrant) for full Security Warning

-
-

Parameters -

-
    -
  • -

    client_id: Must be supplied or set as environment variable

    -
  • -
  • -

    redirect_uri: Must be supplied or set as environment variable

    -
  • -
  • -

    state: May be supplied, no verification is performed

    -
  • -
  • -
    -
    scope: Optional, either a list of scopes or comma separated string of scopes.
    -
    -

    e.g, “playlist-read-private,playlist-read-collaborative”

    -
    -
    -
  • -
  • -
    -
    cache_handler: An instance of the CacheHandler class to handle
    -
    -

    getting and saving cached authorization tokens. - May be supplied, will otherwise use CacheFileHandler. - (takes precedence over cache_path and username)

    -
    -
    -
  • -
  • -
    -
    cache_path: (deprecated) May be supplied, will otherwise be generated
    -
    -

    (takes precedence over username)

    -
    -
    -
  • -
  • -
    -
    username: (deprecated) May be supplied or set as environment variable
    -
    -

    (will set cache_path to .cache-{username})

    -
    -
    -
  • -
  • -

    show_dialog: Interpreted as boolean

    -
  • -
-
-
-
- -
-
- get_access_token(state=None, response=None, check_cache=True) -
-
-

Gets Auth Token from cache (preferred) or user interaction

-
-

Parameters

-
    -
  • -

    state: May be given, overrides (without changing) self.state

    -
  • -
  • -

    response: URI with token, can break expiration checks

    -
  • -
  • -

    check_cache: Interpreted as boolean

    -
  • -
-
-
-
- -
-
- get_auth_response(state=None) -
-
-

Gets a new auth token with user interaction

-
-
- -
-
- get_authorize_url(state=None) -
-
-

Gets the URL to use to authorize this app

-
-
- -
-
- get_cached_token() -
-
-
- -
-
- static parse_auth_response_url(url) -
-
-
- -
-
- parse_response_token(url, state=None) -
-
-

Parse the response code in the given response url

-
-
- -
-
- validate_token(token_info) -
-
-
- -
-
-
- -
-
- class spotipy.oauth2.SpotifyOAuth(client_id=None, client_secret=None, - redirect_uri=None, - state=None, - scope=None, - cache_path=None, - username=None, - proxies=None, - show_dialog=False, - requests_session=True, requests_timeout=None, open_browser=True, - cache_handler=None) -
-
-

Bases: SpotifyAuthBase -

-

Implements Authorization Code Flow for Spotify’s OAuth implementation.

-
-
- OAUTH_AUTHORIZE_URL = 'https://accounts.spotify.com/authorize' -
-
-
- -
-
- OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token' -
-
-
- -
-
- __init__(client_id=None, client_secret=None, redirect_uri=None, state=None, scope=None, cache_path=None, username=None, proxies=None, show_dialog=False, requests_session=True, requests_timeout=None, open_browser=True, cache_handler=None) -
-
-

Creates a SpotifyOAuth object

-
-
Parameters:
-
-
    -
  • -

    client_id: Must be supplied or set as environment variable

    -
  • -
  • -

    client_secret: Must be supplied or set as environment variable

    -
  • -
  • -

    redirect_uri: Must be supplied or set as environment variable

    -
  • -
  • -

    state: Optional, no verification is performed

    -
  • -
  • -
    -
    scope: Optional, either a list of scopes or comma separated string of scopes.
    -
    -

    e.g, “playlist-read-private,playlist-read-collaborative”

    -
    -
    -
  • -
  • -
    -
    cache_path: (deprecated) Optional, will otherwise be generated
    -
    -

    (takes precedence over username)

    -
    -
    -
  • -
  • -
    -
    username: (deprecated) Optional or set as environment variable
    -
    -

    (will set cache_path to .cache-{username})

    -
    -
    -
  • -
  • -

    proxies: Optional, proxy for the requests library to route through

    -
  • -
  • -

    show_dialog: Optional, interpreted as boolean

    -
  • -
  • -

    requests_session: A Requests session

    -
  • -
  • -
    -
    requests_timeout: Optional, tell Requests to stop waiting for a response after
    -
    -

    a given number of seconds

    -
    -
    -
  • -
  • -
    -
    open_browser: Optional, whether or not the web browser should be opened to
    -
    -

    authorize a user

    -
    -
    -
  • -
  • -
    -
    cache_handler: An instance of the CacheHandler class to handle
    -
    -

    getting and saving cached authorization tokens. - Optional, will otherwise use CacheFileHandler. - (takes precedence over cache_path and username)

    -
    -
    -
  • -
-
-
-
-
- -
-
- get_access_token(code=None, as_dict=True, check_cache=True) -
-
-

Gets the access token for the app given the code

-
-
Parameters:
-
-
    -
  • -

    code - the response code

    -
  • -
  • -
    -
    as_dict - a boolean indicating if returning the access token
    -
    -

    as a token_info dictionary, otherwise it will be returned - as a string.

    -
    -
    -
  • -
-
-
-
-
- -
-
- get_auth_response(open_browser=None) -
-
-
- -
-
- get_authorization_code(response=None) -
-
-
- -
-
- get_authorize_url(state=None) -
-
-

Gets the URL to use to authorize this app

-
-
- -
-
- get_cached_token() -
-
-
- -
-
- static parse_auth_response_url(url) -
-
-
- -
-
- parse_response_code(url) -
-
-

Parse the response code in the given response url

-
-
Parameters:
-
-
    -
  • -

    url - the response url

    -
  • -
-
-
-
-
- -
-
- refresh_access_token(refresh_token) -
-
-
- -
-
- validate_token(token_info) -
-
-
- -
-
- -
-
- exception spotipy.oauth2.SpotifyOauthError(message, error=None, error_description=None, - *args, **kwargs) -
-
-

Bases: Exception

-

Error during Auth Code or Implicit Grant flow

-
-
- __init__(message, error=None, error_description=None, *args, **kwargs) -
-
-
- -
-
- -
-
- class spotipy.oauth2.SpotifyPKCE(client_id=None, redirect_uri=None, - state=None, - scope=None, - cache_path=None, - username=None, - proxies=None, - requests_timeout=None, requests_session=True, open_browser=True, - cache_handler=None) -
-
-

Bases: SpotifyAuthBase -

-

Implements PKCE Authorization Flow for client apps

-

This auth manager enables user and non-user endpoints with only - a client ID, redirect URI, and username. When the app requests - an access token for the first time, the user is prompted to - authorize the new client app. After authorizing the app, the client - app is then given both access and refresh tokens. This is the - preferred way of authorizing a mobile/desktop client.

-
-
- OAUTH_AUTHORIZE_URL = 'https://accounts.spotify.com/authorize' -
-
-
- -
-
- OAUTH_TOKEN_URL = 'https://accounts.spotify.com/api/token' -
-
-
- -
-
- __init__(client_id=None, redirect_uri=None, state=None, scope=None, cache_path=None, username=None, proxies=None, requests_timeout=None, requests_session=True, open_browser=True, cache_handler=None) -
-
-

Creates Auth Manager with the PKCE Auth flow.

-
-
Parameters:
-
-
    -
  • -

    client_id: Must be supplied or set as environment variable

    -
  • -
  • -

    redirect_uri: Must be supplied or set as environment variable

    -
  • -
  • -

    state: Optional, no verification is performed

    -
  • -
  • -
    -
    scope: Optional, either a list of scopes or comma separated string of scopes.
    -
    -

    e.g, “playlist-read-private,playlist-read-collaborative”

    -
    -
    -
  • -
  • -
    -
    cache_path: (deprecated) Optional, will otherwise be generated
    -
    -

    (takes precedence over username)

    -
    -
    -
  • -
  • -
    -
    username: (deprecated) Optional or set as environment variable
    -
    -

    (will set cache_path to .cache-{username})

    -
    -
    -
  • -
  • -

    proxies: Optional, proxy for the requests library to route through

    -
  • -
  • -
    -
    requests_timeout: Optional, tell Requests to stop waiting for a response after
    -
    -

    a given number of seconds

    -
    -
    -
  • -
  • -

    requests_session: A Requests session

    -
  • -
  • -
    -
    open_browser: Optional, whether or not the web browser should be opened to
    -
    -

    authorize a user

    -
    -
    -
  • -
  • -
    -
    cache_handler: An instance of the CacheHandler class to handle
    -
    -

    getting and saving cached authorization tokens. - Optional, will otherwise use CacheFileHandler. - (takes precedence over cache_path and username)

    -
    -
    -
  • -
-
-
-
-
- -
-
- get_access_token(code=None, check_cache=True) -
-
-

Gets the access token for the app

-

If the code is not given and no cached token is used, an - authentication window will be shown to the user to get a new - code.

-
-
Parameters:
-
-
    -
  • -

    code - the response code from authentication

    -
  • -
  • -
    -
    check_cache - if true, checks for a locally stored token
    -
    -

    before requesting a new token

    -
    -
    -
  • -
-
-
-
-
- -
-
- get_authorization_code(response=None) -
-
-
- -
-
- get_authorize_url(state=None) -
-
-

Gets the URL to use to authorize this app

-
-
- -
-
- get_cached_token() -
-
-
- -
-
- get_pkce_handshake_parameters() -
-
-
- -
-
- static parse_auth_response_url(url) -
-
-
- -
-
- parse_response_code(url) -
-
-

Parse the response code in the given response url

-
-
Parameters:
-
-
    -
  • -

    url - the response url

    -
  • -
-
-
-
-
- -
-
- refresh_access_token(refresh_token) -
-
-
- -
-
- validate_token(token_info) -
-
-
- -
-
- -
-
- exception spotipy.oauth2.SpotifyStateError(local_state=None, remote_state=None, - message=None, - error=None, - error_description=None, *args, **kwargs) -
-
-

Bases: SpotifyOauthError -

-

The state sent and state received were different

-
-
- __init__(local_state=None, remote_state=None, message=None, error=None, error_description=None, *args, **kwargs) -
-
-
- -
-
- -
- -

util - Module

-

Shows a user’s playlists (need to be authenticated via oauth)

-
-
- spotipy.util.prompt_for_user_token(username=None, scope=None, client_id=None, client_secret=None, redirect_uri=None, cache_path=None, oauth_manager=None, show_dialog=False) -
-
-
- -
-
-
-

Support

-

You can ask questions about Spotipy on Stack Overflow. Don’t forget to add the - Spotipy tag, and any other relevant tags as well, before posting. -

-
- -
-

If you think you’ve found a bug, let us know at - Spotify Issues -

-
-
-

Troubleshooting -

-

This section aims to address common issues that users may encounter while working with Spotipy and - provide practical solutions to resolve them.

-

Authentication errors: Make sure that you have correctly set up your credentials and are - using the correct authorization flow to avoid authenthication erros. Ensure that your client ID and client - secret are correct and that you have added the appropriate redirect URIs to your Spotify Developer - Dashboard.

-

Playlist creation errors: If you’re having trouble creating a playlist, check that your - user ID is correct, and that the user has the necessary permissions to create playlists. Additionally, - make sure that your code is formatted correctly, along with the fact that you are sending the appropriate - request to the Spotify API.

-

Search errors: If you’re having problems when searching for music, make sure that you - are providing the correct search query parameters. You should also check the Spotify API documentation to - ensure that the endpoint you’re using supports the search parameters you are providing.

-

API changes: Sometimes the Spotify API may change, causing errors in your application. - To fix this, check the Spotify API documentation to see if there are any changes that may affect your code - and update it accordingly.

-

Rate limiting: Making too many requests to the Spotify API within a short period of - time, will result in you hitting the rate limit. To prevent this, use caching and backoff mechanisms in - your code

-

Authorization errors: If you encounter authorization errors, make sure that you have - correctly set up your credentials and are using the correct authorization flow. You may also need to check - if your access token has expired and obtain a new one if necessary.

-
-
-

Contribute

-

Spotipy authored by Paul Lamere (plamere) with contributions by:

-
-
- -
-
-

If you are a developer with Python experience, and you would like to contribute to Spotipy, please - be sure to follow the guidelines listed below:

-
-
Export the needed Environment variables:::
-
-

export SPOTIPY_CLIENT_ID=client_id_here - export SPOTIPY_CLIENT_SECRET=client_secret_here - export SPOTIPY_CLIENT_USERNAME=client_username_here # This is actually an id not spotify display name - export SPOTIPY_REDIRECT_URI=http://localhost:8080 # Make url is set in app you created to get your ID - and SECRET

-
-
Create virtual environment, install dependencies, run tests:::
-
-

$ virtualenv –python=python3.7 env - (env) $ pip install –user -e . - (env) $ python -m unittest discover -v tests

-
-
-

Lint

-
-
To automatically fix the code style:::
-
-

pip install autopep8 - autopep8 –in-place –aggressive –recursive .

-
-
To verify the code style:::
-
-

pip install flake8 - flake8 .

-
-
To make sure if the import lists are stored correctly:::
-
-

pip install isort - isort . -c -v

-
-
-

Publishing (by maintainer)

-
    -
  • -

    Bump version in setup.py

    -
  • -
  • -

    Bump and date changelog

    -
  • -
  • -

    Add to changelog:

    -
  • -
-
-
::
-
-

## Unreleased

-

// Add your changes here and then delete this line

-
-
-
    -
  • -

    Commit changes

    -
  • -
  • -

    Package to pypi:

    -
  • -
-
-
::
-
-

python setup.py sdist bdist_wheel - python3 setup.py sdist bdist_wheel - twine check dist/* - twine upload –repository-url https://upload.pypi.org/legacy/ –skip-existing - dist/.(whl|gz|zip)~dist/*linux.whl

-
-
-
    -
  • -

    Create github release https://github.com/plamere/spotipy/releases - with the changelog content for the version and a short name that describes the main addition

    -
  • -
  • -

    Build the documentation again to ensure it’s on the latest version

    -
  • -
-

Changelog

-

Don’t forget to add a short description of your change in the CHANGELOG!

-
-
-

License

-

(Taken from https://github.com/plamere/spotipy/blob/master/LICENSE.md): -

-
-
-
MIT License
-Copyright (c) 2021 Paul Lamere
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
-(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
-publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
-IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-
-
-
-

Indices and tables

- -
- - -
-
-
-
- -
-
- - - - - \ No newline at end of file From 7f31bcccd05234240b8d57b2e645ed1d9d94f7bb Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:11:48 +0100 Subject: [PATCH 11/18] Delete objects.inv --- docs/objects.inv | Bin 1303 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/objects.inv diff --git a/docs/objects.inv b/docs/objects.inv deleted file mode 100644 index 9b23c413d35fa14d457e6cab9a5a8dabd7d11756..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1303 zcmV+y1?c)CAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk&aBp;J zaCr(NAXa5^b7^mGIv_GGFbX3eRA^-&a%F8{X>Md?av*PJAarPHb0B7EY-J#6b0A}H zZE$jBb8}^6Aa!$TZf78RY-wUH3V7PJnN4rwHV}sI`4ukOYmBzXy)A;E4YqB9%`OV` zLeS*MCQOkkNjY(UeTSkfTipbGC;|94D-=j@3rwlI%)UO&;bp| z)CZse(nhq{gEfRK?}G0jr2XZ9oitXiEFdLpfn)}SleqT507JZINJVGm-V*0f`Q9aD zD6dQZWlF)U`UICF`VjDX=*9{cA*B~1qK{=B8FJBhYyHb)lsY(;m%hO>Ze1UkFWIsoTc*0g2Z_?K7_RnLkASJ#AvS<`;x6zE-6JqwP!x+WZaU)O&AY^Z>phV2g)=?{SSN}be;@82!ATzgUFlAMCd!~rRJ`( zfKlD|ks&3=4C-MWR#d)i!D*R{cVZ1L;L-umkqx5}I^1dq!U!^`4Oz%I_d#QA$Dd=OjX$MO zkCSF6KV1Egjxbj3w=nYL&Qa_P=RdfB;Sbmtezi2`G1I0w?ETcI(wv-0fU31p(x7U% zk_=VCRl*z!Z!U=3ld1A&2D6Dn4QD%VdrAR%|Ei$N=}?x!baAcvs_(f|Gx1C>ZfA&d z12{I|bI$Vf6<@Q9;DEdv8n_Ff@t=_;Zl3wPeTJ}n{P^|Duj0$&r~5y|*U!IQc*1aw zdX3f3vDP`)Qy7FW%lBJw*E1j5&KhOXFPLAXt8F$@kM_!c9zQ?)bx*e0oJzOXoKx9W zg_pk)2f)`|gjzr!%s(LdU~2%CRGWOBTVuqX3=!sIuF=hcorqPsx|7ym$w;O>ejF>P ztK4BwRda(=8ZQVH65WxCp6@^>9G>IMLD^x-S%bRp82cQJxUP>Np4$~pHFrD3O(c$~ z0yN0kR9OvdPt8~NA^31%HuRpH;U7<*?(VM+7Fkp+R-C|ip<)2>EKwm)95EH#`x_Y1 zjV2DyxhG7w#o7#OeH}M)3j+O9BI&|X;tgiCcyU5whKqqzCt3_BZm@VxD5eLCqx>ot z>65Wn6gK(wWfy$g5m?=xY!S2WM% N`IB73&A+!of_p&@b(H`B From 391ff3ef0e2bf0fea052a23997ac51d7c86b5a25 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:12:05 +0100 Subject: [PATCH 12/18] Delete py-modindex.html --- docs/py-modindex.html | 113 ------------------------------------------ 1 file changed, 113 deletions(-) delete mode 100644 docs/py-modindex.html diff --git a/docs/py-modindex.html b/docs/py-modindex.html deleted file mode 100644 index 71c59501..00000000 --- a/docs/py-modindex.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - Python Module Index — spotipy 2.0 documentation - - - - - - - - - - - - - - - -
-
-
-
- - -

Python Module Index

- -
- s -
- - - - - - - - - - - - - - - - -
 
- s
- spotipy -
    - spotipy.client -
    - spotipy.oauth2 -
    - spotipy.util -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file From b48a0e71ea1359d727d5b39d2fdbb702d329d53b Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:12:19 +0100 Subject: [PATCH 13/18] Delete search.html --- docs/search.html | 102 ----------------------------------------------- 1 file changed, 102 deletions(-) delete mode 100644 docs/search.html diff --git a/docs/search.html b/docs/search.html deleted file mode 100644 index a97601bf..00000000 --- a/docs/search.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - Search — spotipy 2.0 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Search

- - - - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - -
- - - -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file From 24b2e45588ce03a70dda3bded2101864775278aa Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 8 May 2023 20:12:32 +0100 Subject: [PATCH 14/18] Delete searchindex.js --- docs/searchindex.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/searchindex.js diff --git a/docs/searchindex.js b/docs/searchindex.js deleted file mode 100644 index 78fb8971..00000000 --- a/docs/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({"docnames": ["index"], "filenames": ["index.rst"], "titles": ["Welcome to Spotipy!"], "terms": {"i": 0, "lightweight": 0, "python": 0, "librari": 0, "spotifi": 0, "web": 0, "With": 0, "you": 0, "full": 0, "access": 0, "all": 0, "music": 0, "data": 0, "provid": 0, "platform": 0, "assum": 0, "set": 0, "spotipy_client_id": 0, "spotipy_client_secret": 0, "environ": 0, "variabl": 0, "here": 0, "video": 0, "explain": 0, "how": 0, "do": 0, "so": 0, "For": 0, "longer": 0, "tutori": 0, "includ": 0, "thi": 0, "playlist": 0, "below": 0, "us": 0, "list": 0, "name": 0, "album": 0, "releas": 0, "artist": 0, "birdi": 0, "import": 0, "from": 0, "spotifyclientcredenti": 0, "birdy_uri": 0, "2wx2utcsvv5ons0inacecp": 0, "client_credentials_manag": 0, "result": 0, "artist_album": 0, "album_typ": 0, "item": 0, "while": 0, "next": 0, "extend": 0, "print": 0, "": 0, "anoth": 0, "show": 0, "30": 0, "second": 0, "sampl": 0, "cover": 0, "art": 0, "top": 0, "10": 0, "track": 0, "led": 0, "zeppelin": 0, "lz_uri": 0, "36qjpde2go2kgarlehcdtp": 0, "artist_top_track": 0, "audio": 0, "preview_url": 0, "imag": 0, "0": 0, "final": 0, "an": 0, "given": 0, "sy": 0, "auth_manag": 0, "len": 0, "argv": 0, "1": 0, "join": 0, "els": 0, "radiohead": 0, "search": 0, "q": 0, "type": 0, "end": 0, "point": 0, "detail": 0, "capabl": 0, "ar": 0, "encourag": 0, "review": 0, "document": 0, "window": 0, "download": 0, "offici": 0, "websit": 0, "http": 0, "www": 0, "org": 0, "open": 0, "command": 0, "prompt": 0, "run": 0, "pip": 0, "follow": 0, "authent": 0, "your": 0, "app": 0, "regist": 0, "develop": 0, "dashboard": 0, "obtain": 0, "secret": 0, "maco": 0, "homebrew": 0, "packag": 0, "manag": 0, "followng": 0, "bin": 0, "bash": 0, "c": 0, "curl": 0, "fssl": 0, "raw": 0, "githubusercont": 0, "com": 0, "head": 0, "sh": 0, "brew": 0, "termin": 0, "linux": 0, "distribut": 0, "sudo": 0, "apt": 0, "python3": 0, "can": 0, "sourc": 0, "github": 0, "plamer": 0, "befor": 0, "few": 0, "thing": 0, "need": 0, "To": 0, "make": 0, "call": 0, "my": 0, "applic": 0, "_": 0, "sure": 0, "keep": 0, "choos": 0, "two": 0, "one": 0, "suitabl": 0, "method": 0, "long": 0, "which": 0, "log": 0, "onc": 0, "It": 0, "refresh": 0, "requir": 0, "add": 0, "see": 0, "more": 0, "The": 0, "short": 0, "live": 0, "don": 0, "t": 0, "permiss": 0, "possibl": 0, "request": 0, "higher": 0, "rate": 0, "limit": 0, "than": 0, "would": 0, "give": 0, "ll": 0, "grant": 0, "onli": 0, "sinc": 0, "exchang": 0, "involv": 0, "send": 0, "kei": 0, "perform": 0, "locat": 0, "like": 0, "backend": 0, "servic": 0, "browser": 0, "mobil": 0, "class": 0, "spotifyoauth": 0, "read": 0, "sp": 0, "current_user_saved_track": 0, "idx": 0, "enumer": 0, "reluct": 0, "immort": 0, "env": 0, "instead": 0, "export": 0, "spotipy_redirect_uri": 0, "inform": 0, "about": 0, "navig": 0, "edit": 0, "redirect_uri": 0, "argument": 0, "must": 0, "match": 0, "ad": 0, "ani": 0, "valid": 0, "doe": 0, "localhost": 0, "127": 0, "9090": 0, "If": 0, "scheme": 0, "AND": 0, "specifi": 0, "port": 0, "instanti": 0, "server": 0, "respons": 0, "receiv": 0, "oauth": 0, "blob": 0, "master": 0, "py": 0, "l483": 0, "l490": 0, "endpoint": 0, "advantag": 0, "comparison": 0, "made": 0, "without": 0, "appli": 0, "As": 0, "oppos": 0, "mean": 0, "never": 0, "sign": 0, "page": 0, "user_playlist": 0, "4d": 0, "offset": 0, "none": 0, "number": 0, "differ": 0, "resourc": 0, "identifi": 0, "enter": 0, "desktop": 0, "box": 0, "6rqhfgbbkwnb9mlmuqdhg6": 0, "html": 0, "link": 0, "other": 0, "A": 0, "base": 0, "62": 0, "find": 0, "abov": 0, "etc": 0, "In": 0, "gener": 0, "accept": 0, "form": 0, "automat": 0, "store": 0, "default": 0, "project": 0, "main": 0, "folder": 0, "might": 0, "suit": 0, "everyon": 0, "wai": 0, "creat": 0, "handler": 0, "cache_handl": 0, "inherit": 0, "cachehandl": 0, "cachefilehandl": 0, "good": 0, "instanc": 0, "new": 0, "pass": 0, "when": 0, "spotifypkc": 0, "spotifyimplicitgr": 0, "avail": 0, "defin": 0, "memorycachehandl": 0, "djangosessioncachehandl": 0, "flasksessioncachehandl": 0, "rediscachehandl": 0, "feel": 0, "free": 0, "repo": 0, "section": 0, "we": 0, "step": 0, "some": 0, "essenti": 0, "retriev": 0, "object": 0, "client_id": 0, "your_client_id": 0, "client_secret": 0, "your_client_secret": 0, "your_redirect_uri": 0, "current_us": 0, "user_data": 0, "variou": 0, "piec": 0, "dictionari": 0, "displai": 0, "display_nam": 0, "chocol": 0, "contain": 0, "return": 0, "each": 0, "track_nam": 0, "There": 0, "mani": 0, "directori": 0, "simpl": 0, "thin": 0, "auth": 0, "requests_sess": 0, "true": 0, "oauth_manag": 0, "proxi": 0, "requests_timeout": 0, "5": 0, "status_forcelist": 0, "retri": 0, "3": 0, "status_retri": 0, "backoff_factor": 0, "languag": 0, "usag": 0, "urn": 0, "3jostutkeu2jkjvrdba5gu": 0, "__init__": 0, "option": 0, "session": 0, "truthi": 0, "valu": 0, "falsi": 0, "disabl": 0, "should": 0, "idea": 0, "enabl": 0, "reason": 0, "connect": 0, "pool": 0, "definit": 0, "doc": 0, "2": 0, "en": 0, "advanc": 0, "tell": 0, "stop": 0, "wait": 0, "after": 0, "what": 0, "statu": 0, "occur": 0, "total": 0, "allow": 0, "time": 0, "bad": 0, "backoff": 0, "factor": 0, "between": 0, "attempt": 0, "try": 0, "urllib3": 0, "readthedoc": 0, "io": 0, "latest": 0, "advertis": 0, "prefer": 0, "iso": 0, "639": 0, "wikipedia": 0, "wiki": 0, "list_of_iso_639": 0, "1_code": 0, "add_to_queu": 0, "device_id": 0, "song": 0, "queue": 0, "devic": 0, "current": 0, "plai": 0, "b": 0, "player": 0, "fail": 0, "restrict": 0, "violat": 0, "error": 0, "therefor": 0, "recommend": 0, "leav": 0, "activ": 0, "target": 0, "album_id": 0, "market": 0, "singl": 0, "3166": 0, "alpha": 0, "countri": 0, "album_track": 0, "50": 0, "catalog": 0, "index": 0, "first": 0, "artist_id": 0, "20": 0, "appears_on": 0, "compil": 0, "particular": 0, "artist_related_artist": 0, "similar": 0, "analysi": 0, "commun": 0, "listen": 0, "histori": 0, "u": 0, "audio_analysi": 0, "track_id": 0, "upon": 0, "its": 0, "audio_featur": 0, "multipl": 0, "maximum": 0, "100": 0, "properti": 0, "available_market": 0, "where": 0, "addit": 0, "special": 0, "territori": 0, "categori": 0, "local": 0, "desir": 0, "consist": 0, "underscor": 0, "minimum": 0, "category_id": 0, "info": 0, "category_playlist": 0, "specif": 0, "country_cod": 0, "au": 0, "AT": 0, "BE": 0, "bo": 0, "br": 0, "bg": 0, "ca": 0, "cl": 0, "co": 0, "cr": 0, "cy": 0, "cz": 0, "dk": 0, "ec": 0, "sv": 0, "ee": 0, "fi": 0, "fr": 0, "de": 0, "gr": 0, "gt": 0, "hn": 0, "hk": 0, "hu": 0, "ie": 0, "IT": 0, "jp": 0, "lv": 0, "li": 0, "lt": 0, "lu": 0, "mt": 0, "mx": 0, "mc": 0, "nl": 0, "nz": 0, "ni": 0, "NO": 0, "pa": 0, "pe": 0, "ph": 0, "pl": 0, "pt": 0, "sg": 0, "e": 0, "sk": 0, "se": 0, "ch": 0, "tw": 0, "tr": 0, "gb": 0, "ui": 0, "current_playback": 0, "additional_typ": 0, "playback": 0, "episod": 0, "podcast": 0, "profil": 0, "alia": 0, "me": 0, "current_user_follow_playlist": 0, "playlist_id": 0, "current_user_followed_artist": 0, "last": 0, "previou": 0, "current_user_following_artist": 0, "check": 0, "certain": 0, "boolean": 0, "respect": 0, "current_user_following_us": 0, "current_user_playing_track": 0, "current_user_playlist": 0, "hi": 0, "current_user_recently_plai": 0, "recent": 0, "entiti": 0, "unix": 0, "timestamp": 0, "millisecond": 0, "cursor": 0, "posit": 0, "cannot": 0, "current_user_saved_album": 0, "save": 0, "max_limit": 0, "current_user_saved_albums_add": 0, "current_user_saved_albums_contain": 0, "alreadi": 0, "current_user_saved_albums_delet": 0, "remov": 0, "current_user_saved_episod": 0, "current_user_saved_episodes_add": 0, "current_user_saved_episodes_contain": 0, "current_user_saved_episodes_delet": 0, "current_user_saved_show": 0, "current_user_saved_shows_add": 0, "current_user_saved_shows_contain": 0, "current_user_saved_shows_delet": 0, "current_user_saved_tracks_add": 0, "current_user_saved_tracks_contain": 0, "current_user_saved_tracks_delet": 0, "current_user_top_artist": 0, "time_rang": 0, "medium_term": 0, "over": 0, "frame": 0, "affin": 0, "comput": 0, "short_term": 0, "long_term": 0, "current_user_top_track": 0, "current_user_unfollow_playlist": 0, "unfollow": 0, "delet": 0, "currently_plai": 0, "default_retry_cod": 0, "429": 0, "500": 0, "502": 0, "503": 0, "504": 0, "episode_id": 0, "take": 0, "preced": 0, "neither": 0, "nor": 0, "content": 0, "consid": 0, "unavail": 0, "featured_playlist": 0, "lowercas": 0, "uppercas": 0, "8601": 0, "format": 0, "yyyi": 0, "mm": 0, "ddthh": 0, "ss": 0, "tailor": 0, "date": 0, "dai": 0, "max_retri": 0, "new_releas": 0, "previous": 0, "next_track": 0, "skip": 0, "pause_playback": 0, "paus": 0, "field": 0, "string": 0, "from_token": 0, "playlist_add_item": 0, "playlist_change_detail": 0, "public": 0, "collabor": 0, "descript": 0, "chang": 0, "privat": 0, "state": 0, "playlist_cover_imag": 0, "playlist_is_follow": 0, "user_id": 0, "want": 0, "thei": 0, "playlist_item": 0, "playlist_remove_all_occurrences_of_item": 0, "snapshot_id": 0, "occurr": 0, "snapshot": 0, "playlist_remove_specific_occurrences_of_item": 0, "arrai": 0, "4iv5w9uyedyuva79axb7rh": 0, "1301wleyt98msxvhpzca6m": 0, "7": 0, "playlist_reorder_item": 0, "range_start": 0, "insert_befor": 0, "range_length": 0, "reorder": 0, "insert": 0, "playlist_replace_item": 0, "replac": 0, "compris": 0, "playlist_track": 0, "playlist_upload_cover_imag": 0, "image_b64": 0, "repres": 0, "base64": 0, "encod": 0, "jpeg": 0, "payload": 0, "size": 0, "256": 0, "kb": 0, "previous_track": 0, "recommendation_genre_se": 0, "genr": 0, "function": 0, "seed_artist": 0, "seed_genr": 0, "seed_track": 0, "kwarg": 0, "five": 0, "seed": 0, "least": 0, "found": 0, "playabl": 0, "min": 0, "max": 0, "target_": 0, "attribut": 0, "tuneabl": 0, "filter": 0, "repeat": 0, "mode": 0, "context": 0, "off": 0, "queri": 0, "write": 0, "noqa": 0, "within": 0, "One": 0, "comma": 0, "separ": 0, "g": 0, "search_market": 0, "experiment": 0, "done": 0, "across": 0, "seek_track": 0, "position_m": 0, "seek": 0, "set_auth": 0, "show_id": 0, "show_episod": 0, "shuffl": 0, "toggl": 0, "fals": 0, "start_playback": 0, "context_uri": 0, "resum": 0, "int": 0, "greater": 0, "length": 0, "caus": 0, "transfer_playback": 0, "force_plai": 0, "transfer": 0, "note": 0, "actual": 0, "basic": 0, "usr": 0, "user_follow_artist": 0, "user_follow_us": 0, "user_playlist_add_episod": 0, "user_playlist_add_track": 0, "user_playlist_change_detail": 0, "user_playlist_cr": 0, "user_playlist_follow_playlist": 0, "playlist_owner_id": 0, "owner": 0, "user_playlist_is_follow": 0, "user_playlist_remove_all_occurrences_of_track": 0, "user_playlist_remove_specific_occurrences_of_track": 0, "user_playlist_reorder_track": 0, "user_playlist_replace_track": 0, "user_playlist_track": 0, "user_playlist_unfollow": 0, "user_unfollow_artist": 0, "user_unfollow_us": 0, "volum": 0, "volume_perc": 0, "except": 0, "spotifyexcept": 0, "http_statu": 0, "msg": 0, "header": 0, "spotifyauthbas": 0, "oauth_token_url": 0, "account": 0, "howev": 0, "interact": 0, "either": 0, "constructor": 0, "suppli": 0, "rout": 0, "through": 0, "handl": 0, "otherwis": 0, "cache_path": 0, "usernam": 0, "get_access_token": 0, "as_dict": 0, "check_cach": 0, "memori": 0, "fetch": 0, "token_info": 0, "show_dialog": 0, "implement": 0, "implicit": 0, "non": 0, "copi": 0, "past": 0, "everi": 0, "hour": 0, "standard": 0, "side": 0, "ha": 0, "suggest": 0, "pkce": 0, "extens": 0, "plu": 0, "get_auth_respons": 0, "access_token": 0, "get_authorization_cod": 0, "get_cached_token": 0, "parse_response_token": 0, "parse_response_cod": 0, "concern": 0, "intercept": 0, "proof": 0, "origin": 0, "could": 0, "easili": 0, "compromis": 0, "network": 0, "oauth_authorize_url": 0, "help": 0, "mai": 0, "verif": 0, "deprec": 0, "interpret": 0, "overrid": 0, "self": 0, "break": 0, "expir": 0, "get_authorize_url": 0, "static": 0, "parse_auth_response_url": 0, "pars": 0, "validate_token": 0, "open_brows": 0, "whether": 0, "refresh_access_token": 0, "refresh_token": 0, "spotifyoautherror": 0, "messag": 0, "error_descript": 0, "arg": 0, "dure": 0, "both": 0, "shown": 0, "get_pkce_handshake_paramet": 0, "spotifystateerror": 0, "local_st": 0, "remote_st": 0, "sent": 0, "were": 0, "via": 0, "prompt_for_user_token": 0, "ask": 0, "question": 0, "stack": 0, "overflow": 0, "forget": 0, "tag": 0, "relev": 0, "well": 0, "post": 0, "stackoverflow": 0, "think": 0, "ve": 0, "bug": 0, "let": 0, "know": 0, "issu": 0, "aim": 0, "address": 0, "common": 0, "encount": 0, "work": 0, "practic": 0, "solut": 0, "resolv": 0, "them": 0, "have": 0, "correctli": 0, "up": 0, "correct": 0, "avoid": 0, "authenth": 0, "erro": 0, "ensur": 0, "appropri": 0, "creation": 0, "re": 0, "troubl": 0, "necessari": 0, "addition": 0, "along": 0, "fact": 0, "problem": 0, "also": 0, "sometim": 0, "fix": 0, "affect": 0, "updat": 0, "accordingli": 0, "too": 0, "period": 0, "hit": 0, "prevent": 0, "mechan": 0, "paul": 0, "lamer": 0, "daniel": 0, "beaudri": 0, "danbeaudri": 0, "faruk": 0, "emr": 0, "sahin": 0, "fsahin": 0, "georg": 0, "rogueleaderr": 0, "henri": 0, "grevil": 0, "sethauru": 0, "hugo": 0, "van": 0, "kemanad": 0, "hugovk": 0, "jos\u00e9": 0, "manuel": 0, "p\u00e9rez": 0, "jmperez": 0, "luca": 0, "nunno": 0, "lnunno": 0, "lynn": 0, "root": 0, "econchick": 0, "matt": 0, "dennewitz": 0, "mattdennewitz": 0, "matthew": 0, "duck": 0, "mattduck": 0, "michael": 0, "thelin": 0, "thelinmichael": 0, "ryan": 0, "choi": 0, "ryankick": 0, "simon": 0, "metson": 0, "drsm79": 0, "steve": 0, "winton": 0, "swinton": 0, "tim": 0, "balzer": 0, "timbalz": 0, "corycorycori": 0, "nathan": 0, "coleman": 0, "nathancoleman": 0, "birtwel": 0, "mbirtwel": 0, "harrison": 0, "hay": 0, "harrison97": 0, "stephan": 0, "bruckert": 0, "stephanebruckert": 0, "ritiek": 0, "malhotra": 0, "experi": 0, "pleas": 0, "guidelin": 0, "client_id_her": 0, "client_secret_her": 0, "spotipy_client_usernam": 0, "client_username_her": 0, "8080": 0, "virtual": 0, "depend": 0, "test": 0, "virtualenv": 0, "m": 0, "unittest": 0, "discov": 0, "v": 0, "lint": 0, "style": 0, "autopep8": 0, "place": 0, "aggress": 0, "recurs": 0, "verifi": 0, "flake8": 0, "isort": 0, "publish": 0, "maintain": 0, "bump": 0, "version": 0, "setup": 0, "changelog": 0, "unreleas": 0, "line": 0, "commit": 0, "pypi": 0, "sdist": 0, "bdist_wheel": 0, "twine": 0, "dist": 0, "upload": 0, "repositori": 0, "legaci": 0, "exist": 0, "whl": 0, "gz": 0, "zip": 0, "describ": 0, "build": 0, "again": 0, "taken": 0, "md": 0, "mit": 0, "copyright": 0, "2021": 0, "herebi": 0, "charg": 0, "person": 0, "softwar": 0, "associ": 0, "file": 0, "deal": 0, "right": 0, "modifi": 0, "merg": 0, "sublicens": 0, "sell": 0, "permit": 0, "whom": 0, "furnish": 0, "subject": 0, "condit": 0, "notic": 0, "shall": 0, "substanti": 0, "portion": 0, "THE": 0, "AS": 0, "warranti": 0, "OF": 0, "kind": 0, "express": 0, "OR": 0, "impli": 0, "BUT": 0, "NOT": 0, "TO": 0, "merchant": 0, "fit": 0, "FOR": 0, "purpos": 0, "noninfring": 0, "IN": 0, "event": 0, "holder": 0, "liabl": 0, "claim": 0, "damag": 0, "liabil": 0, "action": 0, "contract": 0, "tort": 0, "aris": 0, "out": 0, "WITH": 0}, "objects": {"spotipy": [[0, 0, 0, "-", "client"], [0, 0, 0, "-", "oauth2"], [0, 0, 0, "-", "util"]], "spotipy.client": [[0, 1, 1, "", "Spotify"], [0, 5, 1, "", "SpotifyException"]], "spotipy.client.Spotify": [[0, 2, 1, "", "__init__"], [0, 2, 1, "", "add_to_queue"], [0, 2, 1, "", "album"], [0, 2, 1, "", "album_tracks"], [0, 2, 1, "", "albums"], [0, 2, 1, "", "artist"], [0, 2, 1, "", "artist_albums"], [0, 2, 1, "", "artist_related_artists"], [0, 2, 1, "", "artist_top_tracks"], [0, 2, 1, "", "artists"], [0, 2, 1, "", "audio_analysis"], [0, 2, 1, "", "audio_features"], [0, 3, 1, "", "auth_manager"], [0, 2, 1, "", "available_markets"], [0, 2, 1, "", "categories"], [0, 2, 1, "", "category"], [0, 2, 1, "", "category_playlists"], [0, 4, 1, "", "country_codes"], [0, 2, 1, "", "current_playback"], [0, 2, 1, "", "current_user"], [0, 2, 1, "", "current_user_follow_playlist"], [0, 2, 1, "", "current_user_followed_artists"], [0, 2, 1, "", "current_user_following_artists"], [0, 2, 1, "", "current_user_following_users"], [0, 2, 1, "", "current_user_playing_track"], [0, 2, 1, "", "current_user_playlists"], [0, 2, 1, "", "current_user_recently_played"], [0, 2, 1, "", "current_user_saved_albums"], [0, 2, 1, "", "current_user_saved_albums_add"], [0, 2, 1, "", "current_user_saved_albums_contains"], [0, 2, 1, "", "current_user_saved_albums_delete"], [0, 2, 1, "", "current_user_saved_episodes"], [0, 2, 1, "", "current_user_saved_episodes_add"], [0, 2, 1, "", "current_user_saved_episodes_contains"], [0, 2, 1, "", "current_user_saved_episodes_delete"], [0, 2, 1, "", "current_user_saved_shows"], [0, 2, 1, "", "current_user_saved_shows_add"], [0, 2, 1, "", "current_user_saved_shows_contains"], [0, 2, 1, "", "current_user_saved_shows_delete"], [0, 2, 1, "", "current_user_saved_tracks"], [0, 2, 1, "", "current_user_saved_tracks_add"], [0, 2, 1, "", "current_user_saved_tracks_contains"], [0, 2, 1, "", "current_user_saved_tracks_delete"], [0, 2, 1, "", "current_user_top_artists"], [0, 2, 1, "", "current_user_top_tracks"], [0, 2, 1, "", "current_user_unfollow_playlist"], [0, 2, 1, "", "currently_playing"], [0, 4, 1, "", "default_retry_codes"], [0, 2, 1, "", "devices"], [0, 2, 1, "", "episode"], [0, 2, 1, "", "episodes"], [0, 2, 1, "", "featured_playlists"], [0, 4, 1, "", "max_retries"], [0, 2, 1, "", "me"], [0, 2, 1, "", "new_releases"], [0, 2, 1, "", "next"], [0, 2, 1, "", "next_track"], [0, 2, 1, "", "pause_playback"], [0, 2, 1, "", "playlist"], [0, 2, 1, "", "playlist_add_items"], [0, 2, 1, "", "playlist_change_details"], [0, 2, 1, "", "playlist_cover_image"], [0, 2, 1, "", "playlist_is_following"], [0, 2, 1, "", "playlist_items"], [0, 2, 1, "", "playlist_remove_all_occurrences_of_items"], [0, 2, 1, "", "playlist_remove_specific_occurrences_of_items"], [0, 2, 1, "", "playlist_reorder_items"], [0, 2, 1, "", "playlist_replace_items"], [0, 2, 1, "", "playlist_tracks"], [0, 2, 1, "", "playlist_upload_cover_image"], [0, 2, 1, "", "previous"], [0, 2, 1, "", "previous_track"], [0, 2, 1, "", "queue"], [0, 2, 1, "", "recommendation_genre_seeds"], [0, 2, 1, "", "recommendations"], [0, 2, 1, "", "repeat"], [0, 2, 1, "", "search"], [0, 2, 1, "", "search_markets"], [0, 2, 1, "", "seek_track"], [0, 2, 1, "", "set_auth"], [0, 2, 1, "", "show"], [0, 2, 1, "", "show_episodes"], [0, 2, 1, "", "shows"], [0, 2, 1, "", "shuffle"], [0, 2, 1, "", "start_playback"], [0, 2, 1, "", "track"], [0, 2, 1, "", "tracks"], [0, 2, 1, "", "transfer_playback"], [0, 2, 1, "", "user"], [0, 2, 1, "", "user_follow_artists"], [0, 2, 1, "", "user_follow_users"], [0, 2, 1, "", "user_playlist"], [0, 2, 1, "", "user_playlist_add_episodes"], [0, 2, 1, "", "user_playlist_add_tracks"], [0, 2, 1, "", "user_playlist_change_details"], [0, 2, 1, "", "user_playlist_create"], [0, 2, 1, "", "user_playlist_follow_playlist"], [0, 2, 1, "", "user_playlist_is_following"], [0, 2, 1, "", "user_playlist_remove_all_occurrences_of_tracks"], [0, 2, 1, "", "user_playlist_remove_specific_occurrences_of_tracks"], [0, 2, 1, "", "user_playlist_reorder_tracks"], [0, 2, 1, "", "user_playlist_replace_tracks"], [0, 2, 1, "", "user_playlist_tracks"], [0, 2, 1, "", "user_playlist_unfollow"], [0, 2, 1, "", "user_playlists"], [0, 2, 1, "", "user_unfollow_artists"], [0, 2, 1, "", "user_unfollow_users"], [0, 2, 1, "", "volume"]], "spotipy.client.SpotifyException": [[0, 2, 1, "", "__init__"]], "spotipy.oauth2": [[0, 1, 1, "", "SpotifyClientCredentials"], [0, 1, 1, "", "SpotifyImplicitGrant"], [0, 1, 1, "", "SpotifyOAuth"], [0, 5, 1, "", "SpotifyOauthError"], [0, 1, 1, "", "SpotifyPKCE"], [0, 5, 1, "", "SpotifyStateError"]], "spotipy.oauth2.SpotifyClientCredentials": [[0, 4, 1, "", "OAUTH_TOKEN_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"]], "spotipy.oauth2.SpotifyImplicitGrant": [[0, 4, 1, "", "OAUTH_AUTHORIZE_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"], [0, 2, 1, "", "get_auth_response"], [0, 2, 1, "", "get_authorize_url"], [0, 2, 1, "", "get_cached_token"], [0, 2, 1, "", "parse_auth_response_url"], [0, 2, 1, "", "parse_response_token"], [0, 2, 1, "", "validate_token"]], "spotipy.oauth2.SpotifyOAuth": [[0, 4, 1, "", "OAUTH_AUTHORIZE_URL"], [0, 4, 1, "", "OAUTH_TOKEN_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"], [0, 2, 1, "", "get_auth_response"], [0, 2, 1, "", "get_authorization_code"], [0, 2, 1, "", "get_authorize_url"], [0, 2, 1, "", "get_cached_token"], [0, 2, 1, "", "parse_auth_response_url"], [0, 2, 1, "", "parse_response_code"], [0, 2, 1, "", "refresh_access_token"], [0, 2, 1, "", "validate_token"]], "spotipy.oauth2.SpotifyOauthError": [[0, 2, 1, "", "__init__"]], "spotipy.oauth2.SpotifyPKCE": [[0, 4, 1, "", "OAUTH_AUTHORIZE_URL"], [0, 4, 1, "", "OAUTH_TOKEN_URL"], [0, 2, 1, "", "__init__"], [0, 2, 1, "", "get_access_token"], [0, 2, 1, "", "get_authorization_code"], [0, 2, 1, "", "get_authorize_url"], [0, 2, 1, "", "get_cached_token"], [0, 2, 1, "", "get_pkce_handshake_parameters"], [0, 2, 1, "", "parse_auth_response_url"], [0, 2, 1, "", "parse_response_code"], [0, 2, 1, "", "refresh_access_token"], [0, 2, 1, "", "validate_token"]], "spotipy.oauth2.SpotifyStateError": [[0, 2, 1, "", "__init__"]], "spotipy.util": [[0, 6, 1, "", "prompt_for_user_token"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:property", "4": "py:attribute", "5": "py:exception", "6": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "property", "Python property"], "4": ["py", "attribute", "Python attribute"], "5": ["py", "exception", "Python exception"], "6": ["py", "function", "Python function"]}, "titleterms": {"welcom": 0, "spotipi": 0, "featur": 0, "instal": 0, "get": 0, "start": 0, "author": 0, "code": 0, "flow": 0, "quick": 0, "scope": 0, "redirect": 0, "uri": 0, "client": 0, "credenti": 0, "id": 0, "url": 0, "custom": 0, "token": 0, "cach": 0, "user": 0, "guid": 0, "exampl": 0, "api": 0, "refer": 0, "modul": 0, "oauth2": 0, "secur": 0, "warn": 0, "paramet": 0, "util": 0, "support": 0, "troubleshoot": 0, "contribut": 0, "licens": 0, "indic": 0, "tabl": 0}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Welcome to Spotipy!": [[0, "welcome-to-spotipy"]], "Features": [[0, "features"]], "Installation": [[0, "installation"]], "Getting Started with Spotipy": [[0, "getting-started-with-spotipy"]], "Authorization Code Flow": [[0, "authorization-code-flow"]], "Quick start": [[0, "quick-start"]], "Scopes": [[0, "scopes"]], "Redirect URI": [[0, "redirect-uri"]], "Client Credentials Flow": [[0, "client-credentials-flow"]], "IDs URIs and URLs": [[0, "ids-uris-and-urls"]], "Customized token caching": [[0, "customized-token-caching"]], "User Guide": [[0, "user-guide"]], "Examples": [[0, "examples"]], "API Reference": [[0, "api-reference"]], "client Module": [[0, "module-spotipy.client"]], "oauth2 Module": [[0, "module-spotipy.oauth2"]], "Security Warning": [[0, "security-warning"]], "Parameters": [[0, "parameters"], [0, "id3"]], "util Module": [[0, "module-spotipy.util"]], "Support": [[0, "support"]], "Troubleshooting": [[0, "troubleshooting"]], "Contribute": [[0, "contribute"]], "License": [[0, "license"]], "Indices and tables": [[0, "indices-and-tables"]]}, "indexentries": {"oauth_authorize_url (spotipy.oauth2.spotifyimplicitgrant attribute)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.OAUTH_AUTHORIZE_URL"]], "oauth_authorize_url (spotipy.oauth2.spotifyoauth attribute)": [[0, "spotipy.oauth2.SpotifyOAuth.OAUTH_AUTHORIZE_URL"]], "oauth_authorize_url (spotipy.oauth2.spotifypkce attribute)": [[0, "spotipy.oauth2.SpotifyPKCE.OAUTH_AUTHORIZE_URL"]], "oauth_token_url (spotipy.oauth2.spotifyclientcredentials attribute)": [[0, "spotipy.oauth2.SpotifyClientCredentials.OAUTH_TOKEN_URL"]], "oauth_token_url (spotipy.oauth2.spotifyoauth attribute)": [[0, "spotipy.oauth2.SpotifyOAuth.OAUTH_TOKEN_URL"]], "oauth_token_url (spotipy.oauth2.spotifypkce attribute)": [[0, "spotipy.oauth2.SpotifyPKCE.OAUTH_TOKEN_URL"]], "spotify (class in spotipy.client)": [[0, "spotipy.client.Spotify"]], "spotifyclientcredentials (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyClientCredentials"]], "spotifyexception": [[0, "spotipy.client.SpotifyException"]], "spotifyimplicitgrant (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyImplicitGrant"]], "spotifyoauth (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyOAuth"]], "spotifyoautherror": [[0, "spotipy.oauth2.SpotifyOauthError"]], "spotifypkce (class in spotipy.oauth2)": [[0, "spotipy.oauth2.SpotifyPKCE"]], "spotifystateerror": [[0, "spotipy.oauth2.SpotifyStateError"]], "__init__() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.__init__"]], "__init__() (spotipy.client.spotifyexception method)": [[0, "spotipy.client.SpotifyException.__init__"]], "__init__() (spotipy.oauth2.spotifyclientcredentials method)": [[0, "spotipy.oauth2.SpotifyClientCredentials.__init__"]], "__init__() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.__init__"]], "__init__() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.__init__"]], "__init__() (spotipy.oauth2.spotifyoautherror method)": [[0, "spotipy.oauth2.SpotifyOauthError.__init__"]], "__init__() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.__init__"]], "__init__() (spotipy.oauth2.spotifystateerror method)": [[0, "spotipy.oauth2.SpotifyStateError.__init__"]], "add_to_queue() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.add_to_queue"]], "album() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.album"]], "album_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.album_tracks"]], "albums() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.albums"]], "artist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist"]], "artist_albums() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist_albums"]], "artist_related_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist_related_artists"]], "artist_top_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artist_top_tracks"]], "artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.artists"]], "audio_analysis() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.audio_analysis"]], "audio_features() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.audio_features"]], "auth_manager (spotipy.client.spotify property)": [[0, "spotipy.client.Spotify.auth_manager"]], "available_markets() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.available_markets"]], "categories() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.categories"]], "category() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.category"]], "category_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.category_playlists"]], "country_codes (spotipy.client.spotify attribute)": [[0, "spotipy.client.Spotify.country_codes"]], "current_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_playback"]], "current_user() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user"]], "current_user_follow_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_follow_playlist"]], "current_user_followed_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_followed_artists"]], "current_user_following_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_following_artists"]], "current_user_following_users() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_following_users"]], "current_user_playing_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_playing_track"]], "current_user_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_playlists"]], "current_user_recently_played() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_recently_played"]], "current_user_saved_albums() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums"]], "current_user_saved_albums_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums_add"]], "current_user_saved_albums_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums_contains"]], "current_user_saved_albums_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_albums_delete"]], "current_user_saved_episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes"]], "current_user_saved_episodes_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes_add"]], "current_user_saved_episodes_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes_contains"]], "current_user_saved_episodes_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_episodes_delete"]], "current_user_saved_shows() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows"]], "current_user_saved_shows_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows_add"]], "current_user_saved_shows_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows_contains"]], "current_user_saved_shows_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_shows_delete"]], "current_user_saved_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks"]], "current_user_saved_tracks_add() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks_add"]], "current_user_saved_tracks_contains() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks_contains"]], "current_user_saved_tracks_delete() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_saved_tracks_delete"]], "current_user_top_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_top_artists"]], "current_user_top_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_top_tracks"]], "current_user_unfollow_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.current_user_unfollow_playlist"]], "currently_playing() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.currently_playing"]], "default_retry_codes (spotipy.client.spotify attribute)": [[0, "spotipy.client.Spotify.default_retry_codes"]], "devices() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.devices"]], "episode() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.episode"]], "episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.episodes"]], "featured_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.featured_playlists"]], "get_access_token() (spotipy.oauth2.spotifyclientcredentials method)": [[0, "spotipy.oauth2.SpotifyClientCredentials.get_access_token"]], "get_access_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_access_token"]], "get_access_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_access_token"]], "get_access_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_access_token"]], "get_auth_response() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_auth_response"]], "get_auth_response() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_auth_response"]], "get_authorization_code() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_authorization_code"]], "get_authorization_code() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_authorization_code"]], "get_authorize_url() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_authorize_url"]], "get_authorize_url() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_authorize_url"]], "get_authorize_url() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_authorize_url"]], "get_cached_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.get_cached_token"]], "get_cached_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.get_cached_token"]], "get_cached_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_cached_token"]], "get_pkce_handshake_parameters() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.get_pkce_handshake_parameters"]], "max_retries (spotipy.client.spotify attribute)": [[0, "spotipy.client.Spotify.max_retries"]], "me() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.me"]], "module": [[0, "module-spotipy.client"], [0, "module-spotipy.oauth2"], [0, "module-spotipy.util"]], "new_releases() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.new_releases"]], "next() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.next"]], "next_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.next_track"]], "parse_auth_response_url() (spotipy.oauth2.spotifyimplicitgrant static method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.parse_auth_response_url"]], "parse_auth_response_url() (spotipy.oauth2.spotifyoauth static method)": [[0, "spotipy.oauth2.SpotifyOAuth.parse_auth_response_url"]], "parse_auth_response_url() (spotipy.oauth2.spotifypkce static method)": [[0, "spotipy.oauth2.SpotifyPKCE.parse_auth_response_url"]], "parse_response_code() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.parse_response_code"]], "parse_response_code() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.parse_response_code"]], "parse_response_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.parse_response_token"]], "pause_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.pause_playback"]], "playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist"]], "playlist_add_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_add_items"]], "playlist_change_details() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_change_details"]], "playlist_cover_image() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_cover_image"]], "playlist_is_following() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_is_following"]], "playlist_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_items"]], "playlist_remove_all_occurrences_of_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_remove_all_occurrences_of_items"]], "playlist_remove_specific_occurrences_of_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_remove_specific_occurrences_of_items"]], "playlist_reorder_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_reorder_items"]], "playlist_replace_items() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_replace_items"]], "playlist_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_tracks"]], "playlist_upload_cover_image() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.playlist_upload_cover_image"]], "previous() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.previous"]], "previous_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.previous_track"]], "prompt_for_user_token() (in module spotipy.util)": [[0, "spotipy.util.prompt_for_user_token"]], "queue() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.queue"]], "recommendation_genre_seeds() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.recommendation_genre_seeds"]], "recommendations() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.recommendations"]], "refresh_access_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.refresh_access_token"]], "refresh_access_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.refresh_access_token"]], "repeat() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.repeat"]], "search() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.search"]], "search_markets() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.search_markets"]], "seek_track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.seek_track"]], "set_auth() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.set_auth"]], "show() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.show"]], "show_episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.show_episodes"]], "shows() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.shows"]], "shuffle() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.shuffle"]], "spotipy.client": [[0, "module-spotipy.client"]], "spotipy.oauth2": [[0, "module-spotipy.oauth2"]], "spotipy.util": [[0, "module-spotipy.util"]], "start_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.start_playback"]], "track() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.track"]], "tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.tracks"]], "transfer_playback() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.transfer_playback"]], "user() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user"]], "user_follow_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_follow_artists"]], "user_follow_users() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_follow_users"]], "user_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist"]], "user_playlist_add_episodes() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_add_episodes"]], "user_playlist_add_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_add_tracks"]], "user_playlist_change_details() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_change_details"]], "user_playlist_create() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_create"]], "user_playlist_follow_playlist() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_follow_playlist"]], "user_playlist_is_following() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_is_following"]], "user_playlist_remove_all_occurrences_of_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_remove_all_occurrences_of_tracks"]], "user_playlist_remove_specific_occurrences_of_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_remove_specific_occurrences_of_tracks"]], "user_playlist_reorder_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_reorder_tracks"]], "user_playlist_replace_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_replace_tracks"]], "user_playlist_tracks() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_tracks"]], "user_playlist_unfollow() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlist_unfollow"]], "user_playlists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_playlists"]], "user_unfollow_artists() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_unfollow_artists"]], "user_unfollow_users() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.user_unfollow_users"]], "validate_token() (spotipy.oauth2.spotifyimplicitgrant method)": [[0, "spotipy.oauth2.SpotifyImplicitGrant.validate_token"]], "validate_token() (spotipy.oauth2.spotifyoauth method)": [[0, "spotipy.oauth2.SpotifyOAuth.validate_token"]], "validate_token() (spotipy.oauth2.spotifypkce method)": [[0, "spotipy.oauth2.SpotifyPKCE.validate_token"]], "volume() (spotipy.client.spotify method)": [[0, "spotipy.client.Spotify.volume"]]}}) \ No newline at end of file From ea01236c58f89ddec32c891d6defaad6b1da58b2 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Sat, 13 May 2023 23:42:11 +0100 Subject: [PATCH 15/18] Add files via upload test for search queries displayed in a tabular form generates xml file as artifact --- tests/test_search.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/test_search.py diff --git a/tests/test_search.py b/tests/test_search.py new file mode 100644 index 00000000..e2e1d695 --- /dev/null +++ b/tests/test_search.py @@ -0,0 +1,36 @@ +import sys +import xml.etree.ElementTree as ET +from spotipy.oauth2 import SpotifyClientCredentials +import spotipy +from tabulate import tabulate + +client_id = 'client_id' +client_secret = 'client_secret' + +client_credentials_manager = SpotifyClientCredentials( + client_id=client_id, client_secret=client_secret) +sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) + +search_str = input("Enter a search string: ") +result = sp.search(search_str) + +# Convert the search results to a table format +headers = ["Track Name", "Artist", "Album"] +table = [[track['name'], track['artists'][0]['name'], track['album']['name']] + for track in result['tracks']['items']] +table_str = tabulate(table, headers=headers) + +# Create an XML tree and save it to a file +root = ET.Element("search_results") +for track in result['tracks']['items']: + track_element = ET.SubElement(root, "track") + track_element.set("name", track['name']) + track_element.set("artist", track['artists'][0]['name']) + track_element.set("album", track['album']['name']) + +xml_str = ET.tostring(root, encoding='utf8', method='xml') +with open('search_results.xml', 'wb') as f: + f.write(xml_str) + +print(table_str) +print("Search results saved to search_results.xml") From 1aeada387f77efc4f064bb95da700be77ed92505 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Sat, 13 May 2023 23:44:34 +0100 Subject: [PATCH 16/18] Rename tests/test_search.py to tests/unit/test_search.py changed folder --- tests/{ => unit}/test_search.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{ => unit}/test_search.py (100%) diff --git a/tests/test_search.py b/tests/unit/test_search.py similarity index 100% rename from tests/test_search.py rename to tests/unit/test_search.py From b6b9aaf7f132d2c291dfc597e37cd33633a34207 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Mon, 29 May 2023 21:42:39 +0100 Subject: [PATCH 17/18] Update test_search.py --- tests/unit/test_search.py | 77 ++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/tests/unit/test_search.py b/tests/unit/test_search.py index e2e1d695..387903dd 100644 --- a/tests/unit/test_search.py +++ b/tests/unit/test_search.py @@ -1,36 +1,45 @@ -import sys -import xml.etree.ElementTree as ET +import unittest from spotipy.oauth2 import SpotifyClientCredentials import spotipy -from tabulate import tabulate - -client_id = 'client_id' -client_secret = 'client_secret' - -client_credentials_manager = SpotifyClientCredentials( - client_id=client_id, client_secret=client_secret) -sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) - -search_str = input("Enter a search string: ") -result = sp.search(search_str) - -# Convert the search results to a table format -headers = ["Track Name", "Artist", "Album"] -table = [[track['name'], track['artists'][0]['name'], track['album']['name']] - for track in result['tracks']['items']] -table_str = tabulate(table, headers=headers) - -# Create an XML tree and save it to a file -root = ET.Element("search_results") -for track in result['tracks']['items']: - track_element = ET.SubElement(root, "track") - track_element.set("name", track['name']) - track_element.set("artist", track['artists'][0]['name']) - track_element.set("album", track['album']['name']) - -xml_str = ET.tostring(root, encoding='utf8', method='xml') -with open('search_results.xml', 'wb') as f: - f.write(xml_str) - -print(table_str) -print("Search results saved to search_results.xml") +import traceback + + +class artist_info_test_case(unittest.TestCase): + def test_artist_info_with_search_str(self): + search_str = 'Radiohead' + sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials( + client_id='id_client', client_secret='secret_client')) + result = sp.search(search_str) + + # Assert that the 'tracks' key is present in the result + self.assertIn('tracks', result) + + # Assert that the 'items' key is present in the 'tracks' dictionary + self.assertIn('items', result['tracks']) + + # Assert that the 'items' list is not empty + self.assertTrue(len(result['tracks']['items']) > 0) + + +class exception_test_case(unittest.TestCase): + def test_empty_search_query(self): + search_str = "Radiohead" + sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials( + client_id='id_client', client_secret='secret_client')) + result = sp.search(search_str) + + # Assert that the 'tracks' key is present in the result + self.assertIn('tracks', result) + + def test_invalid_search_query(self): + search_str = "1234" + sp = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials( + client_id='id_client', client_secret='secret_client')) + result = sp.search(search_str) + + # Make sure at least some tracks are returned + self.assertNotEqual(result['tracks']['total'], 0) + + +if __name__ == '__main__': + unittest.main(verbosity=2) From e1e85b7f21285c04daff44f77586c9f001938098 Mon Sep 17 00:00:00 2001 From: Soman Khan <76926660+soman24@users.noreply.github.com> Date: Fri, 2 Jun 2023 19:01:59 +0100 Subject: [PATCH 18/18] Update retrieve_artists.py Added function to retrieve related artists --- examples/artist_recommendations.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/artist_recommendations.py b/examples/artist_recommendations.py index 40a95a23..d1f75e3f 100644 --- a/examples/artist_recommendations.py +++ b/examples/artist_recommendations.py @@ -19,6 +19,12 @@ def get_args(): return parser.parse_args() +def get_related_artists(artist_id): + results = sp.artist_related_artists(artist_id) + related_artists = [artist['name'] for artist in results['artists']] + return related_artists + + def get_artist(name): results = sp.search(q='artist:' + name, type='artist') items = results['artists']['items']