spotify-cli 0.1.0

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
  • -v, --verbose show confirmations and now-playing info
  • --width N cap table column width
  • --no-trunc disable truncation

Command reference

auth

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

player

spotify-cli player play
spotify-cli player pause
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>

track

spotify-cli track search [query] [--fuzzy] [--user] [--limit <n>] [--pick <n>] [--last] [--play]
spotify-cli track like
spotify-cli track unlike
spotify-cli track info

search

spotify-cli search [query]
  [--type <all|track|album|artist|playlist>]
  [--fuzzy] [--user] [--limit <n>] [--pick <n>] [--last] [--play]

album

spotify-cli album search [query] [--fuzzy] [--user] [--limit <n>] [--pick <n>] [--last] [--play]
spotify-cli album info   [query] [--search <query>] [--fuzzy] [--user] [--pick <n>] [--last]
spotify-cli album play   [query] [--search <query>] [--fuzzy] [--user] [--pick <n>] [--last]

artist

spotify-cli artist search [query] [--fuzzy] [--user] [--limit <n>] [--pick <n>] [--last] [--play]
spotify-cli artist info   [query] [--search <query>] [--fuzzy] [--user] [--pick <n>] [--last]
spotify-cli artist play   [query] [--search <query>] [--fuzzy] [--user] [--pick <n>] [--last]

playlist

spotify-cli playlist search [query] [--fuzzy] [--user] [--limit <n>] [--pick <n>] [--last] [--play]

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

spotify-cli playlist info [query] [--fuzzy] [--user] [--pick <n>] [--last]
spotify-cli playlist play [query] [--url <url>] [--fuzzy] [--user] [--pick <n>] [--last]
spotify-cli playlist add  [query] [--fuzzy] [--user] [--pick <n>] [--last]
spotify-cli playlist follow   [query] [--fuzzy] [--user] [--pick <n>] [--last]
spotify-cli playlist unfollow [query] [--fuzzy] [--user] [--pick <n>] [--last]

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

device

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

system

spotify-cli system sync
spotify-cli system cache status
spotify-cli system cache country [code]
spotify-cli system cache user [name]
spotify-cli system completions <bash|zsh|fish> [--install]

help

spotify-cli help

hidden / internal

spotify-cli sync
spotify-cli cache status|country [code]|user [name]
spotify-cli completions <bash|zsh|fish> [--install]
spotify-cli complete playlist|pin|device

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 "The Beatles" --type artist --play
spotify-cli search "The Beatles" --type track
spotify-cli track info

spotify-cli album search "Abbey Road" --play
spotify-cli album info "Revolver"

spotify-cli artist play "The Beatles"

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

Shell completions

spotify-cli completions zsh --install
spotify-cli completions bash --install
spotify-cli completions fish --install

Automation

make release-local

Cache & settings

  • Cache root: ~/.cache/spotify-cli Override with SPOTIFY_CLI_CACHE_DIR
  • Settings:
    • spotify-cli cache country <code>
    • spotify-cli cache user "<name>"
  • For cached playlist and device completions, run:
    spotify-cli sync
    

Notes

  • playlist add 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.