cliamp
8 min read
cliamp is a retro terminal music player inspired by Winamp. It plays local files, HTTP/PLS/M3U streams, podcasts (RSS), and a long list of online sources — YouTube, YouTube Music, SoundCloud, Bandcamp, Bilibili, Spotify, NetEase Cloud Music, Xiaoyuzhou — as well as self-hosted libraries via Navidrome, Plex, Jellyfin/Emby. It features a spectrum visualizer (20+ modes), a 10-band parametric EQ, playlist management, lyrics, themes, and an IPC remote-control interface.
Written in Go with the Charm stack (Bubble Tea, Lip Gloss), Beep for audio, and go-librespot for Spotify.
sh
cliamp ~/Music # play a directory (recursive)
cliamp *.mp3 *.flac # play specific files
cliamp https://example.com/stream # play a URL / stream / podcast feed
cliamp # no args → built-in radio (or Navidrome browser if configured)
Press ? or Ctrl+K in the player to see every keybinding.
Install
sh
curl -fsSL https://raw.githubusercontent.com/bjarneo/cliamp/HEAD/install.sh | sh
brew install bjarneo/cliamp/cliamp # Homebrew (pulls in codec libs)
yay -S cliamp # Arch (AUR)
Pre-built binaries are on GitHub Releases. On Linux these statically link FLAC/Vorbis/Ogg (no codec packages needed); on macOS they dynamically link those from Homebrew (brew install flac libvorbis libogg), which the brew formula handles for you.
Optional runtime dependencies:
Sources & streaming
cliamp handles a wide range of inputs both as CLI arguments and via the u (load URL) key at runtime:
• HTTP streams — direct audio URLs; non-seekable streams show ● Streaming with ICY (StreamTitle) now-playing metadata.
• M3U / M3U8 / PLS playlists — local or remote, with #EXTINF titles/durations and relative-path resolution. See m3u.
• Podcasts — pass any RSS/Atom feed URL; episodes (titles + <itunes:duration>) are extracted into the playlist.
• Radio catalog — press R to browse/search 30,000+ stations from Radio Browser. Add your own to ~/.config/cliamp/radios.toml.
• yt-dlp sources — YouTube/SoundCloud/Bandcamp/Bilibili/NetEase links play through yt-dlp.
You can run your own station with cliamp-server.
Providers
Remote music providers are configured fastest via the interactive wizard, which validates the connection live and writes the right TOML block:
sh
cliamp setup
Supported: Navidrome, Plex, Jellyfin, Emby, Spotify, YouTube Music, NetEase. Provider hotkeys in the player: N Navidrome, S Spotify, P Plex, J Jellyfin, E Emby, Y YouTube, C SoundCloud, M NetEase, R Radio, L local playlists. Ctrl+F runs the active provider's native search (falling back to YouTube). Set a startup provider with provider = "..." or --provider.
SoundCloud and NetEase are opt-in and authenticate by borrowing your browser's cookie jar (cookies_from = "firefox" etc.) via yt-dlp, since neither offers a usable public OAuth flow.
Configuration
Config lives in ~/.config/cliamp/config.toml (TOML). Copy config.toml.example and edit, or let cliamp setup manage provider blocks.
toml
volume = 0 # default volume in dB (volume_min..6)
volume_min = -50 # volume floor in dB
repeat = "off" # off | all | one
shuffle = false
mono = false # L+R downmix
initial_directory = "~/Music"
seek_large_step_sec = 30 # Shift+arrow seek jump
eq_preset = "Flat" # or Custom/empty to use manual eq[] below
eq = [0,0,0,0,0,0,0,0,0,0] # 10-band gains, -12..12 dB
visualizer = "Bars"
low_power = false # lower UI cadence, disable visualizer
compact = false # cap UI width at 80 columns
theme = "Tokyo Night"
log_level = "info" # → ~/.config/cliamp/cliamp.log
Secrets from env vars: any string whose entire value is $VAR or ${VAR} is read from the environment, keeping passwords and tokens out of the file:
toml
[navidrome]
url = "https://music.example.com"
user = "alice"
password = "${NAVIDROME_PASSWORD}"
Audio quality
Tune the output engine (also exposed as CLI flags). The active settings show in the OUT status line under the EQ; changes take effect on next launch.
| Option | Default | Notes |
|---|---|---|
sample_rate | 44100 | 22050 / 44100 / 48000 / 96000 / 192000 Hz |
buffer_ms | 100 | 50–500; raise to ~200 if audio pops |
resample_quality | 4 | 1–4 sinc quality (4 best, 1 fastest) |
bit_depth | 16 | 16 or 32 (float PCM, lossless) for ffmpeg-decoded formats |
CLI
Flags override config for one session (not persisted) and may appear before/after file arguments.
sh
cliamp --shuffle --volume -5 ~/Music
cliamp --repeat all --auto-play ~/Music
cliamp --eq-preset "Bass Boost" --sample-rate 48000 track.flac
cliamp --playlist "Blade Runner" --auto-play # load a local TOML playlist
cliamp --low-power track.mp3 # battery / slow terminal / SSH
cliamp --compact ~/Music # 80-column layout
Key flags: --volume (-30..+6 dB), --shuffle, --repeat, --mono/--no-mono, --auto-play, --theme, --eq-preset, --sample-rate, --buffer-ms, --resample-quality, --bit-depth, --playlist, --log-level, --low-power, --daemon/-d. --help, --version, --upgrade for housekeeping.
Subcommands
sh
cliamp setup # provider config wizard
cliamp search "never gonna give..." # search & play from YouTube (yt-dlp)
cliamp search-sc "lofi beats" # search SoundCloud
cliamp playlist list|create|add|show|remove|delete # manage local playlists
cliamp history [--limit N|--json|clear] # recently played (50%+ counts as a play)
cliamp spotify reset # clear stored Spotify credentials
cliamp plugins list|install|remove # Lua plugin manager
Keybindings
A condensed view (?/Ctrl+K shows the full map):
| Key | Action | Key | Action |
|---|---|---|---|
Space | play/pause | s | stop |
> < / . , | next / prev | ← → | seek ±5s |
Shift+←/→ | seek ±30s | Ctrl+J | jump to time |
+ - | volume | ] [ | speed ±0.25× |
m | toggle mono | e | cycle EQ preset |
t | theme picker | v / Ctrl+V | cycle / pick visualizer |
V | fullscreen visualizer | Tab | focus playlist ↔ EQ |
o | file browser | / | search playlist (fuzzy) |
f | bookmark ★ / favorite station | y | lyrics |
Ctrl+S | save track to ~/Music | Ctrl+F | provider search |
a | queue (play next) | A | queue manager |
p | playlist manager | r | cycle repeat |
z | toggle shuffle | q | quit |
Local search boxes (/ and Ctrl+F on the Local provider) match fuzzily — query chars need only appear in order (skr finds "Sakura"). Other providers use their own server-side search.
Playlists
Two kinds:
• M3U/PLS files loaded as arguments (with EXTINF metadata and relative paths).
• Local TOML playlists in ~/.config/cliamp/playlists/, one .toml per playlist (filename = name), managed in-app with the p key or from the CLI (cliamp playlist ...).
toml
# ~/.config/cliamp/playlists/favorites.toml
[[track]]
path = "/home/user/Music/song.mp3"
title = "Great Song"
artist = "Good Artist"
[[track]]
path = "https://feeds.simplecast.com/54nAGcIl"
title = "The Daily"
feed = true # resolve an RSS feed into episodes
Each [[track]] takes path (file or URL, required), title (required), artist (optional), and feed = true to expand a podcast feed (URLs ending .xml/.rss/.atom auto-detect). Removing the last track auto-deletes the file. A virtual "Recently Played" entry appears in the Local Playlists provider.
Lyrics
Press y to fetch lyrics from LRCLIB and NetEase. Local and Navidrome tracks get synced lyrics (auto-scroll, active-line highlight); streams and untimed lyrics use manual scroll (j/k). Stream lyrics refresh on ICY metadata changes.
Themes
20 built-in themes (tokyo-night, catppuccin, gruvbox, kanagawa, nord, dracula, rose-pine, everforest, neon-blade-runner, vantablack, hackerman, …). Press t for the live-preview picker; the choice is saved. Add custom themes as ~/.config/cliamp/themes/<name>.toml with six hex colors (a same-named file overrides a built-in):
toml
accent = "#268bd2" # title, track name, seek bar, selection
bright_fg = "#eee8d5" # primary text
fg = "#839496" # muted/secondary text
green = "#859900" # playing indicator, spectrum low
yellow = "#b58900" # spectrum middle
red = "#dc322f" # spectrum top, errors
Media controls (MPRIS / NowPlaying)
cliamp integrates with the OS media layer, so hardware media keys and desktop tooling work without touching the TUI:
• Linux — registers org.mpris.MediaPlayer2.cliamp over D-Bus; control with playerctl play-pause, next, etc.
• macOS — MPNowPlayingInfoCenter / remote command center (built-in).
Remote control (IPC)
A running instance listens on a Unix socket at ~/.config/cliamp/cliamp.sock (perms 0600, stale-socket cleanup via a PID file). Drive it from another terminal, a script, or a status bar:
sh
cliamp toggle # play/pause
cliamp next && cliamp status --json | jq .track.title
cliamp volume -5 # dB
cliamp seek 30 # seconds
cliamp load "Blade Runner" # load a playlist
cliamp eq Rock # set EQ preset
cliamp eq --band 0 6.0 # set one EQ band
cliamp device list # list / switch output devices
cliamp visstream --fps 60 # NDJSON 10-band spectrum frames
The protocol is newline-delimited JSON ({"cmd":"status"} → {"ok":true,...}). status --json reports state, track, position/duration, volume, playlist index, visualizer, and the active theme's resolved hex colors. visstream powers external visualizers like the Quickshell now-playing widget.
Headless daemon
Run without a TUI, exposing the same IPC surface — for background playback, status bars, hotkey daemons, or cron:
sh
cliamp --daemon --auto-play --playlist "Lofi"
UI-only IPC commands (theme, vis) error in this mode, and there's no MPRIS bridge — wire media keys to cliamp subcommands directly. Stop with SIGINT/SIGTERM (resume position is saved). A minimal systemd user unit or Hyprland/Waybar binding makes a tidy always-on player.
Plugins
A Lua 5.1 plugin system (~/.config/cliamp/plugins/); each plugin runs in an isolated, sandboxed VM (no os.execute) so a crash can't take down the player. Two types: hooks (react to events — scrobbling, notifications, status-bar output) and custom visualizers.
lua
local p = plugin.register({ name = "now-playing", type = "hook" })
p:on("track.change", function(track)
cliamp.fs.write("/tmp/cliamp-now-playing", track.artist .. " - " .. track.title)
end)
Events include track.change, playback.state, player.seek, player.volume, player.eq, player.mode, and queue.change (diffed from state, so they fire regardless of source). The cliamp.* API exposes player getters, cliamp.http, cliamp.fs, etc. Install from GitHub/GitLab/Codeberg or a URL:
sh
cliamp plugins install bjarneo/cliamp-plugin-lastfm@v1.0
Repos must be named cliamp-plugin-<name> with <name>.lua at the root; the prefix is stripped on install.
Troubleshooting
• Silence, no errors (Linux): the ALSA backend needs a bridge to your sound server — install pipewire-alsa or pulseaudio-alsa.
• WSL2: install libasound2-plugins and route ALSA through PulseAudio via ~/.asoundrc (pcm.default pulse / ctl.default pulse); WSLg must be active.
• macOS Library not loaded: libvorbisenc...: install codecs with brew install flac libvorbis libogg (or install via the brew tap).