A light weight Python library for the Spotify Web API
Comprehensive playlist operations including creation, modification, track management, collaboration features, and following functionality. Supports both current user's playlists and operations on other users' public playlists.
Retrieve playlist details and metadata.
def playlist(self, playlist_id, fields=None, market=None, additional_types=("track",)):
"""
Get playlist information.
Args:
playlist_id (str): Spotify playlist ID or URI
fields (str, optional): Comma-separated list of fields to return
market (str, optional): ISO 3166-1 alpha-2 country code
additional_types (tuple): Include 'episode' for podcast episodes (default: ("track",))
Returns:
dict: Playlist object with tracks, metadata, and owner information
"""
def current_user_playlists(self, limit=50, offset=0):
"""
Get current user's playlists.
Requires scope: playlist-read-private
Args:
limit (int): Number of playlists to return (1-50, default: 50)
offset (int): Index of first playlist (default: 0)
Returns:
dict: Paging object of simplified playlist objects
"""
def user_playlists(self, user, limit=50, offset=0):
"""
Get user's public playlists.
Args:
user (str): Spotify user ID
limit (int): Number of playlists to return (1-50, default: 50)
offset (int): Index of first playlist (default: 0)
Returns:
dict: Paging object of simplified playlist objects
"""Access and retrieve playlist content.
def playlist_items(self, playlist_id, fields=None, limit=100, offset=0,
market=None, additional_types=("track", "episode")):
"""
Get playlist items (tracks and episodes).
Args:
playlist_id (str): Spotify playlist ID or URI
fields (str, optional): Comma-separated list of fields to return
limit (int): Number of items to return (1-100, default: 100)
offset (int): Index of first item (default: 0)
market (str, optional): ISO 3166-1 alpha-2 country code
additional_types (tuple): Content types to include (default: ("track", "episode"))
Returns:
dict: Paging object of playlist track objects with added_by and added_at info
"""
def playlist_tracks(self, playlist_id, fields=None, limit=100, offset=0,
market=None, additional_types=("track",)):
"""
Get playlist tracks (legacy method, use playlist_items instead).
Args:
playlist_id (str): Spotify playlist ID or URI
fields (str, optional): Comma-separated list of fields to return
limit (int): Number of tracks to return (1-100, default: 100)
offset (int): Index of first track (default: 0)
market (str, optional): ISO 3166-1 alpha-2 country code
additional_types (tuple): Content types to include (default: ("track",))
Returns:
dict: Paging object of playlist track objects
"""
def user_playlist(self, user, playlist_id=None, fields=None, market=None):
"""
Get user playlist (legacy method, use playlist instead).
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
fields (str, optional): Comma-separated list of fields to return
market (str, optional): ISO 3166-1 alpha-2 country code
Returns:
dict: Playlist object
"""
def user_playlist_tracks(self, user, playlist_id, fields=None, limit=100,
offset=0, market=None):
"""
Get user playlist tracks (legacy method, use playlist_tracks instead).
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
fields (str, optional): Comma-separated list of fields to return
limit (int): Number of tracks to return (1-100, default: 100)
offset (int): Index of first track (default: 0)
market (str, optional): ISO 3166-1 alpha-2 country code
Returns:
dict: Paging object of playlist track objects
"""Create new playlists and modify existing ones.
def user_playlist_create(self, user, name, public=True, collaborative=False, description=""):
"""
Create playlist for user (legacy method).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (must be current user)
name (str): Playlist name
public (bool): Make playlist public (default: True)
collaborative (bool): Make playlist collaborative (default: False)
description (str): Playlist description (default: "")
Returns:
dict: Created playlist object
"""
def playlist_change_details(self, playlist_id, name=None, public=None,
collaborative=None, description=None):
"""
Change playlist details.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
name (str, optional): New playlist name
public (bool, optional): Make playlist public/private
collaborative (bool, optional): Make playlist collaborative
description (str, optional): New playlist description
Returns:
None
"""
def user_playlist_change_details(self, user, playlist_id, name=None, public=None,
collaborative=None, description=None):
"""
Change user playlist details (legacy method, use playlist_change_details instead).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
name (str, optional): New playlist name
public (bool, optional): Make playlist public/private
collaborative (bool, optional): Make playlist collaborative
description (str, optional): New playlist description
Returns:
None
"""Add tracks and episodes to playlists.
def playlist_add_items(self, playlist_id, items, position=None):
"""
Add items to playlist.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
items (list): List of track/episode URIs to add (max 100)
position (int, optional): Position to insert items (default: end)
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def user_playlist_add_tracks(self, user, playlist_id, tracks, position=None):
"""
Add tracks to user playlist (legacy method, use playlist_add_items instead).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
tracks (list): List of track URIs to add (max 100)
position (int, optional): Position to insert tracks (default: end)
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def user_playlist_add_episodes(self, user, playlist_id, episodes, position=None):
"""
Add episodes to user playlist (legacy method, use playlist_add_items instead).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
episodes (list): List of episode URIs to add (max 100)
position (int, optional): Position to insert episodes (default: end)
Returns:
dict: Object with snapshot_id for the updated playlist
"""Replace playlist contents and reorder items.
def playlist_replace_items(self, playlist_id, items):
"""
Replace all items in playlist.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
items (list): List of track/episode URIs to replace with (max 100)
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def user_playlist_replace_tracks(self, user, playlist_id, tracks):
"""
Replace all tracks in user playlist (legacy method, use playlist_replace_items instead).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
tracks (list): List of track URIs to replace with (max 100)
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def playlist_reorder_items(self, playlist_id, range_start, insert_before,
range_length=1, snapshot_id=None):
"""
Reorder items in playlist.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
range_start (int): Position of first item to move
insert_before (int): Position to insert the items
range_length (int): Number of items to move (default: 1)
snapshot_id (str, optional): Playlist snapshot ID for consistency
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def user_playlist_reorder_tracks(self, user, playlist_id, range_start, insert_before,
range_length=1, snapshot_id=None):
"""
Reorder tracks in user playlist (legacy method, use playlist_reorder_items instead).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
range_start (int): Position of first track to move
insert_before (int): Position to insert the tracks
range_length (int): Number of tracks to move (default: 1)
snapshot_id (str, optional): Playlist snapshot ID for consistency
Returns:
dict: Object with snapshot_id for the updated playlist
"""Remove tracks and episodes from playlists.
def playlist_remove_all_occurrences_of_items(self, playlist_id, items, snapshot_id=None):
"""
Remove all occurrences of items from playlist.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
items (list): List of track/episode URIs to remove (max 100)
snapshot_id (str, optional): Playlist snapshot ID for consistency
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def playlist_remove_specific_occurrences_of_items(self, playlist_id, items, snapshot_id=None):
"""
Remove specific occurrences of items from playlist.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
items (list): List of objects with 'uri' and 'positions' keys (max 100)
snapshot_id (str, optional): Playlist snapshot ID for consistency
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def user_playlist_remove_all_occurrences_of_tracks(self, user, playlist_id, tracks, snapshot_id=None):
"""
Remove all occurrences of tracks from user playlist (legacy method).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
tracks (list): List of track URIs to remove (max 100)
snapshot_id (str, optional): Playlist snapshot ID for consistency
Returns:
dict: Object with snapshot_id for the updated playlist
"""
def user_playlist_remove_specific_occurrences_of_tracks(self, user, playlist_id, tracks,
positions, snapshot_id=None):
"""
Remove specific occurrences of tracks from user playlist (legacy method).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): Spotify user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
tracks (list): List of track URIs to remove
positions (list): List of positions for each track URI
snapshot_id (str, optional): Playlist snapshot ID for consistency
Returns:
dict: Object with snapshot_id for the updated playlist
"""Follow and unfollow playlists, check following status.
def current_user_follow_playlist(self, playlist_id, public=True):
"""
Follow playlist.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
public (bool): Show as public in user's profile (default: True)
Returns:
None
"""
def current_user_unfollow_playlist(self, playlist_id):
"""
Unfollow playlist.
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
Returns:
None
"""
def playlist_is_following(self, playlist_id, user_ids):
"""
Check if users follow playlist.
Args:
playlist_id (str): Spotify playlist ID or URI
user_ids (list): List of user IDs to check (max 5)
Returns:
list: Boolean list indicating which users follow the playlist
"""
def user_playlist_follow_playlist(self, playlist_owner_id, playlist_id):
"""
Follow playlist (legacy method, use current_user_follow_playlist instead).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
playlist_owner_id (str): Playlist owner's user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
Returns:
None
"""
def user_playlist_unfollow(self, user, playlist_id):
"""
Unfollow playlist (legacy method, use current_user_unfollow_playlist instead).
Requires scope: playlist-modify-public or playlist-modify-private
Args:
user (str): User ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
Returns:
None
"""
def user_playlist_is_following(self, playlist_owner_id, playlist_id, user_ids):
"""
Check if users follow playlist (legacy method, use playlist_is_following instead).
Args:
playlist_owner_id (str): Playlist owner's user ID (ignored in current API)
playlist_id (str): Spotify playlist ID or URI
user_ids (list): List of user IDs to check (max 5)
Returns:
list: Boolean list indicating which users follow the playlist
"""Manage playlist cover images.
def playlist_cover_image(self, playlist_id):
"""
Get playlist cover image.
Args:
playlist_id (str): Spotify playlist ID or URI
Returns:
list: List of image objects with URL, height, and width
"""
def playlist_upload_cover_image(self, playlist_id, image_b64):
"""
Upload custom playlist cover image.
Requires scope: ugc-image-upload, playlist-modify-public or playlist-modify-private
Args:
playlist_id (str): Spotify playlist ID or URI
image_b64 (str): Base64 encoded JPEG image data (max 256KB)
Returns:
None
"""import spotipy
from spotipy.oauth2 import SpotifyOAuth
scope = "playlist-modify-public playlist-modify-private"
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
# Get current user ID
user = sp.me()
user_id = user['id']
# Create a new playlist
playlist = sp.user_playlist_create(
user=user_id,
name="My Awesome Playlist",
description="Created with Spotipy",
public=True
)
print(f"Created playlist: {playlist['name']} (ID: {playlist['id']})")
# Add tracks to the playlist
track_uris = [
'spotify:track:4iV5W9uYEdYUVa79Axb7Rh', # Mr. Brightside
'spotify:track:0VjIjW4GlUAb6qAOLklx2J', # Bohemian Rhapsody
'spotify:track:1301WleyT98MSxVHPZCA6M' # Sweet Child O' Mine
]
result = sp.playlist_add_items(playlist['id'], track_uris)
print(f"Added {len(track_uris)} tracks. Snapshot ID: {result['snapshot_id']}")
# Update playlist details
sp.playlist_change_details(
playlist['id'],
name="My Updated Playlist",
description="Updated description with more details",
public=False # Make it private
)
print("Playlist details updated")playlist_id = "37i9dQZF1DXcBWIGoYBM5M" # Example playlist ID
# Get playlist information
playlist_info = sp.playlist(playlist_id)
print(f"Playlist: {playlist_info['name']} by {playlist_info['owner']['display_name']}")
print(f"Tracks: {playlist_info['tracks']['total']}")
print(f"Followers: {playlist_info['followers']['total']}")
# Get all tracks from playlist
tracks = []
results = sp.playlist_items(playlist_id, limit=50)
tracks.extend(results['items'])
while results['next']:
results = sp.next(results)
tracks.extend(results['items'])
print(f"\\nAll {len(tracks)} tracks:")
for i, item in enumerate(tracks[:10], 1): # Show first 10
track = item['track']
if track: # Check if track is not None (could be deleted)
artist_names = ', '.join([artist['name'] for artist in track['artists']])
print(f" {i}. {track['name']} - {artist_names}")
print(f" Added by: {item['added_by']['id']} on {item['added_at'][:10]}")# Create a collaborative playlist
collaborative_playlist = sp.user_playlist_create(
user=user_id,
name="Team Collaborative Playlist",
description="Add your favorite tracks!",
collaborative=True,
public=False # Private but collaborative
)
print(f"Created collaborative playlist: {collaborative_playlist['external_urls']['spotify']}")
# Check who's following a playlist
user_ids_to_check = ['spotify', 'example_user', user_id]
following_status = sp.playlist_is_following(collaborative_playlist['id'], user_ids_to_check)
for user_id_check, is_following in zip(user_ids_to_check, following_status):
status = "following" if is_following else "not following"
print(f"User {user_id_check} is {status} the playlist")# Reorder tracks in playlist
my_playlist_id = "your_playlist_id_here"
# Move track at position 0 to position 5
result = sp.playlist_reorder_items(
playlist_id=my_playlist_id,
range_start=0, # Move track at position 0
insert_before=6, # Insert before position 6 (so it ends up at position 5)
range_length=1 # Move 1 track
)
print(f"Reordered playlist. New snapshot: {result['snapshot_id']}")
# Remove specific occurrences of tracks
tracks_to_remove = [
{
"uri": "spotify:track:4iV5W9uYEdYUVa79Axb7Rh",
"positions": [0, 3] # Remove from positions 0 and 3
}
]
result = sp.playlist_remove_specific_occurrences_of_items(
my_playlist_id,
tracks_to_remove
)
print(f"Removed specific track occurrences. New snapshot: {result['snapshot_id']}")
# Replace entire playlist content
new_track_uris = [
'spotify:track:0VjIjW4GlUAOLklx2J',
'spotify:track:1301WleyT98MSxVHPZCA6M',
'spotify:track:4VqPOruhp5EdPBeR92t6lQ'
]
result = sp.playlist_replace_items(my_playlist_id, new_track_uris)
print(f"Replaced all playlist content. New snapshot: {result['snapshot_id']}")import base64
# Get current playlist cover
cover_images = sp.playlist_cover_image(playlist_id)
if cover_images:
print(f"Current cover image: {cover_images[0]['url']}")
print(f"Dimensions: {cover_images[0]['width']}x{cover_images[0]['height']}")
# Upload custom cover image
# Note: Image must be JPEG format, base64 encoded, max 256KB
with open("my_playlist_cover.jpg", "rb") as image_file:
image_b64 = base64.b64encode(image_file.read()).decode('utf-8')
try:
sp.playlist_upload_cover_image(playlist_id, image_b64)
print("Successfully uploaded custom playlist cover!")
except Exception as e:
print(f"Failed to upload cover: {e}")# Get all user's playlists
all_playlists = []
results = sp.current_user_playlists(limit=50)
all_playlists.extend(results['items'])
while results['next']:
results = sp.next(results)
all_playlists.extend(results['items'])
print(f"Found {len(all_playlists)} playlists")
# Analyze playlists
total_tracks = 0
collaborative_count = 0
public_count = 0
for playlist in all_playlists:
total_tracks += playlist['tracks']['total']
if playlist['collaborative']:
collaborative_count += 1
if playlist['public']:
public_count += 1
print(f"Total tracks across all playlists: {total_tracks}")
print(f"Collaborative playlists: {collaborative_count}")
print(f"Public playlists: {public_count}")
print(f"Private playlists: {len(all_playlists) - public_count}")
# Find largest playlists
largest_playlists = sorted(all_playlists, key=lambda x: x['tracks']['total'], reverse=True)[:5]
print("\\nLargest playlists:")
for playlist in largest_playlists:
print(f" {playlist['name']}: {playlist['tracks']['total']} tracks")Install with Tessl CLI
npx tessl i tessl/pypi-spotipy