██████ ██ ██ █████ ███ ███ ██████ ██ ██ ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ███████ ██ ████ ██ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████ ███████ ██ ██ ██ ██ ██ ██
Playlists, EQ, visualizers, lyrics, remote control, and a Lua plugin system. Streams from Spotify, YouTube Music, Plex, Jellyfin, Navidrome, and 30,000+ radio stations.
$ cliamp https://radio.cliamp.stream/lofi/stream.pls
$ curl -fsSL …/install.sh | sh
COPIED
$ brew install bjarneo/cliamp/cliamp
COPIED
$ yay -S cliamp
COPIED
Stream from everywhere. Every provider runs through the same playlist, EQ, visualizer, and lyrics pipeline — your config follows you across services.
cliamp search-sc from the shell.Parametric EQ with presets: Rock, Jazz, Pop, Classical, and more.
17 built-in themes and multiple visualizer modes. Hot-swap with t / v.
TOML playlists, M3U/M3U8/PLS support, built-in playlist manager.
Play from URLs, internet radio, and remote M3U playlists.
Auto-scrolling lyrics for local & Navidrome tracks. Press y.
Seamless transitions with preloaded next-track buffering.
Desktop integration. Hardware media keys and playerctl.
Configurable sample rate (22kHz–192kHz), buffer size, resample.
ICY/Shoutcast metadata — current song on internet radio streams.
ID3v2, Vorbis comments, MP4 atoms — artist, album, genre, year.
Override volume, shuffle, repeat, theme, EQ, sample rate per-session.
Run --upgrade to update to the latest release in-terminal.
Control a running instance from another terminal via Unix-socket IPC.
Lua 5.1 sandboxed plugin system. Hook events, add visualizers, push data.
Press Ctrl+S to save the current track to ~/Music.
17 built-in themes. Press t to switch, or use --theme "name" from the CLI.
Drop a .toml file in ~/.config/cliamp/themes/ to add your own.
CLI flags override any config option for a single session.
Remote commands control a running instance over Unix-socket IPC — open another terminal and talk to cliamp directly.
Lua 5.1 plugin system. Hook into playback events, add custom visualizers, or push data to external services.
Each plugin runs in an isolated sandbox — a crash in one cannot affect others or the player.
Drop a .lua file in ~/.config/cliamp/plugins/ and restart.
-- ~/.config/cliamp/plugins/now-playing.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) p:on("app.quit", function() cliamp.fs.remove("/tmp/cliamp-now-playing") end)
-- ~/.config/cliamp/plugins/webhook.lua local p = plugin.register({ name = "webhook", type = "hook", }) local url = p:config("url") p:on("track.change", function(track) if not url then return end cliamp.http.post(url, { json = { title = track.title, artist = track.artist } }) end)
-- ~/.config/cliamp/plugins/simple-bars.lua local p = plugin.register({ name = "simple-bars", type = "visualizer", }) -- Called ~20 FPS. bands: 10 values (0.0-1.0) function p:render(bands, frame) local lines = {} for row = 5, 1, -1 do local line = "" for i = 1, 10 do if bands[i] > (row - 1) / 5 then line = line .. "██████ " else line = line .. " " end end table.insert(lines, line) end return table.concat(lines, "\n") end
Read-only state: state(), position(), volume(), shuffle(), eq_bands()…
Current metadata: title(), artist(), album(), genre(), duration_secs()
HTTP client: get(), post(). JSON, form body, headers, 5s timeout.
Sandboxed I/O: write(), read(), append(), remove(), exists()
encode() and decode() for JSON serialization.
md5(), sha256(), hmac_sha256() for hashing and signing.
Desktop notifications via notify-send. Works with mako, dunst, etc.
message(text, secs) → transient message in the player's status bar.
Schedule callbacks: after(), every(), cancel()
info(), warn(), error(), debug() → plugins.log
Read per-plugin values from [plugins.name] in config.toml via p:config(key)