dotfiles
Apps

Spotifast: Spotify without a browser engine

Edit on GitHub

Package pkgs/spotifast/. Upstream: https://github.com/crmne/spotifast.

Why it is here

The official client is CEF, a whole Chromium. Spotifast is native (Rust + egui), plays through librespot and reads the library through the Web API. Upstream claims ~100 to 250 MB of RAM and well under a second to open. Playback needs Premium; a Free account only browses.

Why the release binary and not the flake

The same reasons, the same layout and the same bump as its sibling ZapFast: the upstream flake has no binary cache, so every bump would compile Rust (plus libprojectM for MilkDrop), while the x86_64-unknown-linux-gnu tarball links only libpipewire, libasound, libstdc++ and glibc 2.39. It is built WHOLE from unstable for the same glibc reason. Its wrapper adds dbus to the dlopened list, which upstream's flake wraps too and ZapFast does not need.

spotifast-portable.txt is left out of the tarball, because it turns on the in-app updater, which would try to rewrite the store. The contrib/omarchy hook is for another distro's theming.

The theme: colors only, and a real file

modules/home/apps/spotifast.nix generates ~/.config/spotifast/themes/dotfiles.json from my.theme.palette, mapped like the spicetify "text" scheme it replaced: the background, the surfaces and the green accent. It follows a my.theme.name switch on the next rebuild.

  • Colors only. Upstream's format sets colors and keeps the app's fonts, so the mono, TUI-like look of spicetify's "text" theme did not come along. Accepted on 24/10/2026 for the RAM.
  • A copy, not a link. The app skips symlinks in its themes folder, so home.file cannot own it; an activation installs the file instead, and the app notices the change on its own.
  • Picked once, by hand. The choice lives in the app's own settings.json, which it rewrites, so it is not declared: Settings > Appearance > Theme > dotfiles. The fixed file name keeps that pick valid across palette switches. Turn off "Colour from album art" for fixed colors on every page.

Playback goes through Soloist

Spotify refuses librespot the audio key for many accounts, new AND old (the log says error audio key 0 1, then Spotify refused the audio key). Sign-in, the library and search all work; only the sound is refused, and nothing on this machine changes that. It is upstream's open spotifast#283, on top of librespot#1649. It hit this account on 24/10/2026, on the first play.

The way around it keeps spotifast as the app: Soloist, Spotify's OFFICIAL headless Connect receiver, runs as a --user service (modules/home/apps/spotifast.nix) and shows up in spotifast's device list under the hostname. Spotifast picks it once and remembers the choice; Soloist gets its keys through Spotify's own engine, so it plays. No Electron, no CEF.

  • Package. pkgs/soloist/, the release binary, unfree. It links only glibc and libatomic and dlopens libpulse, which PipeWire answers.
  • It EXPIRES. A build stops 90 days after it is made, exiting 10. The unit does not restart on 10; update (its bump reads the URL's Last-Modified) plus a rebuild does.
  • Nobody has to remember that. The soloist-expiry timer runs daily at 10:00 (catching up after a powered-off morning) and, from 14 days out, warns on the desktop and on the phone (ntfy). The deadline is the version (the build date) plus 90 days; on 24/10/2026 it said 88, the same as Soloist's own client expires in 88 days. It warns instead of updating on its own because an unattended bump would commit and switch the system with nobody looking.
  • The API key. Generated once in the Spotify for Developers dashboard (Soloist API Key page, Premium only), stored in Bitwarden as Spotify Soloist API Key, then sync-secrets and a rebuild. It reaches the unit as SOLOIST_API_KEY through the soloist.env template, and systemd expands it into --api-key: the binary ignores the variable, despite what upstream's guide suggests (Error: --api-key is required, 24/10/2026). The unit does not exist until the vault holds the key.
  • Pairing is ONE time, from the phone. Spotifast's own ZeroConf login reaches Soloist (zeroconf: received addUser) and is ignored without a word, so the first login comes from the official app on the phone instead. Its ZeroConf port is random per start and closed to the LAN, so it is opened only for that minute (iptables -I nixos-fw -p tcp --dport <port> -j nixos-fw-accept, then -D). The login lands in the StateDirectory and survives restarts (measured 24/10/2026: logged in as ... again with no phone), so after that Soloist is a normal device of the account and no inbound port is needed.
  • Checking it. journalctl --user -u soloist says logged in as <user>; then the hostname in spotifast's devices.

Around it

  • Media controls. It registers MPRIS as spotifast, so playerctl --player=spotifast; the bar pill and the media panel match that name (modules/home/desktop/quickshell/).
  • Autostart. The spotifast entry in my.autostart opens it with --start-hidden. Its own "start with computer" stays Off, or it becomes a second owner (autostart.md).
  • Sign-in. The grants go to the Secret Service (gnome-keyring), so a locked keyring means signing in again each session.

What it replaced

The CEF client themed by spicetify (spicetify-nix), plus three overlays that existed only to make CEF open: --no-zygote, the Wayland flag and a cleaner for a stale SingletonLock. All gone on 24/10/2026. The 4145 restarts it caused in the autostart are kept as history in autostart.md.