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

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

### Cargo install

```bash
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)

```bash
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

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

---

### player

```bash
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

```bash
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

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

---

### album

```bash
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

```bash
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

```bash
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

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

---

### system

```bash
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

```bash
spotify-cli help
```

---

### hidden / internal

```bash
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:

```bash
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

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

---

## Automation

```bash
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:
  ```bash
  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.