a small rust navidrome client for tiling window managers
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Christian Thackston b9d850ab63
Add album queue, shuffle mode, library cache and gapless album transitions
Browser:
- Mark albums lf-style (space, u to clear). Enter plays the marked
  albums in order;  adds them, or the selected album, to the queue.
-  toggles shuffle mode: when an album ends, the next one is random,
  picked from the queue or, if it is empty, the whole library.
- Play/pause moves to  and stop to ;  refreshes a column.
- Cache the whole library (albums, artists, every album's tracks) in
  ~/.cache/smldrome/library.json and refresh it in the background, so
  browsing never waits on the server. Tracks come from paged search3
  requests (500 songs each) instead of one request per album.
- Reap spawned players so finished ones don't linger as zombies.

Player:
- Keep an album queue and shuffle state; ,  and
   control commands, plus  flags.
- Make album changes gapless: 30s before an album ends, fetch the next
  one and append it to the engine queue so its first track is decoded
  ahead. Queue or shuffle changes before then still pick what follows.
- Next on an album's last track moves on to the next album.
- Show the queued-album count and a shuffle toggle beside the controls.
- Snap icon geometry to whole pixels (the pause bars rendered unevenly
  at fractional positions) and restyle the shuffle icon to match.
2026-10-12 21:46:11 -07:00
src Add album queue, shuffle mode, library cache and gapless album transitions 2026-10-12 21:46:11 -07:00
.gitignore Initial commit (again) 2026-10-12 21:10:36 -07:00
Cargo.lock Initial commit (again) 2026-10-12 21:10:36 -07:00
Cargo.toml Initial commit (again) 2026-10-12 21:10:36 -07:00
config.example.toml Initial commit (again) 2026-10-12 21:10:36 -07:00
README.md Add album queue, shuffle mode, library cache and gapless album transitions 2026-10-12 21:46:11 -07:00

smldrome

A small album player for Navidrome (or any Subsonic API server). You browse in the terminal with lf-style columns. Picking an album opens a small window with the cover art and basic controls. The window exists only during playback and closes when the album ends.

It works in whole albums: you pick albums, queue them, or let shuffle pick the next one. There are no playlists or favorites.

Install

cargo install --path .
mkdir -p ~/.config/smldrome && cp config.example.toml ~/.config/smldrome/config.toml
smldrome login      # asks for the password once

login checks the password against the server, then saves only the Subsonic auth token (md5 of password + salt) and the salt to ~/.local/share/smldrome/credentials (mode 0600). The token can't be turned back into your password, but it does log in to the API, so treat the file like a password. smldrome logout deletes it. Setting password_command or password in the config overrides the stored login.

Use

smldrome                       browse
smldrome play <album-id> [n]   open the player directly
smldrome ctl toggle|pause|resume|next|prev|stop|status
smldrome ctl seek +10|-10|90      # relative or absolute seconds
smldrome ctl volume 40           # percent
smldrome ctl queue ID.. | playall ID.. | shuffle [on|off]
smldrome login | logout

Browser keys

key action
j k / arrows move
l / → open (artist → albums → tracks)
h / ← back
Enter play the marked albums in order; with none marked, the album or from the selected track
gg G ^d ^u ^f ^b jump
/ filter the current column (Enter keeps it, Esc clears it)
space mark/unmark the album and move down (like lf); u clears all marks
a add the marked albums (or the selected one) to the player's queue
s shuffle mode: when an album ends, the next one is random, picked from the queue or, if the queue is empty, the whole library
p [ ] x play/pause, previous, next, stop
r refresh the current column from the server
q quit (playback continues)

Player keys

space play/pause · h/l seek ±10s · j/k (or n/p) next/prev · +/- volume · s shuffle · q close. The number left of the controls is how many albums are queued, and the icon on the right toggles shuffle. Next on an album's last track moves to the next album. You can also click the cover to pause, scroll anywhere in the window to change the volume by volume_step percent (volume_step_fine, 1% by default, while holding shift), and click or drag the progress bar to seek.

When a player is already open, picking another album replaces what it plays. The window stays where you put it.

Sway

The window's app_id is smldrome. This makes it 1/8 of the screen in the bottom-right corner:

for_window [app_id="smldrome"] floating enable, sticky enable, resize set 25 ppt 50 ppt, move position 75 ppt 50 ppt
bindsym $mod+m exec foot -e smldrome
bindsym XF86AudioPlay exec playerctl play-pause
bindsym XF86AudioNext exec playerctl next
bindsym XF86AudioPrev exec playerctl previous

The player also registers on MPRIS as smldrome, so playerctl, waybar's mpris module and other media widgets can see and control it: play/pause, next/previous, seek, set position, volume and stop. They also get the title, artist, album, length and cover art (from the local cache). Position updates once a second. smldrome ctl does the same things without D-Bus.

The window switches to a side-by-side layout when it is wider than it is tall, and to a stacked layout under the cover when it is much taller than wide. In both, text and controls grow (up to max_text_scale) to fill the spare room. Lines are dropped, track number first, when there is too little room. The info includes the audio quality, e.g. FLAC · 24-bit/96 kHz · 2304 kbps.

Playback keeps running on its own thread, so smldrome ctl and track changes work while the window is on a hidden workspace.

smldrome ctl status prints state<TAB>title<TAB>artist<TAB>album<TAB>pos<TAB>duration<TAB>shuffle|-<TAB>queued, which you can use in a waybar custom module.

Notes

  • Playback is gapless everywhere: between tracks, and from one album into the next (queued or shuffled). The next track is always downloaded and decoded before the current one ends. In the last 30 seconds of an album, the next album is picked and lined up behind it. Until then, queue and shuffle changes still decide what comes next.
  • Tracks play while they download (after the first 256 KB), and skipping to the already lined-up next track is instant. You can seek only within the part already downloaded, which the progress bar shows. When the server transcodes, it doesn't send the file length, so seeking waits until the download finishes.
  • The whole library (albums, artists and every album's tracks) is cached in ~/.cache/smldrome/library.json, so browsing is instant. Each start, the browser refreshes it in the background. Track lists come from a bulk song listing, about 500 songs per request, rather than one request per album. The dynamic lists (recently added/played, most played, random) show their last contents right away and update once per session. r refreshes a column.
  • Covers are cached in ~/.cache/smldrome/covers. While the browser is open, it downloads every album's cover in the background (prefetch_covers) and shows its progress in the status line. Covers are resampled to the exact size they're drawn at, so they stay sharp in a small window.
  • Audio goes only through PipeWire, as a normal client stream named smldrome. There is no PulseAudio or ALSA fallback: going through ALSA directly takes the sound card away from PipeWire and breaks audio for other apps. If PipeWire isn't running, the player says so and exits.
  • Supported formats are mp3, flac, alac, aac/m4a, ogg vorbis and wav. Opus is not supported, so set transcode = "mp3" if your library uses it.