Skip to main content

Spotify terminal UI — album art, cava audio visualizer, palette theming, lyrics. macOS/Linux, experimental Windows.

Project description

Disco Terminal

CI PyPI Python 3.11+ License: MIT

Turn your terminal into a disco. A Spotify TUI with album art, a real-time cava audio visualizer, full-app color theming, synced lyrics, and playback control — without leaving your shell or focusing the Spotify window.

Disco Terminal — now playing with live visualizer

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
  • ⌨️ 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 "Spotify TUI 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
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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

discoterminal-0.1.0.tar.gz (9.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

discoterminal-0.1.0-py3-none-any.whl (32.4 kB view details)

Uploaded Python 3

File details

Details for the file discoterminal-0.1.0.tar.gz.

File metadata

  • Download URL: discoterminal-0.1.0.tar.gz
  • Upload date:
  • Size: 9.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for discoterminal-0.1.0.tar.gz
Algorithm Hash digest
SHA256 39ce5b6fd3885b4e8a043b8ddc8cd7c8fd321fc92439c1042b90d57cae0fa051
MD5 66bc9b5a90248c3799564a91c63f7eea
BLAKE2b-256 9b7762fcf323eaa47ec4135c76e89e4e2d68d1461af17a6171eef7c60785e513

See more details on using hashes here.

Provenance

The following attestation bundles were made for discoterminal-0.1.0.tar.gz:

Publisher: publish.yml on VinnyVanGogh/discoterminal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file discoterminal-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: discoterminal-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for discoterminal-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7fbfcef2f48777f27f95db57edd435e1053b2c44050bc66fad35b1939f6b7a80
MD5 853d84d5a6711d5e22f11db8f404f54f
BLAKE2b-256 26ce1b7ca365dcd1ceaefd5bd4c8f59a1d274c3584f9f9db24c33ff795aa309f

See more details on using hashes here.

Provenance

The following attestation bundles were made for discoterminal-0.1.0-py3-none-any.whl:

Publisher: publish.yml on VinnyVanGogh/discoterminal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page