spotify-player: run a daemon; fix progress bar; add progress+volume to media card

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-08-16 12:49:01 +01:00
parent 2652d14a8f
commit 82de631064
2 changed files with 144 additions and 1 deletions

View file

@ -133,7 +133,57 @@ in
# of the wheel is a dozen requests and a 429. Use PipeWire for volume
# instead — same sink, instant, free.
enable_mouse_scroll_volume = false;
# The librespot device is only usable once Spotify's backend has accepted
# it, which takes ~20s from process start — that is the wait before you can
# play anything, and it is server-side, so there is nothing local to speed
# up. Instead, pay it once at login: the daemon below holds the device for
# the whole session, and DaemonOnly keeps the TUI from registering a second
# one, so opening the TUI is instant and plays straight onto the daemon's
# device.
enable_streaming = "DaemonOnly";
};
# Rectangle gauges only ever use `playback_progress_bar`: ratatui paints the
# filled part in its fg and the rest in its bg, and `_unfilled` is ignored
# (it is Line-only). The upstream default is fg Green / bg BrightBlack, and
# stylix collapses the whole 16-colour palette onto three colours — Green
# #41afb2 and BrightBlack #3fa8ab are the same teal by eye, so the bar
# rendered as one solid block with no visible progress. Repainting it
# foreground-on-background is the only pair stylix guarantees is distinct.
# mkForce because stylix owns this list and find_theme takes the *first*
# match by name, so an appended second "stylix" would be ignored; the
# palette below reproduces stylix's own mapping so nothing else changes.
themes = lib.mkForce [
{
name = "stylix";
palette = with config.lib.stylix.colors.withHashtag; {
background = base00;
foreground = base05;
black = base00;
red = base08;
green = base0B;
yellow = base0A;
blue = base0D;
magenta = base0E;
cyan = base0C;
white = base05;
bright_black = base03;
bright_red = base08;
bright_green = base0B;
bright_yellow = base0A;
bright_blue = base0D;
bright_magenta = base0E;
bright_cyan = base0C;
bright_white = base07;
};
component_style = {
playback_progress_bar = {
fg = "BrightWhite";
bg = "Black";
};
playback_progress_bar_unfilled.bg = "Black";
};
}
];
# The home-manager module only writes keymap.toml when `keymaps` is
# non-empty, so `actions` alone would silently emit nothing. Restating a
# default binding is the cheapest way to make the file exist.
@ -166,11 +216,34 @@ in
];
};
# Holds the librespot Spotify Connect device for the whole session, so the
# ~20s the Spotify backend takes to accept a new device is paid once at login
# instead of on every launch. Also means the MPRIS card in quickshell keeps
# working with no terminal open. Type=forking because the daemonize crate
# double-forks and the parent exits; it writes no pidfile, so systemd guesses.
systemd.user.services.spotify-player-daemon = lib.mkIf isDesktop {
Unit = {
Description = "spotify-player daemon (holds the Spotify Connect device)";
After = [ "graphical-session.target" "pipewire.service" ];
PartOf = [ "graphical-session.target" ];
};
Service = {
Type = "forking";
ExecStart = "${config.programs.spotify-player.package}/bin/spotify_player --daemon";
Restart = "on-failure";
RestartSec = 10;
};
Install.WantedBy = [ "graphical-session.target" ];
};
# Upstream ships no .desktop file (TUI only), so the launcher can't find it.
# enable_media_control=false: media-control is not gated on `is_daemon`, so
# without this both the daemon and the TUI export org.mpris.MediaPlayer2 and
# quickshell would show two cards for one player. The daemon owns MPRIS.
xdg.desktopEntries.spotify-player = lib.mkIf isDesktop {
name = "Spotify Player";
genericName = "Music Player";
exec = "ghostty --title=spotify-player -e spotify_player";
exec = "ghostty --title=spotify-player -e spotify_player -o enable_media_control=false";
icon = "spotify";
terminal = false;
categories = [ "Audio" "Music" "Player" "AudioVideo" ];