A boring Spotify CLI client
Project description
Spotidry
Spotidry is a deliberately minimal Spotify CLI for status bars, hotkeys, and quick playback control.
It prints the current track in a compact one-line format, lets you toggle the current song in your Liked Songs, and exposes the playback controls you need without turning your terminal into a full music client.
What it does well
- Print the current Spotify status in a customizable format.
- Toggle the current track in your Liked Songs with a single command.
- Control playback with play/pause, next, and previous actions.
- Scroll long artist/title strings cleanly in narrow status bars.
- Reuse recent playback data to keep 1 Hz status lines responsive and avoid unnecessary Spotify requests.
Installation
Install from PyPI with uv:
uv tool install spotidry
spotidry --setup
Or install with pip:
pip install --user spotidry
spotidry --setup
Spotidry is tested on Linux across Python 3.10 through 3.14.
Spotify setup
Run spotidry --setup to create the config file interactively. The command opens the Spotify Developer Dashboard and prompts you for the values it needs.
- Create a Spotify app at My Dashboard.
- Make sure the app has Web API enabled.
- Set a redirect URI such as
http://127.0.0.1:9999. - Paste the Client ID, Client Secret, and Redirect URI into the setup prompt.
If you prefer to create the config manually, write this file to ~/.config/spotidry/spotidry.yaml:
client_id: '<ID>'
client_secret: '<SECRET>'
redirect_uri: 'http://127.0.0.1:9999'
output_format: '{play_symbol} {artist_song} {liked_symbol}'
# Optional: scrolling for long titles (useful for 1 Hz status lines)
max_width: 30
scroll_speed: 0.5
scroll_gap: ' '
# Optional: reuse recent playback data between CLI invocations
status_cache_seconds: 5
On the first normal run, Spotidry opens a browser window so you can authorize access to your Spotify account.
Configuration
Output placeholders
output_format supports these placeholders:
{artist}: artist name{song}: track title{artist_song}:"{artist} - {song}", including scrolling when enabled{play_symbol}: playback indicator (▶or⏸){liked_symbol}: liked indicator (❤or♡)
The default output format is:
{play_symbol} {artist_song} {liked_symbol}
Caching and rate limits
status_cache_seconds controls how often Spotidry asks Spotify for fresh playback data. The default of 5 works well for 1 Hz status bars while keeping API traffic low.
- Increase it if your status line refreshes frequently and you still hit rate limits.
- Set it to
0to fetch fresh data on every invocation.
Recent playback data is cached at ~/.cache/spotidry/status_cache.json. If Spotify temporarily replies with 429 Too Many Requests, Spotidry can keep showing the most recent cached status instead of waiting on a long retry window.
Usage
Common commands:
spotidry
spotidry --save
spotidry --play
spotidry --next
spotidry --previous
spotidry --volume-show
spotidry --volume-up
spotidry --volume-down
spotidry --setup
CLI help:
usage: spotidry [-h] [-v] [-s] [-S] [-p] [-n] [--previous] [--volume-show]
[--volume-up] [--volume-down]
Spotify CLI client
options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-s, --save toggle liked track status
-S, --setup setup spotidry configuration
-p, --play play/pause track
-n, --next play next track
--previous play previous track/skip to beginning of current track
--volume-show print current device volume
--volume-up increase current device volume by 10%
--volume-down decrease current device volume by 10%
The volume commands print only the current volume. They do not add volume to the default spotidry status line.
If you need to re-authorize Spotify, delete the auth cache at ~/.cache/spotidry.json and run Spotidry again. If you are upgrading from an older release, re-authorizing may be necessary for the new playback-state scope used by the volume commands.
Tmux integration
Example for the popular .tmux config:
tmux_conf_theme_status_right='#(flock -n /tmp/spotidry.lock spotidry 2>/dev/null; sleep 1) #{prefix}#{pairing} #{?battery_status, #{battery_status},}#{?battery_bar, #{battery_bar},}#{?battery_percentage, #{battery_percentage},} , %R , %d %b | #{username}#{root} | #{hostname} '
This redraws once per second for smooth scrolling. With the default status_cache_seconds: 5, Spotify is still refreshed only about once every 5 seconds.
If you do not need 1 Hz scrolling, increase the shell sleep to reduce API traffic even further.
Polybar integration
Add this module to ~/.config/polybar/config.ini:
[module/spotidry]
type = custom/script
exec = ~/.local/bin/spotidry
exec-if = test -f ~/.local/bin/spotidry
click-left = ~/.local/bin/spotidry --next 2> /dev/null
click-middle = ~/.local/bin/spotidry --save 2> /dev/null
click-right = ~/.local/bin/spotidry --play 2> /dev/null
interval = 1
This uses interval = 1 for smooth scrolling. With the default cache settings, Spotify is still refreshed only about once every 5 seconds.
To reduce API traffic further, either raise status_cache_seconds or increase the Polybar interval.
Development
Set up a local development environment:
git clone https://github.com/mikeboiko/spotidry.git
cd spotidry
uv sync --extra test
The repository pins the local development interpreter to Python 3.14 via .python-version, so uv will pick that version automatically when available.
Useful development commands:
uv run pytest -q
uv run basedpyright spotidry
uv run spotidry --help
Release automation
GitHub Actions handles validation and publishing:
- Tests runs on every push, pull request, and manual dispatch.
- Publish to PyPI runs after a successful
Testsrun onmaster. - A release is only created when
spotidry/__init__.pychanges and the version is bumped.
Routine commits should leave spotidry/__init__.py and CHANGELOG.md alone. Update them together only when preparing an actual release.
When a release is triggered, GitHub Actions will:
- Create and push the matching Git tag.
- Build the source distribution and wheel.
- Validate the package with
twine check. - Create a GitHub Release with the built artifacts.
- Publish the package to PyPI.
Make sure the repository has a PYPI_API_TOKEN secret configured.
Contributing
Issues and pull requests are welcome.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file spotidry-0.0.11.tar.gz.
File metadata
- Download URL: spotidry-0.0.11.tar.gz
- Upload date:
- Size: 42.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6acad40fc216f1edd0fc930a010c09ca8ff32a7f7f7faa6be4bb6fbe0c732034
|
|
| MD5 |
c8a08cb6493e898f1e24bc75f6f172a6
|
|
| BLAKE2b-256 |
2fcf2f6451084a1e2387338129bddf05b7e455eacbb34fa57908aca4c7fc751a
|
File details
Details for the file spotidry-0.0.11-py3-none-any.whl.
File metadata
- Download URL: spotidry-0.0.11-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28b0c2e75d8db6dda6b046e8b7dc2ee770ff33894f6406200b22cf9d81f6fd75
|
|
| MD5 |
0697be569a8161c8eadf7daf36da28c8
|
|
| BLAKE2b-256 |
b6c3bd170f6b0d87fbf68e03683ce485a0a7d3ff37ccaec8420872d65c8ca3da
|