Skip to content

Lightweight, single-file, zero-dependency Spotify wrapper for Python 2.7+ and Python 3.x

License

Notifications You must be signed in to change notification settings

orangeblock/spotify-lite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

spotify-lite

A lightweight, single-file, zero-dependency Spotify wrapper, that can be dropped into any Python 2.x or 3.x project with minimal hassle.

Quickstart

pip install spotify-lite

or simply drop spotify/spotify.py anywhere into your project.

Get an instance of the API wrapper:

import spotify

client_id = "my-client-id"
client_secret = "top-secret"
# optional but required when registering a user via authorization code flow
redirect_uri = "http://localhost:1337"

api = spotify.SpotifyAPI(client_id, client_secret, redirect_uri)

Get user permission and complete authorization:

url = api.oauth2_url(scopes=['user-read-private'])
# redirect user to above url, get auth code and then...
user = api.set_user_from_code('really-long-code-string')

See Authorization section for more options and detailed explanation.

Get a playlist:

pl = api.playlist('1SCHh6WSTufPLgEFjGSteL')
print(pl['name'])

The response for single resource endpoints is the JSON response from Spotify, as a Python dictionary.

Get associated user's playlists:

pls = api.playlists()
for pl in pls:
  print(pl['name'])

The response for endpoints returning multiple resources is always a generator, yielding the inner Spotify resource(s). Pagination is automatically handled.

Post a boatload of tracks to a playlist:

track_uris = ["spotify:track:4uLU6hMCjMI75M1A2tKUQC"] * 5000
api.playlist_tracks_add('some-playlist-id', track_uris)

You don't need to batch your requests - the above will execute multiple batch requests internally to add all tracks to the playlist.

See API Endpoints for a more in-depth look at the request/response mapping.


Authorization

First, you need to initialize an instance of the API wrapper with your developer credentials:

import spotify

client_id = "my-client-id"
client_secret = "top-secret"
# optional but required when registering a user via authorization code
redirect_uri = "http://localhost:1337"

api = spotify.SpotifyAPI(client_id, client_secret, redirect_uri) 

Alternatively you can set the SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET and SPOTIFY_REDIRECT_URI environment variables and call the above constructor with no arguments:

import os

# ... or directly through your runtime environment
os.environ['SPOTIFY_CLIENT_ID'] = "my-client-id"
os.environ['SPOTIFY_CLIENT_SECRET'] = "top-secret"
os.environ['SPOTIFY_REDIRECT_URI'] = "http://localhost:1337"

api = spotify.SpotifyAPI()

This library supports the authorization code flow. You will need to prompt a user to grant permissions which will generate an authorization code that you can use to associate the user with the API instance. You can call api.oauth2_url(scopes=['user-read-private']) on the above created object to generate a valid auth URL requesting the specified roles (passed as a list of strings). Refer to the documentation for allowed authorization scopes.

After you've sent the user to the above URL (and assuming your setup credentials are valid) you will obtain an authorization code on the specified redirect URI. You can then pass that code to the API instance:

code = "code-i-received-from-authorization-flow"
user = api.set_user_from_code(code)

If successful, the user object you receive contains the currently generated access and refresh tokens. You can store user.refresh_token to skip the authorization code flow in the future. According to Spotify refresh tokens should be valid indefinitely unless you change your client credentials.

If you've persisted a user's refresh token you can directly instantiate an API instance by creating a SpotifyUser object and passing it to the wrapper's constructor:

# assume environment variables for client credentials are set
user = spotify.SpotifyUser(refresh_token='user-token-persisted-across-sessions')
api = spotify.SpotifyAPI(user=user)

SpotifyUsers can be dynamically assigned to a SpotifyAPI instance:

new_user = spotify.SpotifyUser(refresh_token='another-saved-token')
api.set_user(new_user)
# API methods now work against new_user

If you only have one user for your application and you've already obtained the refresh token you can set the environment variable SPOTIFY_REFRESH_TOKEN to eliminate any boilerplate code:

import os

# ... or directly through your runtime environment
os.environ['SPOTIFY_CLIENT_ID'] = "my-client-id"
os.environ['SPOTIFY_CLIENT_SECRET'] = "top-secret"
os.environ['SPOTIFY_REFRESH_TOKEN'] = "user-token-persisted-across-sessions"

api = spotify.SpotifyAPI()
print(api.profile())

API endpoints

This library automatically handles pagination for requests and responses. Additionally, responses will always return the parsed JSON received from Spotify.

Each Spotify API endpoint is mapped to a method you can access via the API wrapper instance. For details on what parameters are accepted for a particular endpoint, refer to the official Web API Reference. Path parameters and IDs for batch requests are passed as positional arguments, and query parameters as keyword arguments. The names of keyword arguments follow the naming convetion outlined in the Spotify documentation:

>>> api.playlist('2pFB0I2SvMbsPHZrfRfbZL', fields=['description', 'uri'])
{'description': 'Music candy. High replay value.', 'uri': 'spotify:playlist:2pFB0I2SvMbsPHZrfRfbZL'}

You will notice in the above we are using a Python list instead of what the documentation mentions, which is a comma-separated list of strings. In general, CSV parameters should be passed as lists and the library will automatically convert them. Additionally, ignore any parameters that have to deal with pagination, such as limit or offset as these are automatically handled internally.

All methods that should return multiple items return a generator, which you use to iterate over all results without specifiying any pagination parameters:

tracks_generator = api.playlist_tracks("1SCHh6WSTufPLgEFjGSteL")
for track in tracks_generator:
  print(track['track']['name'])

You don't have to unwrap the Spotify paging object or worry about hitting pagination limits, the library will automatically handle all of this and always use the highest available limit for each paginated request to limit round-trip time.

Endpoints that receive multiple ids usually need to be sent in batches. The library takes care of all that for you so you can simply pass the entire list:

# huge list of 5000 tracks
track_uris = [...] 
api.playlist_tracks_add("my-playlist-id", track_uris)

Mapping

Below is a list of supported endpoints and their corresponding method names, accessed via the object returned by the call to SpotifyAPI. Argument positioning and naming as explained previously:

Albums

Get Multiple Albums -> albums

Get an Album -> album

Get an Album's Tracks -> album_tracks

Artists

Get Multiple Artists -> artists

Get an Artist -> artist

Get an Artist's Top Tracks -> artist_top_tracks

Get an Artist's Related Artists -> artist_related_artists

Get an Artist's Albums -> artist_albums

Browse

Get All New Releases -> new_releases

Get All Featured Playlists -> featured_playlists

Get All Categories -> categories

Get a Category -> category

Get a Category's Playlists -> category_playlists

Get Recommendations -> recommendations

Episodes

Get Multiple Episodes -> episodes

Get an Episode -> episode

Follow

Follow a Playlist -> follow_playlist

Unfollow Playlist -> unfollow_playlist

Check if Users Follow a Playlist -> is_playlist_followed

Get User's Followed Artists -> artists_followed

Follow Artists or Users -> follow_artists, follow_users

Unfollow Artists or Users -> unfollow_artists, unfollow_users

Get Following State for Artists/Users -> is_following_artists, is_following_users

Library

Get User's Saved Albums -> saved_albums

Save Albums for Current User -> saved_albums_add

Remove Albums for Current User -> saved_albums_remove

Check User's Saved Albums -> are_albums_saved

Get User's Saved Tracks -> saved_tracks

Save Tracks for User -> saved_tracks_add

Remove User's Saved Tracks -> saved_tracks_remove

Check User's Saved Tracks -> are_tracks_saved

Get User's Saved Shows -> saved_shows

Save Shows for Current User -> saved_shows_add

Remove User's Saved Shows -> saved_shows_remove

Check User's Saved Shows -> are_shows_saved

Personalization

Get a User's Top Artists and Tracks -> top_artists, top_tracks

Playlists

Get a List of Current User's Playlists -> playlists

Get a List of a User's Playlists -> playlists (w/ user ID as parameter)

Create a Playlist -> playlists_add

Get a Playlist -> playlist

Change a Playlist's Details -> playlist_edit

Get a Playlist's Items -> playlist_tracks

Add Items to a Playlist -> playlist_tracks_add

Reorder or Replace a Playlist's Items -> playlist_tracks_reorder, playlist_tracks_replace

Remove Items from a Playlist -> playlist_tracks_remove

Get a Playlist Cover Image -> playlist_images

Upload a Custom Playlist Cover Image -> playlist_image_add (w/ image binary as a file descriptor, e.g. through open)

Search

Search for an Item -> search_albums, search_artists, search_playlists, search_tracks, search_shows

Shows

Get Multiple Shows -> shows

Get a Show -> show

Get a Show's Episodes -> show_episodes

Tracks

Get Several Tracks -> tracks

Get a Track -> track

Get Audio Features for Several Tracks -> tracks_audio_features

Get Audio Features for a Track -> track_audio_features

Get Audio Analysis for a Track -> track_audio_analysis

User Profile

Get Current User's Profile -> profile

Get a User's Profile -> profile (w/ user ID as param)

Player

Get Information About The User's Current Playback -> player

Transfer a User's Playback -> player_transfer

Get a User's Available Devices -> player_devices

Get the User's Currently Playing Track -> player_current_track

Start/Resume a User's Playback -> player_play

Pause a User's Playback -> player_pause

Skip User's Playback To Next Track -> player_next

Skip User's Playback To Previous Track -> player_previous

Seek To Position In Currently Playing Track -> player_seek

Set Repeat Mode On User's Playback -> player_repeat

Set Volume For User's Playback -> player_volume

Toggle Shuffle For Userâs Playback -> player_shuffle

Get Current User's Recently Played Tracks -> player_recent_tracks

Add an item to queue -> player_queue_add

Convenience methods

I've added a few additional convenience methods:

playlist_track_objs, saved_album_objs, saved_show_objs, saved_track_objs, player_recent_track_objs

These break the contract that you always get the exact JSON response from Spotify and return the inner objects, omitting any additional metadata in the outer object. As an example, these do the same thing:

for track in api.playlist_tracks("1SCHh6WSTufPLgEFjGSteL"):
  print(track['track']['name'])
for track in api.playlist_track_objs("1SCHh6WSTufPLgEFjGSteL"):
  print(track['name'])

Direct API access (experimental)

You can use this library purely as an authentication wrapper and send direct requests to the Spotify API. Call the get, post, put and delete methods on the wrapper instance with parameters similar to what you would use in Requests, namely params, data, json and headers. You will then get back an instance of http.client.HTTPResponse (in Python 3.x), which you can handle as you like. Example:

import json
import spotify

api = spotify.SpotifyAPI()
response = api.get("playlists/2pFB0I2SvMbsPHZrfRfbZL")
response_json = json.loads(response.read())
print(response_json['name'])

These are used under the hood by the wrapper methods, so are fairly well tested, but you will have to handle URL/parameter construction and response/pagination handling by yourself.


Testing

Full integration tests are availble in tests, running against a real Spotify user. You need to set up the SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET and SPOTIFY_REFRESH_TOKEN environment variables as explained in Authorization.

Then, from root directory:

python -m unittest

About

Lightweight, single-file, zero-dependency Spotify wrapper for Python 2.7+ and Python 3.x

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages