spotify-cli 0.2.2

A terminal-first Spotify control surface
Documentation

spotify-cli

A terminal-first Spotify control surface.

This started as a small experiment: mostly to learn Rust, partly out of boredom, slightly to smooth over a minor workflow annoyance, and a little bit because it felt easier than not doing it at all.

The result is a CLI that lets you control Spotify without switching context — and that can be composed, scripted, or wired into other tools however you like.


What this is

spotify-cli is a small, scriptable interface to Spotify that exposes common actions — playback, search, library, and playlist management — as plain shell commands.

It doesn’t try to replace Spotify’s UI, and it doesn’t assume how you want to use it. It just runs commands and prints output.


What this is for

This tool is intentionally flexible.

Some things you might use it for:

  • Controlling Spotify without switching windows
  • Driving playback from shell scripts
  • Wiring commands into editors, window managers, or launchers
  • Powering status bars or small widgets
  • Chaining with tools like jq, fzf, or awk
  • Automating playlists and library actions
  • Treating Spotify as something you can script

You don’t need to be a “power user” to use it — but if you are one, it probably fits in nicely.


What this isn’t

This tool is deliberately modest in scope.

It is not:

  • A replacement for Spotify’s desktop or mobile apps
  • A full-featured Spotify client
  • A background daemon or always-on service
  • A UI or TUI with its own interaction model
  • An attempt to reimplement Spotify features
  • Opinionated about how you should use it

spotify-cli focuses on being a small, composable command-line tool. If you want a UI, a long-running service, or an all-in-one solution, this probably isn’t it — but you might be able to use this to help build one, and that’s kind of the point.


Disclaimer

This is provided as-is.

It is over-engineered relative to the problem it solves, and probably under-engineered in places where it could be more polished.

It exists primarily because it was interesting to build.

Use it if it’s useful to you.


Install

Local release build

cargo build --release
mkdir -p ~/.local/bin
cp target/release/spotify-cli ~/.local/bin/spotify-cli

Cargo install

cargo install --path .

Authentication

Spotify app setup (Client ID)

  1. Create a Spotify app at https://developer.spotify.com/dashboard
  2. Copy the Client ID
  3. Add a Redirect URI Default: http://127.0.0.1:8888/callback
  4. Either keep the Client ID handy or export it as SPOTIFY_CLIENT_ID

A note about Spotify APIs

Spotify’s APIs can be unpredictable.

Endpoints, scopes, and behavior sometimes change with little notice or explanation. Things that work today may stop working tomorrow, or behave slightly differently.

This tool does its best to adapt, but it ultimately sits on top of Spotify’s APIs and inherits their quirks.


Auth flow (PKCE OAuth — no client secret)

spotify-cli auth login --client-id <client-id>
spotify-cli auth status
spotify-cli auth scopes
spotify-cli auth logout

Notes:

  • auth login prints an authorization URL and starts a local callback listener
  • Redirect URI can be overridden with --redirect-uri <uri>
  • Tokens and metadata are cached (metadata.json under the cache root)

Global flags

These apply to all commands:

  • --json output machine-readable JSON

Command reference

auth

spotify-cli auth check
spotify-cli auth login [--client-id <id>] [--redirect-uri <uri>]
spotify-cli auth logout
spotify-cli auth scopes
spotify-cli auth status

info

spotify-cli info [album|artist|track|playlist] [query] [--play]

Notes:

  • If the type is omitted, info searches all types and returns the best match.
  • If no query is provided for album/artist/playlist, it uses the currently playing item.

search

spotify-cli search [album|artist|track|playlist] [query] [--play]
spotify-cli search [album|artist|track|playlist] [--last]

Notes:

  • If the type is omitted, search searches all types.
  • If no query is provided, cached results are returned.

nowplaying

spotify-cli nowplaying [--delay-ms <ms>]
spotify-cli nowplaying like
spotify-cli nowplaying addto [query] [--pick <n>] [--last] [--user]

player

spotify-cli player play
spotify-cli player pause
spotify-cli player toggle
spotify-cli player next
spotify-cli player prev
spotify-cli player status
spotify-cli player shuffle <on|off>
spotify-cli player repeat <off|track|context>

playlist

spotify-cli playlist addto [query] [--pick <n>] [--last] [--user]

spotify-cli playlist list
  [--collaborative] [--owned] [--public] [--private]
  [--sort <name|owner|public|collaborative>]

spotify-cli playlist create <name> [--public|--private]
spotify-cli playlist rename [query] <new_name> [--pick <n>] [--last] [--user]
spotify-cli playlist delete [query] [--pick <n>] [--last] [--user]

pin

spotify-cli pin add <name> <url>
spotify-cli pin remove <name>
spotify-cli pin list

device

spotify-cli device list [--live]
spotify-cli device set <name>

sync

spotify-cli sync

queue

spotify-cli queue [--limit <n>]

recentlyplayed

spotify-cli recentlyplayed [--limit <n>]

Design philosophy

This started with a small bit of friction: wanting to like tracks or add them to playlists without switching context while working.

Turning it into a CLI wasn’t a grand architectural choice — it was simply the most straightforward way to experiment, learn Rust, and end up with something reusable.

By keeping it CLI-first:

  • Scripts can use it
  • Editors and tools can shell out to it
  • Output can be piped or parsed
  • The tool stays small and understandable

No daemon. No custom UI. No assumptions about how it should be used.


Examples

Some common commands:

spotify-cli player play|pause|next|prev|status

spotify-cli search artist "The Beatles" --play
spotify-cli search track "The Beatles"
spotify-cli info track

spotify-cli info album "Revolver" --play
spotify-cli info artist "The Beatles"

spotify-cli playlist list --sort name
spotify-cli playlist addto "My Playlist"
spotify-cli pin add "Beatles Essentials" "<url>"

Automation

make release-local

Cache & settings

  • Cache root: ~/.cache/spotify-cli Override with SPOTIFY_CLI_CACHE_DIR
  • Settings:
    • cached playlist/device data is refreshed by spotify-cli sync

Notes

  • playlist addto adds the currently playing track to the chosen playlist
  • The playlist must be writable (owned or collaborative)
  • Pins are local shortcuts, not Spotify objects
  • --user search prefers cached playlists and pins first

Future plans

This project is CLI-first, and that is unlikely to change.

Planned or likely:

  • Hardening the CLI surface

    • More consistent --json output
    • Clearer errors and exit codes
    • Better stability at the command boundary
    • Improve fuzzy logic
  • Small workflow refinements

    • Improvements to interactive flows (--pick, fuzzy search)
    • Quality-of-life tweaks based on real usage

Possible, if there’s interest:

  • Thin, optional integrations
    • Example configs or reference wrappers

Not planned:

  • A persistent daemon
  • A full Spotify client or UI
  • Reimplementing Spotify features
  • Turning this into an ecosystem

Contributions

Contributions are welcome.

Bug fixes, small improvements, and quality-of-life changes are appreciated — especially if they improve reliability or clarity.

The project is intentionally CLI-first and relatively opinionated, so large architectural changes or major expansions may not be a good fit. If you’re unsure, opening an issue or discussion first is always fine.