HASH dce0046ad9df
DATE 2026-06-07
SUBJECT sunshine/moonlite: module init
FILES 7 CHANGED
HASH dce0046ad9df
DATE 2026-06-07
SUBJECT sunshine/moonlite: module init
FILES 7 CHANGED
┌─ hosts/ooksdesk/default.nix ───────────────────────────────────────────────┐
│ diff --git a/hosts/ooksdesk/default.nix b/hosts/ooksdesk/default.nix │
│ index 843c16d..b8d3647 100644 │
│ --- a/hosts/ooksdesk/default.nix │
│ +++ b/hosts/ooksdesk/default.nix │
│ @@ -25,6 +25,7 @@ │
│ workstation = { │
│ environment = "hyprland"; │
│ theme = "minimal"; │
│ + sunshine.enable = true; │
│ profiles = ["creative" "virtualization" "gaming" "media" "communication" "p │
│ roductivity" "infra" "work"]; │
│ default = { │
│ browser = "zen"; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ hosts/ooksdesk/default.nix ─────────┐
│ diff --git a/hosts/ooksdesk/default.nix b/ho │
│ sts/ooksdesk/default.nix │
│ index 843c16d..b8d3647 100644 │
│ --- a/hosts/ooksdesk/default.nix │
│ +++ b/hosts/ooksdesk/default.nix │
│ @@ -25,6 +25,7 @@ │
│ workstation = { │
│ environment = "hyprland"; │
│ theme = "minimal"; │
│ + sunshine.enable = true; │
│ profiles = ["creative" "virtualizatio │
│ n" "gaming" "media" "communication" "product │
│ ivity" "infra" "work"]; │
│ default = { │
│ browser = "zen"; │
└──────────────────────────────────────────────┘
┌─ modules/darwin/packages.nix ──────────────────────────────────────────────┐
│ diff --git a/modules/darwin/packages.nix b/modules/darwin/packages.nix │
│ index a08ade7..bf50b0a 100644 │
│ --- a/modules/darwin/packages.nix │
│ +++ b/modules/darwin/packages.nix │
│ @@ -28,6 +28,7 @@ in { │
│ "obsidian" │
│ "microsoft-teams" │
│ "slack" │
│ + "moonlight" │
│ ] │
│ ++ optionals (default.terminal == "ghostty" || programs.ghostty.enable) ["g │
│ hostty"] │
│ ++ optionals (default.browser == "firefox" || programs.firefox.enable) ["fi │
│ refox"] │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ modules/darwin/packages.nix ────────┐
│ diff --git a/modules/darwin/packages.nix b/m │
│ odules/darwin/packages.nix │
│ index a08ade7..bf50b0a 100644 │
│ --- a/modules/darwin/packages.nix │
│ +++ b/modules/darwin/packages.nix │
│ @@ -28,6 +28,7 @@ in { │
│ "obsidian" │
│ "microsoft-teams" │
│ "slack" │
│ + "moonlight" │
│ ] │
│ ++ optionals (default.terminal == "gh │
│ ostty" || programs.ghostty.enable) ["ghostty │
│ "] │
│ ++ optionals (default.browser == "fir │
│ efox" || programs.firefox.enable) ["firefox" │
│ ] │
└──────────────────────────────────────────────┘
┌─ modules/home/nixos/hyprland/components/hypridle.nix ──────────────────────┐
│ diff --git a/modules/home/nixos/hyprland/components/hypridle.nix b/modules/home/ni │
│ xos/hyprland/components/hypridle.nix │
│ index 7dbac3a..049ae6b 100644 │
│ --- a/modules/home/nixos/hyprland/components/hypridle.nix │
│ +++ b/modules/home/nixos/hyprland/components/hypridle.nix │
│ @@ -5,8 +5,8 @@ │
│ config, │
│ ... │
│ }: let │
│ - inherit (lib) getExe getExe' mkIf; │
│ - inherit (osConfig.ooknet.workstation) environment; │
│ + inherit (lib) getExe getExe' mkIf optionals; │
│ + inherit (osConfig.ooknet.workstation) environment sunshine; │
│ │
│ dpms = "${getExe' osConfig.programs.hyprland.package "hyprctl"} dispatch dpms"; │
│ lock = "${getExe' pkgs.systemd "loginctl"} lock-session"; │
│ @@ -20,17 +20,22 @@ in { │
│ lock_cmd = hyprlock; │
│ before_sleep_cmd = lock; │
│ }; │
│ - listener = [ │
│ - { │
│ - timeout = 300; │
│ - on-timeout = hyprlock; │
│ - } │
│ - { │
│ - timeout = 360; │
│ - on-timeout = "${dpms} off"; │
│ - on-resume = "${dpms} on"; │
│ - } │
│ - ]; │
│ + listener = │
│ + [ │
│ + { │
│ + timeout = 300; │
│ + on-timeout = hyprlock; │
│ + } │
│ + ] │
│ + # keep the display powered on while sunshine streaming is enabled │
│ + # wayland kms capture 503s on a dpms-off display and cant be woken remo │
│ tely │
│ + ++ optionals (!sunshine.enable) [ │
│ + { │
│ + timeout = 360; │
│ + on-timeout = "${dpms} off"; │
│ + on-resume = "${dpms} on"; │
│ + } │
│ + ]; │
│ }; │
│ }; │
│ }; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...rland/components/hypridle.nix ───┐
│ diff --git a/modules/home/nixos/hyprland/com │
│ ponents/hypridle.nix b/modules/home/nixos/hy │
│ prland/components/hypridle.nix │
│ index 7dbac3a..049ae6b 100644 │
│ --- a/modules/home/nixos/hyprland/components │
│ /hypridle.nix │
│ +++ b/modules/home/nixos/hyprland/components │
│ /hypridle.nix │
│ @@ -5,8 +5,8 @@ │
│ config, │
│ ... │
│ }: let │
│ - inherit (lib) getExe getExe' mkIf; │
│ - inherit (osConfig.ooknet.workstation) env │
│ ironment; │
│ + inherit (lib) getExe getExe' mkIf optiona │
│ ls; │
│ + inherit (osConfig.ooknet.workstation) env │
│ ironment sunshine; │
│ │
│ dpms = "${getExe' osConfig.programs.hyprl │
│ and.package "hyprctl"} dispatch dpms"; │
│ lock = "${getExe' pkgs.systemd "loginctl" │
│ } lock-session"; │
│ @@ -20,17 +20,22 @@ in { │
│ lock_cmd = hyprlock; │
│ before_sleep_cmd = lock; │
│ }; │
│ - listener = [ │
│ - { │
│ - timeout = 300; │
│ - on-timeout = hyprlock; │
│ - } │
│ - { │
│ - timeout = 360; │
│ - on-timeout = "${dpms} off"; │
│ - on-resume = "${dpms} on"; │
│ - } │
│ - ]; │
│ + listener = │
│ + [ │
│ + { │
│ + timeout = 300; │
│ + on-timeout = hyprlock; │
│ + } │
│ + ] │
│ + # keep the display powered on whi │
│ le sunshine streaming is enabled │
│ + # wayland kms capture 503s on a d │
│ pms-off display and cant be woken remotely │
│ + ++ optionals (!sunshine.enable) [ │
│ + { │
│ + timeout = 360; │
│ + on-timeout = "${dpms} off"; │
│ + on-resume = "${dpms} on"; │
│ + } │
│ + ]; │
│ }; │
│ }; │
│ }; │
└──────────────────────────────────────────────┘
┌─ modules/nixos/workstation/services/default.nix ───────────────────────────┐
│ diff --git a/modules/nixos/workstation/services/default.nix b/modules/nixos/workst │
│ ation/services/default.nix │
│ index a50d475..8a36d04 100644 │
│ --- a/modules/nixos/workstation/services/default.nix │
│ +++ b/modules/nixos/workstation/services/default.nix │
│ @@ -4,5 +4,6 @@ │
│ ./gnome-services.nix │
│ ./geoclue.nix │
│ ./ollama.nix │
│ + ./sunshine.nix │
│ ]; │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...kstation/services/default.nix ───┐
│ diff --git a/modules/nixos/workstation/servi │
│ ces/default.nix b/modules/nixos/workstation/ │
│ services/default.nix │
│ index a50d475..8a36d04 100644 │
│ --- a/modules/nixos/workstation/services/def │
│ ault.nix │
│ +++ b/modules/nixos/workstation/services/def │
│ ault.nix │
│ @@ -4,5 +4,6 @@ │
│ ./gnome-services.nix │
│ ./geoclue.nix │
│ ./ollama.nix │
│ + ./sunshine.nix │
│ ]; │
│ } │
└──────────────────────────────────────────────┘
┌─ modules/nixos/workstation/services/sunshine.nix ──────────────────────────┐
│ diff --git a/modules/nixos/workstation/services/sunshine.nix b/modules/nixos/works │
│ tation/services/sunshine.nix │
│ new file mode 100644 │
│ index 0000000..3242f57 │
│ --- /dev/null │
│ +++ b/modules/nixos/workstation/services/sunshine.nix │
│ @@ -0,0 +1,44 @@ │
│ +{ │
│ + lib, │
│ + config, │
│ + pkgs, │
│ + ... │
│ +}: let │
│ + inherit (lib) mkIf getExe'; │
│ + inherit (config.ooknet.workstation) sunshine; │
│ + │
│ + hyprctl = getExe' config.programs.hyprland.package "hyprctl"; │
│ + systemctl = getExe' pkgs.systemd "systemctl"; │
│ + │
│ + # sunshine runs prep cmds without a shell, so wrap them in a script │
│ + # never fail the stream over a convenience cmd, hence the `|| true` │
│ + prepDo = pkgs.writeShellScript "sunshine-prep-do" '' │
│ + ${hyprctl} dispatch dpms on || true │
│ + ${systemctl} --user stop hypridle.service || true │
│ + ''; │
│ + prepUndo = pkgs.writeShellScript "sunshine-prep-undo" '' │
│ + ${systemctl} --user start hypridle.service || true │
│ + ''; │
│ +in { │
│ + config = mkIf sunshine.enable { │
│ + services.sunshine = { │
│ + enable = true; │
│ + autoStart = true; │
│ + # CAP_SYS_ADMIN for KMS/DRM capture on wayland │
│ + capSysAdmin = true; │
│ + # reachable over the trusted tailscale0 interface, pair locally via https:/ │
│ /localhost:47990 │
│ + openFirewall = false; │
│ + # wake the display and pause hypridle for the duration of a stream │
│ + # sunshine wants this as a json string, not a nix list │
│ + settings.global_prep_cmd = builtins.toJSON [ │
│ + { │
│ + do = "${prepDo}"; │
│ + undo = "${prepUndo}"; │
│ + } │
│ + ]; │
│ + }; │
│ + │
│ + # vainfo, to verify vaapi encode is picked up │
│ + environment.systemPackages = [pkgs.libva-utils]; │
│ + }; │
│ +} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...station/services/sunshine.nix ───┐
│ diff --git a/modules/nixos/workstation/servi │
│ ces/sunshine.nix b/modules/nixos/workstation │
│ /services/sunshine.nix │
│ new file mode 100644 │
│ index 0000000..3242f57 │
│ --- /dev/null │
│ +++ b/modules/nixos/workstation/services/sun │
│ shine.nix │
│ @@ -0,0 +1,44 @@ │
│ +{ │
│ + lib, │
│ + config, │
│ + pkgs, │
│ + ... │
│ +}: let │
│ + inherit (lib) mkIf getExe'; │
│ + inherit (config.ooknet.workstation) sunsh │
│ ine; │
│ + │
│ + hyprctl = getExe' config.programs.hyprlan │
│ d.package "hyprctl"; │
│ + systemctl = getExe' pkgs.systemd "systemc │
│ tl"; │
│ + │
│ + # sunshine runs prep cmds without a shell │
│ , so wrap them in a script │
│ + # never fail the stream over a convenienc │
│ e cmd, hence the `|| true` │
│ + prepDo = pkgs.writeShellScript "sunshine- │
│ prep-do" '' │
│ + ${hyprctl} dispatch dpms on || true │
│ + ${systemctl} --user stop hypridle.servi │
│ ce || true │
│ + ''; │
│ + prepUndo = pkgs.writeShellScript "sunshin │
│ e-prep-undo" '' │
│ + ${systemctl} --user start hypridle.serv │
│ ice || true │
│ + ''; │
│ +in { │
│ + config = mkIf sunshine.enable { │
│ + services.sunshine = { │
│ + enable = true; │
│ + autoStart = true; │
│ + # CAP_SYS_ADMIN for KMS/DRM capture o │
│ n wayland │
│ + capSysAdmin = true; │
│ + # reachable over the trusted tailscal │
│ e0 interface, pair locally via https://local │
│ host:47990 │
│ + openFirewall = false; │
│ + # wake the display and pause hypridle │
│ for the duration of a stream │
│ + # sunshine wants this as a json strin │
│ g, not a nix list │
│ + settings.global_prep_cmd = builtins.t │
│ oJSON [ │
│ + { │
│ + do = "${prepDo}"; │
│ + undo = "${prepUndo}"; │
│ + } │
│ + ]; │
│ + }; │
│ + │
│ + # vainfo, to verify vaapi encode is pic │
│ ked up │
│ + environment.systemPackages = [pkgs.libv │
│ a-utils]; │
│ + }; │
│ +} │
└──────────────────────────────────────────────┘
┌─ modules/options/workstation/default.nix ──────────────────────────────────┐
│ diff --git a/modules/options/workstation/default.nix b/modules/options/workstation │
│ /default.nix │
│ index 4dcb4d7..2f4e5ca 100644 │
│ --- a/modules/options/workstation/default.nix │
│ +++ b/modules/options/workstation/default.nix │
│ @@ -21,6 +21,7 @@ in { │
│ silentBoot = { │
│ enable = mkEnableOption "Enable silent boot with plymouth"; │
│ }; │
│ + sunshine.enable = mkEnableOption "Sunshine game/desktop streaming host"; │
│ environment = mkOption { │
│ type = nullOr (enum ["hyprland" "gnome" "aerospace"]); │
│ default = "hyprland"; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...tions/workstation/default.nix ───┐
│ diff --git a/modules/options/workstation/def │
│ ault.nix b/modules/options/workstation/defau │
│ lt.nix │
│ index 4dcb4d7..2f4e5ca 100644 │
│ --- a/modules/options/workstation/default.ni │
│ x │
│ +++ b/modules/options/workstation/default.ni │
│ x │
│ @@ -21,6 +21,7 @@ in { │
│ silentBoot = { │
│ enable = mkEnableOption "Enable silen │
│ t boot with plymouth"; │
│ }; │
│ + sunshine.enable = mkEnableOption "Sunsh │
│ ine game/desktop streaming host"; │
│ environment = mkOption { │
│ type = nullOr (enum ["hyprland" "gnom │
│ e" "aerospace"]); │
│ default = "hyprland"; │
└──────────────────────────────────────────────┘
┌─ outputs/ook/lib/services.nix ─────────────────────────────────────────────┐
│ diff --git a/outputs/ook/lib/services.nix b/outputs/ook/lib/services.nix │
│ index a0dedf6..63ba9d2 100644 │
│ --- a/outputs/ook/lib/services.nix │
│ +++ b/outputs/ook/lib/services.nix │
│ @@ -11,7 +11,10 @@ │
│ mkTrayService = exec: { │
│ Unit = { │
│ Requires = ["tray.target"]; │
│ - After = ["graphical-session-pre.target" "tray.target"]; │
│ + # graphical-session.target needs an explicit After, without it systemd inje │
│ cts an │
│ + # implicit Before=graphical-session.target which loops back through │
│ + # tray.target -> waybar -> graphical-session.target and breaks session star │
│ tup │
│ + After = ["graphical-session.target" "graphical-session-pre.target" "tray.ta │
│ rget"]; │
│ PartOf = ["graphical-session.target"]; │
│ }; │
│ Service = { │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ outputs/ook/lib/services.nix ───────┐
│ diff --git a/outputs/ook/lib/services.nix b/ │
│ outputs/ook/lib/services.nix │
│ index a0dedf6..63ba9d2 100644 │
│ --- a/outputs/ook/lib/services.nix │
│ +++ b/outputs/ook/lib/services.nix │
│ @@ -11,7 +11,10 @@ │
│ mkTrayService = exec: { │
│ Unit = { │
│ Requires = ["tray.target"]; │
│ - After = ["graphical-session-pre.targe │
│ t" "tray.target"]; │
│ + # graphical-session.target needs an e │
│ xplicit After, without it systemd injects an │
│ + # implicit Before=graphical-session.t │
│ arget which loops back through │
│ + # tray.target -> waybar -> graphical- │
│ session.target and breaks session startup │
│ + After = ["graphical-session.target" " │
│ graphical-session-pre.target" "tray.target"] │
│ ; │
│ PartOf = ["graphical-session.target"] │
│ ; │
│ }; │
│ Service = { │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET