Skip to main content

Disco Terminal

CI PyPI Python 3.11+ License: MIT

A Spotify client that runs entirely in your terminal. Album art, a real-time cava audio visualizer, full-app color theming, synced lyrics, and playback control — in iTerm2, kitty, or Windows Terminal, without leaving your shell or focusing the Spotify window. Turn your terminal into a disco.

Disco Terminal — now playing with live visualizer

Yes — everything above is a terminal emulator rendering text.

pipx install discoterminal

See it move

Pick a palette and the whole app rethemes — visualizer, borders, buttons, labels:

Switching color palettes live

Eight visualizer styles (area, bars, mirror, peaks, outline, dots, led, rain):

Cycling visualizer styles

Synced lyrics follow the song, Spotify-style; the card flips between now-playing, artist info, and lyrics:

Lyrics and artist card

More demos & screenshots (search, playlists, playback, cards…)

Search anything

Search feature

Playlists sidebar

Playlist selection

Playback controls

Playback controls

Cards & pickers

Artist info card Lyrics card
Color palette picker Visualizer style picker
Queue viewer Collapsed sidebar & visualizer

Visualizer on / off

Visualizer toggle

Built with Textual. Playback control picks the best backend for your platform automatically:

Platform Local control Visualizer audio
macOS shpotify (AppleScript) BlackHole loopback (setup script included)
Linux playerctl (MPRIS) PulseAudio/PipeWire monitor — works out of the box
Windows (experimental) Spotify Web API cava's native WASAPI loopback

The Spotify Web API (OAuth PKCE) powers your library, search, devices, queue, and is the universal control fallback. Override backend selection with {"backend": "shpotify" | "playerctl" | "webapi"} in config.

Features

  • 🎨 Now playing card with album art (sixel/TGP/halfcell), live progress bar, and click-to-seek
  • 📊 Audio visualizer — embedded cava, 8 render styles (area, bars, mirror, peaks, outline, dots, led, rain), 14 color palettes
  • 🌈 Whole-app theming — pick a palette and every border, button, and label recolors to match
  • 🔀 Card flip — artist info (genres, followers, popularity, top tracks) with artist photo
  • 📻 Your playlists in a collapsible sidebar, fetched live from your account
  • 🔍 Search anything — tracks, albums, playlists, artists — pick from a results modal
  • 🎤 Lyrics via lrclib.net (no API key)
  • ♥ Like/unlike the current track, ⏭ queue viewer, 📱 device switcher
  • 🕺 Rave mode — beat-detected palette strobes across the whole app, or a fullscreen VJ takeover (flash rate capped at 4/sec)
  • ⌨️ Everything keyboard-driven; playback via Web API so the Spotify app never steals focus

Install

macOS:

brew install shpotify cava            # local control + visualizer
pipx install discoterminal                 # or: pip install discoterminal
discoterminal

Linux:

sudo apt install playerctl cava       # or your distro's equivalent
pipx install discoterminal
discoterminal

Windows (experimental — testers wanted):

pip install discoterminal                  # control goes through the Web API
discoterminal                              # cava optional; needs a sixel-capable terminal

Requires Python 3.11+ and the Spotify desktop app. The Web API features (playlists, search, queue, lyrics card, artist info) need a Premium account — a Feb 2026 Spotify policy requires Premium for Web-API dev-mode apps. Local playback control via shpotify/playerctl works without Premium.

Spotify API setup (one time)

  1. Go to the Spotify developer dashboard and create an app.

    • If the Web API checkbox is greyed out on the create form (a known dashboard bug): create the app without it, then Edit the app and add Web API there — it won't be greyed out on edit.
  2. Add redirect URI: http://127.0.0.1:8888/callback

  3. Copy the Client ID into ~/.config/discoterminal/config.json:

    { "client_id": "your-client-id-here" }
    

    (or export SPOTIPY_CLIENT_ID=...)

  4. First launch opens a browser to log in once; the token is cached after. No client secret needed — discoterminal uses the PKCE flow.

Visualizer audio setup (macOS only, optional)

Linux and Windows: nothing to do — cava captures system audio natively (PulseAudio/PipeWire monitor, WASAPI loopback).

macOS has no built-in way for apps to hear system output, so cava needs a loopback device:

brew install blackhole-2ch
sudo killall coreaudiod              # load the driver
swift scripts/setup-audio.swift      # create + activate a Multi-Output device

The script builds a "Disco Terminal Multi-Out" device (your speakers + BlackHole) via CoreAudio and switches the system output to it. discoterminal auto-detects BlackHole and points cava at it. Skip all this and the visualizer simply shows a hint instead.

Note: with a Multi-Output device active, macOS volume keys are disabled (aggregate-device limitation). Use discoterminal's +/- — they control Spotify's own volume.

Turn it off / undo:

swift scripts/setup-audio.swift off      # back to speakers (device kept)
swift scripts/setup-audio.swift remove   # back to speakers + delete the device

Re-running without arguments turns it back on. Or just pick any output in System Settings → Sound.

Automatic mode: once the Multi-Out device exists, discoterminal switches to it on launch and restores your previous output on quit — you only run the setup script once, ever. Opt out with {"auto_multiout": false} in config.json.

Keys

Key Action
space Play / pause
n / p Next / previous track
+ / - Volume up / down
l ♥ Like / unlike current track
i Flip card: song ↔ artist info
y Lyrics
u Queue viewer
d Device switcher
/ Search (Enter → results picker)
b Toggle playlist sidebar
v Toggle visualizer
shift+V Visualizer style picker
c Color palette / theme picker
click progress bar Seek
shift+R 🕺 Rave mode: beat-strobing palettes → fullscreen VJ takeover
q Quit

Startup arguments: discoterminal next, discoterminal <playlist name>, discoterminal play artist NF — opens the TUI and runs the action.

Config reference

~/.config/discoterminal/config.json:

Key Values Default
client_id Spotify app client ID —
visualizer_style area bars mirror peaks outline dots led rain area
visualizer_colors aurora synthwave matrix fire ocean mono sunset vaporwave rainbow ice lava candy gold cyberpunk aurora
art_renderer auto sixel tgp halfcell unicode auto
auto_multiout true / false — switch to Multi-Out on launch, restore on quit (macOS) true
backend shpotify playerctl webapi — override auto-selection auto

Development

pip install -e ".[dev]"
pytest
ruff check src tests
mypy src

Tests run headless with mocked Spotify backends — no account or audio setup needed. CI covers Linux, macOS, and Windows.

License

MIT

Metadata

Release files for discoterminal 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for discoterminal 0.3.1
File Size Uploaded
discoterminal-0.3.1.tar.gz 9.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for discoterminal 0.3.1
File Interpreter ABI Platform
discoterminal-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 10.0 MB

Release files / discoterminal-0.3.1.tar.gz

Download URL discoterminal-0.3.1.tar.gz
Size 9.9 MB
Tags Source
SHA-256 checksum
How to use checksums
f20272e32ed53525295ca158baa1cf065c4a57ff6101177ba20967502fa8feba
BLAKE2b-256 checksum
How to use checksums
a4c8621105b08a43d3657c8aab5d2498e16cb73f2142011c4170daf219616ce6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release files / discoterminal-0.3.1-py3-none-any.whl

Download URL discoterminal-0.3.1-py3-none-any.whl
Size 36.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
04c4301d442584e3e16f0a297dfe139d3cf547c7cb3d9f601d662bc88569acd1
BLAKE2b-256 checksum
How to use checksums
744358d9948ffdb470ec2a7ff84c254b994547d54e2ee05094a7a87d3e4ffe3d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page