Skip to main content

A production-quality Spotify CLI in a single Python file

Project description

spopy

PyPI License: MIT Python 3.12+

A production-quality Spotify CLI in a single Python file. Runs anywhere with uv — no install step, no virtualenv, no package manager.

Designed for both local use and self-hosting on a remote gateway (Dokku, VPS, etc.).

Features

  • Single file — one script, zero config files, inline dependencies via PEP 723
  • Two auth modes — local browser login or headless gateway bootstrap (paste-back flow)
  • Persistent tokens — authenticate once, use forever (auto-refresh)
  • Full playback control — play, pause, seek, volume, shuffle, repeat, queue
  • Search and browse — tracks, albums, artists, playlists
  • Playlist management — create, add, remove, reorder, clear, replace
  • Library operations — save, unsave, check, list saved tracks/albums
  • Discovery — top tracks/artists, recently played, genre/mood search
  • Three output modes — rich (human), plain (pipes), JSON (machines)
  • Honest API handling — unsupported endpoints are reported clearly, never faked
  • Safe for servers — never leaks tokens, no secrets in logs or output

Install

PyPI (recommended)

uv tool install spopy

Or with pipx:

pipx install spopy

Script installer

curl -fsSL https://raw.githubusercontent.com/amitkot/spopy/main/install.sh | bash

Standalone script

curl -fsSL https://raw.githubusercontent.com/amitkot/spopy/main/spopy.py -o ~/.local/bin/spopy && chmod +x ~/.local/bin/spopy

The standalone script uses PEP 723 inline deps and runs with uv run spopy.py.

Quick Start

No setup required — spopy includes a built-in Spotify app.

spopy auth login
spopy status
spopy play "bohemian rhapsody"

Remote / headless server

spopy auth url
# Open the printed URL in a browser on another machine
# After approving, copy the command from the callback page
spopy auth callback-url '<paste_the_url>'

Transfer token from local to remote

# On local machine
spopy auth login
spopy auth export-token-info --raw --yes > token.json

# Copy token.json to remote, then:
spopy auth import-token-info token.json

Configuration

All configuration is via environment variables. None are required — spopy works out of the box with PKCE auth.

Auth (all optional)

Variable Default Description
SPOTIFY_CLIENT_ID (built-in) Override with your own Spotify app
SPOTIFY_CLIENT_SECRET Set to switch to classic OAuth flow
SPOTIFY_REDIRECT_URI (auto) Override redirect URI

Setting SPOTIFY_CLIENT_SECRET switches spopy to the classic OAuth flow with your own Spotify app. See spopy auth setup-guide for details.

Runtime (all optional)

Variable Default Description
SPOTIFY_CACHE_PATH ~/.config/spopy/token_cache Token cache file path
SPOTIFY_USERNAME Spotify username (for multi-user)
SPOTIFY_SCOPES (sensible defaults) Override OAuth scopes
SPOTIFY_DEFAULT_DEVICE_ID Fallback device ID
SPOTIFY_DEFAULT_DEVICE_NAME Fallback device name
SPOTIFY_MARKET ISO country code for market
SPOTIFY_OUTPUT rich Default output: rich, plain, json
SPOTIFY_TIMEOUT_SECONDS 15 API request timeout
SPOTIFY_RETRIES 3 Max retry attempts
SPOTIFY_BACKOFF_FACTOR 0.5 Exponential backoff factor
SPOTIFY_DEBUG 0 Enable debug logging (1)
SPOTIFY_OPEN_BROWSER 1 Allow browser opening (0 to disable)
SPOTIFY_NO_COLOR 0 Disable color output (1)
SPOTIFY_STATE_FILE Path to persist auth state

Commands

Global flags

--json          JSON output
--plain         Plain text output (pipe-friendly)
--debug         Debug logging
--market CC     Spotify market (ISO country code)
--device-id ID  Target device ID
--device-name N Target device name
--limit N       Result limit
--offset N      Result offset
--yes           Skip confirmations
--exact         Prefer exact name matches
--interactive   Interactive selection from results
--version       Show version

Auth

Command Description
auth setup-guide First-time setup instructions
auth status Show auth config and token status
auth url Print authorization URL (for gateway flow)
auth login Interactive login (local browser)
auth callback-url <url> Exchange redirect URL for tokens
auth code <code> Exchange raw auth code for tokens
auth import-token-info <path> Import token JSON (- for stdin)
auth export-token-info Export token JSON (--raw for real tokens)
auth whoami Show current user
auth logout Remove token cache

Playback

Command Description
play [query] Play or resume. Search query, URI, URL, or ID
pause Pause playback
resume Resume playback
stop Stop (alias for pause — no true stop API)
next Skip to next track
previous Skip to previous
seek <pos> Seek: 1:30, +10s, -15s, or milliseconds
volume <0-100> Set volume
repeat <off|track|context> Set repeat mode
shuffle <on|off|toggle> Set shuffle

Search

Command Description
search <query> Search (--type track,album,artist,playlist)

Devices

Command Description
devices list List available devices
devices transfer <device> Transfer playback (name or ID)

Track

Command Description
track show <query> Track details
track play <query> Play a track
track queue <query> Add to queue
track save <query> Save to library
track unsave <query> Remove from library
track check <query> Check if saved
track open <query> Print Spotify URL
track audio <query> Audio features (restricted API)

Album

Command Description
album show <query> Album details
album play <query> Play album
album tracks <query> List album tracks
album save <query> Save to library
album unsave <query> Remove from library
album check <query> Check if saved

Artist

Command Description
artist show <query> Artist details
artist top <query> Top tracks (search-based)
artist albums <query> List albums
artist follow <query> Follow artist
artist unfollow <query> Unfollow artist
artist related <query> Related artists (restricted API)

Playlist

Command Description
playlist list Your playlists (--all for full list)
playlist show <pl> Playlist details
playlist create <name> Create (--description, --public/--private)
playlist rename <pl> <name> Rename
playlist describe <pl> <desc> Set description
playlist set-public <pl> Make public
playlist set-private <pl> Make private
playlist follow <pl> Follow playlist
playlist unfollow <pl> Unfollow playlist
playlist items <pl> List items
playlist add <pl> <tracks...> Add tracks
playlist remove <pl> <tracks...> Remove tracks
playlist clear <pl> Remove all items
playlist reorder <pl> Reorder (--from, --to, --length)
playlist replace <pl> <tracks...> Replace all items

Library

Command Description
library tracks Saved tracks
library albums Saved albums
library save <query> Save item
library unsave <query> Remove item
library check <query> Check if saved

Queue

Command Description
queue list Current queue
queue add <query> Add to queue
queue clear Not supported (no API)
queue remove Not supported (no API)

Discovery

Command Description
status Current playback summary
current Detailed now-playing info
recent Recently played tracks
top tracks Your top tracks (--time-range)
top artists Your top artists (--time-range)
discover Discovery suggestions from your history
radio <query> Build a queue from a seed (search heuristic)
genre list Well-known genres
genre search <genre> Search by genre
mood search <mood> Search by mood (heuristic)
doctor Diagnose auth, config, devices, connectivity

Output Modes

Rich (default)

$ spopy status
╭─ Bohemian Rhapsody  —  Queen  (A Night at the Opera) ───╮
│ Playing  2:15 / 5:55                                     │
│ Device: MacBook Pro  |  Volume: 65%  |  Shuffle: off     │
╰──────────────────────────────────────────────────────────╯

JSON

$ spopy --json status
{
  "ok": true,
  "command": "status",
  "data": {
    "name": "Bohemian Rhapsody",
    "artists": "Queen",
    "playing": true,
    "progress": "2:15",
    "duration": "5:55",
    "device": "MacBook Pro"
  }
}

Plain

$ spopy --plain status
Bohemian Rhapsody	Queen	A Night at the Opera	playing	2:15/5:55	MacBook Pro

AI Agent Skill

A Claude Code skill is included for AI agents.

To install it, copy the skills/ directory into your project or Claude Code config:

# Project-level
cp -r skills/ /path/to/your/project/.claude/skills/

# Or user-level
cp -r skills/ ~/.claude/skills/

The skill teaches the agent how to invoke the CLI, parse JSON output, and handle errors.

Exit Codes

Code Meaning
0 Success
2 Invalid user input
3 Auth/config error
4 Spotify API error (Premium required, no device, 403, 404)
5 Rate limit exhausted
10 Internal error

Device Selection

For playback commands, devices are selected in this order:

  1. --device-id flag
  2. --device-name flag
  3. Currently active Spotify device
  4. SPOTIFY_DEFAULT_DEVICE_ID env var
  5. SPOTIFY_DEFAULT_DEVICE_NAME env var
  6. Error with helpful message

Known Limitations

These are Spotify API limitations, not CLI bugs:

  • Queue clear/remove — no API endpoint exists
  • Recommendations — removed from Spotify API (Nov 2024)
  • Audio features — restricted to apps with extended API access
  • Related artists — restricted to apps with extended API access
  • Artist top tracks — removed from API (Feb 2026); CLI uses search fallback
  • Search limit — max 10 results per type (Spotify API limit)
  • Volume control — some devices (phones, smart speakers) don't support remote volume
  • Premium required — all playback control requires Spotify Premium

License

MIT License. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spopy-0.3.1.tar.gz (31.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spopy-0.3.1-py3-none-any.whl (31.3 kB view details)

Uploaded Python 3

File details

Details for the file spopy-0.3.1.tar.gz.

File metadata

  • Download URL: spopy-0.3.1.tar.gz
  • Upload date:
  • Size: 31.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for spopy-0.3.1.tar.gz
Algorithm Hash digest
SHA256 da48ead240434209e5125f32b2aa65f6998b1d96420b5bdef16354486e7852c6
MD5 25db09f32ecf02207bcb3fe8320a8fcb
BLAKE2b-256 d00d55a857d9057f4cc75e3481eca153524c31f4be98882e99ee34ec0725a411

See more details on using hashes here.

File details

Details for the file spopy-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: spopy-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 31.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for spopy-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a28c528b06aee42d55a0978ffecb2309ae1b71eeb907429b2f100324a914b324
MD5 b55e5648038d31c8f33a287ae0bdbd3b
BLAKE2b-256 b12bda3b93a298b5f151861dac156c70c91741ba372d36836f61fc4b277b4994

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page