tuify

command module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 3 Imported by: 0

README

Tuify

A terminal-based Spotify client. Browse playlists, search for music and podcasts, control playback — Spotify without all the noise.

CI Go Report Card Go Windows macOS Linux

Tuify screenshot Tuify visualizers

Features

  • Playback Control — Play, pause, skip, previous, shuffle, seek
  • Playlists — Browse and play your Spotify playlists
  • Podcasts — Browse saved shows and episodes
  • Search — Find tracks, episodes, artists, albums, and shows
  • Now Playing — Live progress bar, track info, shuffle state, active device indicator
  • Device Selector — Switch playback between Spotify Connect devices
  • Mini Mode — Compact single-line view with track info and progress
  • Mouse Support — Scroll wheel to navigate lists, click to select, double-click to play or drill down
  • Visualizers — Album art, starfield, spectrum, oscillogram, spectrogram, VU meter, and Milkdrop-style presets (spiral, tunnel, kaleidoscope, ripple)
  • Lyrics — Fetches and displays lyrics from Genius.com
  • Dark & Light Terminals — Adaptive color palette that adjusts automatically

Requirements

Install

macOS / Linux
brew install lounge/tap/tuify
Windows

Install Scoop, then:

scoop bucket add lounge https://github.com/lounge/scoop-bucket
scoop install tuify
Direct download

Pre-built binaries for all platforms are available on the Releases page.

Getting Started

  1. Go to https://developer.spotify.com/dashboard and create an app
  2. Set the redirect URI to http://127.0.0.1:4444/callback
  3. Check the Web API checkbox
  4. Copy your Client ID
  5. Run tuify — it will ask for your Client ID on first launch
  6. A browser window will open to authorize with Spotify

Keybindings

Key Action
Enter Select / play
Esc Go back
Space Play / pause
n Next track
p Previous track
a / d Seek backward / forward
r Toggle shuffle
s Stop
c Copy track link
/ Search
v Toggle visualizer
/ Cycle visualizers
Tab Device selector
m Toggle mini mode
h Show help overlay
q Quit
Search Shortcuts

Type a prefix in the search bar to filter by type:

Prefix Searches
t: Tracks (default)
e: Episodes
a: Artists
l: Albums
s: Shows
Vim Mode

Enable vim-style keybindings by setting "vim_mode": true in your config file.

Key Action
h / l Go back / select
j / k Cursor down / up
g / G Jump to first / last item
Ctrl+d / Ctrl+u Half-page down / up
, / . Seek backward / forward
? Show help overlay

Visualizers

Visualizer Requires Librespot
Album Art No
Lyrics No
Spectrum Yes
Starfield Yes
Oscillogram Yes
Spectrogram Yes
VU Meter Yes
Milkdrop Spiral Yes
Milkdrop Tunnel Yes
Milkdrop Kaleidoscope Yes
Milkdrop Ripple Yes

Album Art and Lyrics work out of the box. The audio-reactive visualizers require librespot — see the section below.

Librespot (Optional)

Librespot is an open-source Spotify Connect client. Installing it unlocks direct audio streaming and all audio-reactive visualizers.

Setup
  1. Install librespot and make sure it's in your PATH
  2. Set "enable_librespot": true in ~/.config/tuify/config.json
  3. Restart tuify — it will connect as a Spotify device automatically

If the connection drops, tuify detects the failure, restarts librespot, and transfers playback back automatically. If you manually switch to another device in Spotify, tuify respects that and won't reclaim playback. When librespot becomes inactive (playback moved away), the UI updates immediately via Spotify Connect signals — no API polling delay.

Librespot Config

Add these to ~/.config/tuify/config.json:

Option Default Description
enable_librespot true Enable librespot integration
librespot_path "librespot" Path to librespot binary
device_name "tuify" Spotify Connect device name
bitrate 320 Audio bitrate (96, 160, or 320 kbps)
audio_backend "pipe" Audio backend (see below)
spotify_username "" Spotify username for direct auth
Audio Backends

Only "pipe" enables audio-reactive visualizers.

Backend Description
pipe Audio piped through tuify for playback and visualizers. Default and recommended.
rodio Cross-platform audio output. Librespot's built-in default.
alsa Direct ALSA output (Linux).
pulseaudio Audio via PulseAudio (Linux).

Other backends (jackaudio, portaudio, gstreamer, sdl) require enabling cargo features when building librespot. See the librespot Audio Backends wiki.

Configuration

All configuration is stored in ~/.config/tuify/ (or $XDG_CONFIG_HOME/tuify/).

Option Default Description
client_id "" Spotify Developer App Client ID
redirect_url "http://127.0.0.1:4444/callback" OAuth callback URL (must match your Spotify app settings)
vim_mode false Enable vim-style keybindings
appearance "" (auto) Force "dark" or "light" palette. Empty/omitted uses terminal-background autodetection.
theme (see below) Per-role color overrides (light + dark)
Theme

The theme block lets you override every UI color. Each role takes a {light, dark} hex pair, so the override picks up automatically based on the terminal's background. First-time setup writes the current defaults into config.json, so opening the file shows you the full set ready to edit. Removing a role (or setting either hex to "") falls back to the built-in default for that mode. Each color must be #RGB or #RRGGBB.

What each role drives:

Role Where you see it
primary Selected list item, now-playing track title, active home tab background, search prefix, progress bar gradient start, spinner
secondary Now-playing play/pause icon, search input text, overlay box borders, active-device icon
muted Breadcrumb, device list secondary text, inactive device names
subtle Overlay box content, help descriptions, selected list descriptions, loading text, progress bar timestamps
dim Empty progress bar track, dimmed list descriptions
error Error rows in lists, error banners in the now-playing area
text List item titles, status line, help command names, dialog titles
text_dim List item descriptions, dimmed list titles
tip End glyph of the progress bar gradient (●)
on_primary Text rendered on top of a primary background (active home tab label)
gradient_start / gradient_end Top and bottom of the now-playing area background gradient
{
  "theme": {
    "primary":        { "light": "#874BFD", "dark": "#58f796" },
    "secondary":      { "light": "#6232CC", "dark": "#b48eff" },
    "muted":          { "light": "#9B9B9B", "dark": "#626262" },
    "subtle":         { "light": "#6C6C6C", "dark": "#8a8a8a" },
    "dim":            { "light": "#BCBCBC", "dark": "#444444" },
    "error":          { "light": "#FF0000", "dark": "#ff0087" },
    "text":           { "light": "#1a1a1a", "dark": "#dddddd" },
    "text_dim":       { "light": "#A49FA5", "dark": "#777777" },
    "tip":            { "light": "#D4A017", "dark": "#FFD866" },
    "on_primary":     { "light": "#000000", "dark": "#000000" },
    "gradient_start": { "light": "#e4d4f7", "dark": "#110a24" },
    "gradient_end":   { "light": "#f8f5fc", "dark": "#040208" }
  }
}

Logs

Tuify writes a debug log to ~/.config/tuify/debug.log on each run. The log is overwritten every time you start tuify. Check this file if something isn't working as expected.


Development

Build from source

Requires Go 1.26+. On Linux, also install libasound2-dev.

git clone https://github.com/lounge/tuify.git
cd tuify
go build
go test ./...
golangci-lint run ./...   # matches CI; catches formatting + lint issues
Architecture
Package Description
internal/bootstrap Application bootstrap — config, auth, librespot wiring, composition root
internal/ui TUI views, components, and visualizers (Bubble Tea + Lip Gloss)
internal/spotify Spotify Web API client (zmb3/spotify)
internal/audio Real-time audio pipeline — FFT analysis, PCM pipe reader (oto)
internal/librespot Librespot process lifecycle
internal/lyrics Genius.com lyrics scraping
internal/auth OAuth2 PKCE authentication
internal/config Configuration management
internal/theme Color palette + user theme overrides applied at startup
internal/testutil Test-only helpers shared across packages (HTTP stubbing)

TODO

License

MIT

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
internal
audio
Package audio provides the PCM ingest and FFT analysis that feed the TUI's visualizers.
Package audio provides the PCM ingest and FFT analysis that feed the TUI's visualizers.
auth
Package auth handles Spotify OAuth2 with PKCE: interactive login via a local callback server, token persistence on disk, and proactive token refresh to avoid blocking API calls on an expiring token.
Package auth handles Spotify OAuth2 with PKCE: interactive login via a local callback server, token persistence on disk, and proactive token refresh to avoid blocking API calls on an expiring token.
bootstrap
Package bootstrap wires together the application's startup sequence: loading or interactively creating config, authenticating against Spotify, starting optional librespot playback, and launching the Bubbletea TUI.
Package bootstrap wires together the application's startup sequence: loading or interactively creating config, authenticating against Spotify, starting optional librespot playback, and launching the Bubbletea TUI.
config
Package config manages the tuify config file.
Package config manages the tuify config file.
librespot
Package librespot manages the lifecycle of an external librespot subprocess: spawning it with the configured bitrate, backend, and device name; watching stdout for connection/state events; piping PCM audio to the audio package when backend=="pipe"; and invoking user-supplied callbacks on reconnect and inactivity.
Package librespot manages the lifecycle of an external librespot subprocess: spawning it with the configured bitrate, backend, and device name; watching stdout for connection/state events; piping PCM audio to the audio package when backend=="pipe"; and invoking user-supplied callbacks on reconnect and inactivity.
lyrics
Package lyrics fetches song lyrics for the visualizer's lyrics panel.
Package lyrics fetches song lyrics for the visualizer's lyrics panel.
spotify
Package spotify wraps the zmb3/spotify Web API client with the higher-level operations tuify needs: playlist and library fetches, player state polling, playback control, device selection, and transfer-on-reconnect behavior.
Package spotify wraps the zmb3/spotify Web API client with the higher-level operations tuify needs: playlist and library fetches, player state polling, playback control, device selection, and transfer-on-reconnect behavior.
testutil
Package testutil holds test-only helpers shared across the other internal packages.
Package testutil holds test-only helpers shared across the other internal packages.
theme
Package theme owns the application color palette and the bridge from user config (a Theme struct deserialized from config.json) into the mutable lipgloss colors used by package ui.
Package theme owns the application color palette and the bridge from user config (a Theme struct deserialized from config.json) into the mutable lipgloss colors used by package ui.
ui
Package ui is the Bubble Tea-based terminal UI for tuify.
Package ui is the Bubble Tea-based terminal UI for tuify.
ui/visualizers
Package visualizers holds the pluggable Visualizer implementations rendered on top of the now-playing view when the user toggles on the visualizer pane.
Package visualizers holds the pluggable Visualizer implementations rendered on top of the now-playing view when the user toggles on the visualizer pane.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL