A light weight Python library for the Spotify Web API
Control Spotify playback across user's active devices. Requires Spotify Premium subscription for most playback control features. Provides comprehensive control over playback state, queue management, and device switching.
Get current playback state and currently playing content.
def current_playback(self, market=None, additional_types=None):
"""
Get current playback information.
Requires scope: user-read-playback-state
Args:
market (str, optional): ISO 3166-1 alpha-2 country code
additional_types (str, optional): Comma-separated list of item types - 'track', 'episode'
Returns:
dict: Playback state object with device, track/episode, progress, shuffle/repeat state, or None if nothing playing
"""
def currently_playing(self, market=None, additional_types=None):
"""
Get currently playing track or episode.
Requires scope: user-read-currently-playing
Args:
market (str, optional): ISO 3166-1 alpha-2 country code
additional_types (str, optional): Comma-separated list of item types - 'track', 'episode'
Returns:
dict: Currently playing object with basic playback info, or None if nothing playing
"""
def current_user_playing_track(self):
"""
Get current playing track (deprecated, use currently_playing instead).
Requires scope: user-read-currently-playing
Returns:
dict: Currently playing track object or None
"""Access and control available playback devices.
def devices(self):
"""
Get available devices.
Requires scope: user-read-playback-state
Returns:
dict: Object containing list of device objects with id, name, type, volume
"""
def transfer_playback(self, device_id, force_play=True):
"""
Transfer playback to different device.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
device_id (str or list): Device ID or list of device IDs to transfer to
force_play (bool): Ensure playback starts on new device (default: True)
Returns:
None
"""Start, pause, and navigate through tracks.
def start_playback(self, device_id=None, context_uri=None, uris=None,
offset=None, position_ms=None):
"""
Start or resume playback.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
device_id (str, optional): Device ID to start playback on
context_uri (str, optional): URI of album, artist, or playlist to play
uris (list, optional): List of track/episode URIs to play (max 100)
offset (dict, optional): Indicates where to start playback - {'position': 0} or {'uri': 'track_uri'}
position_ms (int, optional): Position in milliseconds to start playback
Returns:
None
"""
def pause_playback(self, device_id=None):
"""
Pause playback.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
device_id (str, optional): Device ID to pause playback on
Returns:
None
"""
def next_track(self, device_id=None):
"""
Skip to next track.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
device_id (str, optional): Device ID to skip on
Returns:
None
"""
def previous_track(self, device_id=None):
"""
Skip to previous track.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
device_id (str, optional): Device ID to skip on
Returns:
None
"""
def seek_track(self, position_ms, device_id=None):
"""
Seek to position in currently playing track.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
position_ms (int): Position to seek to in milliseconds
device_id (str, optional): Device ID to seek on
Returns:
None
"""Control shuffle, repeat, and volume settings.
def shuffle(self, state, device_id=None):
"""
Toggle shuffle for user's playback.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
state (bool): True to turn on shuffle, False to turn off
device_id (str, optional): Device ID to set shuffle on
Returns:
None
"""
def repeat(self, state, device_id=None):
"""
Set repeat mode for user's playback.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
state (str): Repeat mode - 'track', 'context', 'off'
device_id (str, optional): Device ID to set repeat on
Returns:
None
"""
def volume(self, volume_percent, device_id=None):
"""
Set volume for user's playback.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
volume_percent (int): Volume percentage (0-100)
device_id (str, optional): Device ID to set volume on
Returns:
None
"""Access and modify the playback queue.
def queue(self):
"""
Get user's queue.
Requires scope: user-read-playback-state
Returns:
dict: Queue object with currently_playing and queue arrays
"""
def add_to_queue(self, uri, device_id=None):
"""
Add track or episode to queue.
Requires scope: user-modify-playback-state
Requires: Spotify Premium
Args:
uri (str): URI of track or episode to add to queue
device_id (str, optional): Device ID to add to queue on
Returns:
None
"""import spotipy
from spotipy.oauth2 import SpotifyOAuth
scope = "user-read-playback-state user-modify-playback-state"
sp = spotipy.Spotify(auth_manager=SpotifyOAuth(scope=scope))
# Get current playback
current = sp.current_playback()
if current:
print(f"Currently playing: {current['item']['name']}")
print(f"Artist: {current['item']['artists'][0]['name']}")
print(f"Device: {current['device']['name']}")
print(f"Is playing: {current['is_playing']}")
print(f"Progress: {current['progress_ms']/1000:.1f}s / {current['item']['duration_ms']/1000:.1f}s")
# Pause if playing, resume if paused
if current['is_playing']:
sp.pause_playback()
print("Paused playback")
else:
sp.start_playback()
print("Resumed playback")
else:
print("No active playback")# Get available devices
devices_response = sp.devices()
devices = devices_response['devices']
print("Available devices:")
for device in devices:
status = "🔊 ACTIVE" if device['is_active'] else "💤 Inactive"
print(f" {status} {device['name']} ({device['type']}) - Volume: {device['volume_percent']}%")
# Transfer to specific device
if devices:
# Find computer or smartphone
preferred_device = None
for device in devices:
if device['type'] in ['Computer', 'Smartphone'] and not device['is_restricted']:
preferred_device = device
break
if preferred_device:
print(f"\\nTransferring playback to: {preferred_device['name']}")
sp.transfer_playback(preferred_device['id'], force_play=True)# Start playing a specific album
album_uri = "spotify:album:4aawyAB9vmqN3uQ7FjRGTy" # Example album
sp.start_playback(context_uri=album_uri)
print("Started playing album")
# Skip to track 3 in the album
sp.start_playback(
context_uri=album_uri,
offset={"position": 2} # 0-indexed, so position 2 is track 3
)
print("Started playing track 3 of album")
# Play specific tracks
track_uris = [
"spotify:track:4iV5W9uYEdYUVa79Axb7Rh", # Mr. Brightside
"spotify:track:0VjIjW4GlUAOLklx2J", # Bohemian Rhapsody
]
sp.start_playback(uris=track_uris)
print("Started playing specific tracks")
# Seek to 1 minute into current track
sp.seek_track(60000) # 60,000 milliseconds = 1 minute
print("Seeked to 1 minute")# Get current queue
queue_info = sp.queue()
print(f"Currently playing: {queue_info['currently_playing']['name']}")
print("\\nUpcoming in queue:")
for i, track in enumerate(queue_info['queue'][:5], 1): # Show next 5 tracks
artist_names = ', '.join([artist['name'] for artist in track['artists']])
print(f" {i}. {track['name']} - {artist_names}")
# Add tracks to queue
tracks_to_add = [
"spotify:track:1301WleyT98MSxVHPZCA6M", # Sweet Child O' Mine
"spotify:track:4VqPOruhp5EdPBeR92t6lQ", # Stairway to Heaven
]
for track_uri in tracks_to_add:
sp.add_to_queue(track_uri)
print(f"Added track to queue: {track_uri}")# Get current playback to check settings
current = sp.current_playback()
if current:
print(f"Shuffle: {'On' if current['shuffle_state'] else 'Off'}")
print(f"Repeat: {current['repeat_state']}")
print(f"Volume: {current['device']['volume_percent']}%")
# Toggle shuffle
new_shuffle = not current['shuffle_state']
sp.shuffle(new_shuffle)
print(f"Set shuffle to: {'On' if new_shuffle else 'Off'}")
# Cycle through repeat modes
repeat_modes = ['off', 'context', 'track']
current_repeat = current['repeat_state']
next_repeat_index = (repeat_modes.index(current_repeat) + 1) % len(repeat_modes)
next_repeat = repeat_modes[next_repeat_index]
sp.repeat(next_repeat)
print(f"Set repeat to: {next_repeat}")
# Adjust volume
current_volume = current['device']['volume_percent']
new_volume = min(100, current_volume + 10) # Increase by 10%, max 100%
sp.volume(new_volume)
print(f"Set volume to: {new_volume}%")import time
def monitor_playback(duration_seconds=60):
"""Monitor playback for specified duration."""
print(f"Monitoring playback for {duration_seconds} seconds...")
last_track = None
start_time = time.time()
while time.time() - start_time < duration_seconds:
current = sp.current_playback()
if current and current['item']:
track_name = current['item']['name']
artist_name = current['item']['artists'][0]['name']
progress_ms = current['progress_ms']
duration_ms = current['item']['duration_ms']
is_playing = current['is_playing']
# Check if track changed
if track_name != last_track:
print(f"\\n🎵 Now playing: {track_name} - {artist_name}")
last_track = track_name
# Show progress
progress_percent = (progress_ms / duration_ms) * 100
status = "▶️ Playing" if is_playing else "⏸️ Paused"
print(f"\\r{status} [{progress_percent:5.1f}%] {progress_ms//1000:3d}s / {duration_ms//1000:3d}s", end="")
else:
print("\\rNo active playback", end="")
time.sleep(2) # Update every 2 seconds
print("\\nMonitoring finished")
# Run monitoring
monitor_playback(30) # Monitor for 30 secondsdef play_playlist_smartly(playlist_id, shuffle=True, start_from_position=None):
"""Play playlist with smart features."""
# Get playlist info
playlist = sp.playlist(playlist_id)
print(f"Playing playlist: {playlist['name']}")
print(f"Total tracks: {playlist['tracks']['total']}")
# Set shuffle if requested
if shuffle:
sp.shuffle(True)
print("Shuffle enabled")
# Start playback
if start_from_position:
sp.start_playback(
context_uri=playlist['uri'],
offset={"position": start_from_position}
)
print(f"Started from position {start_from_position + 1}")
else:
sp.start_playback(context_uri=playlist['uri'])
print("Started from beginning")
# Set moderate volume
sp.volume(70)
print("Set volume to 70%")
# Use the smart player
playlist_id = "37i9dQZF1DXcBWIGoYBM5M" # Example: Today's Top Hits
play_playlist_smartly(playlist_id, shuffle=True, start_from_position=5)from spotipy.exceptions import SpotifyException
def safe_playback_control(action_func, *args, **kwargs):
"""Safely execute playback control with error handling."""
try:
action_func(*args, **kwargs)
return True
except SpotifyException as e:
if e.http_status == 403:
print("❌ Premium subscription required for playback control")
elif e.http_status == 404:
print("❌ No active device found")
else:
print(f"❌ Playback error: {e.msg}")
return False
# Examples with error handling
if safe_playback_control(sp.start_playback):
print("✅ Playback started successfully")
if safe_playback_control(sp.next_track):
print("✅ Skipped to next track")
if safe_playback_control(sp.volume, 80):
print("✅ Volume set to 80%")Most playback control features require a Spotify Premium subscription:
start_playback, pause_playback, next_track, previous_track, seek_track, shuffle, repeat, volume, transfer_playback, add_to_queuecurrent_playback, currently_playing, devices, queue (read-only)devices() to check for available devices before attempting playback controlPlayback endpoints have rate limits. Avoid rapid successive calls to prevent API errors.
Install with Tessl CLI
npx tessl i tessl/pypi-spotipy