# home-manager/fred.nix { config, pkgs, lib, inputs, osConfig, ... }: let isDesktop = lib.elem osConfig.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]; in { home.stateVersion = "25.11"; home.packages = with pkgs; [ # ]; home.file.".config/nixpkgs/config.nix".text = '' { allowUnfree = true; } ''; # Wallpaper source — consumed by stylix's image option (set in # settings/stylix.nix) and by quickshell's wallpaper layer. home.file.".local/share/backgrounds/wallpaper.png".source = "${inputs.self}/walls/wallpaper.png"; # btop — stylix's btop target writes the colour theme; we keep our # non-colour preferences here. programs.btop = { enable = true; settings = { theme_background = false; vim_keys = false; proc_filter_kernel = true; }; }; # Ghostty — stylix's ghostty target writes the colour theme. programs.ghostty = lib.mkIf isDesktop { enable = true; settings = { font-family = "CaskaydiaCove NF"; font-size = 11; font-thicken = true; window-padding-x = 10; window-padding-y = 10; window-padding-balance = true; background-opacity = 0.98; confirm-close-surface = false; gtk-titlebar = false; gtk-single-instance = true; # keeps the warm instance alive with zero windows quit-after-last-window-closed = false; cursor-style = "bar"; cursor-style-blink = true; }; }; # spotify-player — native librespot TUI replacing the Electron Spotify app. # stylix's spotify-player target writes the colour theme. # MPRIS (quickshell's media card), notifications and streaming are all on by # default on Linux, so only the off-by-default visualiser needs setting. programs.spotify-player = lib.mkIf isDesktop { enable = true; # 26.05 ships 0.23.0, whose Web API token is cached with refresh_token = # null: once it expires (~1h) nothing can renew it and the library just # spins until the app is restarted. 0.24.1 treats a non-renewable cached # token as unusable and re-runs the PKCE flow instead. Drop this override # once the pinned channel reaches 0.24.1. package = pkgs.spotify-player.overrideAttrs (old: rec { version = "0.24.1"; src = pkgs.fetchFromGitHub { owner = "aome510"; repo = "spotify-player"; tag = "v${version}"; hash = "sha256-+GADmRl4XMwV8TfYZjEeyKDDfda3bDPzeerhYryX6vA="; }; cargoDeps = pkgs.rustPlatform.fetchCargoVendor { inherit src; hash = "sha256-CSZ5sZ+d7Jhi43ipaWXKupYPFgWCbCx4RMTQN8emu9o="; }; # Always claim playback on our own device at launch, instead of having to # pick it from the device popup every time. Two upstream guards in # client/mod.rs stop that from happening: # 1. initialize_playback skips connecting entirely if any playback # already exists — a phone or web player holding a paused playback # is enough. # 2. find_available_device returns the currently *active* device before # it ever gets to the "prefer the integrated device" branch. # Disabling both leaves the integrated device as the startup target. # The CLI can't do this from the outside: `connect --name` resolves names # against the Web API device list, which usually doesn't contain our # freshly registered librespot device at all. postPatch = (old.postPatch or "") + '' substituteInPlace spotify_player/src/client/mod.rs \ --replace-fail "if state.player.read().playback.is_some() {" \ "if false {" \ --replace-fail "if let Some(d) = devices.iter().find(|d| d.is_active) {" \ "if let Some(d) = devices.iter().find(|d| false && d.is_active) {" ''; }); settings = { enable_audio_visualization = true; # Our own Spotify app rather than the built-in default (ncspot's client # ID, shared by every spotify-player/ncspot install). Spotify rate-limits # per client ID, and exhausting the shared one surfaced here as # "Token is not valid" and an endlessly loading library. Public PKCE # client, no secret involved, so it's fine in the repo. # Redirect URI registered: http://127.0.0.1:8989/login client_id = "265506bc7bbd4032bf0fee708b321d3e"; }; }; # Upstream ships no .desktop file (TUI only), so the launcher can't find it. xdg.desktopEntries.spotify-player = lib.mkIf isDesktop { name = "Spotify Player"; genericName = "Music Player"; exec = "ghostty --title=spotify-player -e spotify_player"; icon = "spotify"; terminal = false; categories = [ "Audio" "Music" "Player" "AudioVideo" ]; }; # Warm Ghostty instance — new windows attach via gtk-single-instance. systemd.user.services.ghostty-daemon = lib.mkIf isDesktop { Unit = { Description = "Ghostty warm instance (no window)"; After = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; }; Service = { Type = "simple"; ExecStart = "${pkgs.ghostty}/bin/ghostty --initial-window=false"; Restart = "always"; }; Install.WantedBy = [ "graphical-session.target" ]; }; }