Shows whatever media is playing right now — album art, the timeline, and the lyrics in time with the song — inside your terminal.
Written in C. It talks to any media player over MPRIS (D-Bus), fetches the cover art, and draws it with the kitty graphics protocol, so the artwork is real pixels, not coloured text.
┌──────────────┐ ▶ playing · mpv
│ │
│ album art │ ━━━━━━━━━━━━━━━●────────────────────────
│ │ 1:23 3:52
│ │
│ │ the line that was just sung
└──────────────┘ the line being sung right now ← accent
the next line
How to Fight Lonel… and the one after that
Wilco …
Summerteeth
The cover sits top-left, the track/artist/album go underneath it, and the timeline sits to its right. When the song has lyrics they scroll along under the timeline, with the line being sung highlighted. The accent colour — the artist line, the status line, the filled part of the bar, the current lyric — is pulled out of the cover art itself, so the whole thing recolours with every track.
Needs a C compiler and these libraries (all with pkg-config files):
| library | why |
|---|---|
dbus-1 |
talking to the player over MPRIS |
libcurl |
downloading cover art and lyrics over http(s) |
libpng, libjpeg |
decoding cover art |
libwebp |
optional — WebP covers, detected at build time |
On Arch: sudo pacman -S dbus curl libpng libjpeg-turbo libwebp
On Debian/Ubuntu: sudo apt install libdbus-1-dev libcurl4-openssl-dev libpng-dev libjpeg-dev libwebp-dev
make
./nowplayingsudo make install drops it in /usr/local/bin (make install PREFIX=~/.local
if you would rather it went somewhere else).
nowplaying [options]
-p, --player NAME prefer this MPRIS player (mpv, vlc, firefox, ...)
-s, --size COLS width of the cover art, in terminal columns
-1, --once print the current track once and exit
-b, --blocks draw the cover with unicode half blocks
-k, --kitty force the kitty graphics protocol
-L, --no-lyrics do not look for lyrics
-h, --help help
-v, --version version
Keys, while it is running:
| key | |
|---|---|
q, Esc, Ctrl-C |
quit |
space, p |
play / pause |
n |
next track |
b |
previous track |
← → |
seek 5 seconds |
l |
show / hide lyrics |
+ - |
lyrics a quarter second earlier / later |
r |
redraw |
--once prints one frame inline and exits, which is handy from a script or a
shell prompt. Everything else runs full-screen and updates live.
Any MPRIS2 player will do — music players, mpv, VLC, or a tab playing media in
Firefox or Chromium. When several are running it prefers the one you named
with --player, then whichever is actually playing, and it sticks with its
choice rather than flip-flopping. If nothing is running it waits and picks the
player up as soon as one appears.
For each new track it looks, in order, for:
- lyrics the player itself publishes (
xesam:asTextin the MPRIS metadata), - a
.lrcfile next to a local track —song.flac→song.lrc, - LRCLIB, a free, open lyrics database — this sends the title, artist, album and length of the track to lrclib.net.
Timed (LRC) lyrics follow the song line by line: the sung line is highlighted
in the accent colour, and the display updates the moment the next line starts,
including after a seek. Untimed lyrics scroll slowly along with the song
instead. If the words run early or late for your player, nudge them with +
and -. Tracks without lyrics keep the plain layout, and --no-lyrics turns
the whole thing off (and with it every request to lrclib.net).
Cover art needs kitty graphics: kitty, Ghostty and WezTerm all work, and
are detected automatically. Anywhere else it falls back to unicode half blocks
with 24-bit colour, which looks surprisingly decent. Force either one with
--blocks / --kitty, or set NOWPLAYING_RENDER=blocks|kitty.
The cover is scaled to the exact pixel size of the cell box it occupies, so it stays sharp and square whatever your font size is, and it is re-scaled from the already-decoded original whenever you resize the window — no re-download.
| file | |
|---|---|
src/mpris.c |
MPRIS2 over D-Bus: find a player, read its metadata, send it commands |
src/art.c |
fetch (file://, http(s)://), decode (PNG/JPEG/WebP), resample, pick the accent colour |
src/lyrics.c |
find lyrics (player, .lrc, LRCLIB), parse LRC, time the lines |
src/kitty.c |
kitty graphics protocol, and the half-block fallback |
src/ui.c |
layout and drawing |
src/main.c |
the loop, the keys, and worker threads that load art and lyrics without stalling the display |
Art and lyrics load on their own threads, so a slow download never freezes the timeline. The position is read from the player twice a second and interpolated from the monotonic clock in between, which is what makes the bar move smoothly instead of in half-second steps.



