diff --git a/flake.nix b/flake.nix index f35532e..cbf7bb3 100644 --- a/flake.nix +++ b/flake.nix @@ -172,6 +172,7 @@ ./machines/boxy/configuration.nix { home-manager.users.johno = import ./home/home-media-center.nix; + # kodi user: AVR volume control + minimal Plasma config for Bigscreen session home-manager.users.kodi = import ./home/home-kodi.nix; home-manager.extraSpecialArgs = { inherit system; }; } diff --git a/machines/boxy/configuration.nix b/machines/boxy/configuration.nix index fa7599f..11872b4 100644 --- a/machines/boxy/configuration.nix +++ b/machines/boxy/configuration.nix @@ -22,12 +22,11 @@ with lib; sddm = true; wayland = true; }; - kodi = { + plasma-bigscreen = { enable = true; autologin = true; - wayland = true; - appLauncherServer.enable = true; jellyfinScaleFactor = 1.0; + appLauncherServer.enable = true; }; nfs-mounts.enable = true; users.enable = true; @@ -72,4 +71,3 @@ with lib; system.stateVersion = "24.05"; # Did you read the comment? } - diff --git a/roles/default.nix b/roles/default.nix index 2a02e65..4bdc62b 100644 --- a/roles/default.nix +++ b/roles/default.nix @@ -12,6 +12,7 @@ with lib; ./k3s-node ./kodi ./nfs-mounts + ./plasma-bigscreen ./nvidia ./printing ./rclone-mount diff --git a/roles/plasma-bigscreen/default.nix b/roles/plasma-bigscreen/default.nix new file mode 100644 index 0000000..6263041 --- /dev/null +++ b/roles/plasma-bigscreen/default.nix @@ -0,0 +1,132 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.roles.plasma-bigscreen; + + # Plasma Bigscreen package — not yet in nixpkgs, built from upstream master + plasma-bigscreen = pkgs.kdePackages.callPackage ./package.nix {}; + + jellyfinMediaPlayerPkg = + if cfg.jellyfinScaleFactor != null + then pkgs.symlinkJoin { + name = "jellyfin-media-player-scaled"; + paths = [ pkgs.qt-pinned.jellyfin-media-player ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; + postBuild = '' + mkdir -p $out/bin + rm -f $out/bin/jellyfin-desktop + makeWrapper ${pkgs.qt-pinned.jellyfin-media-player}/bin/jellyfin-desktop $out/bin/jellyfin-desktop \ + --add-flags "--tv --scale-factor ${toString cfg.jellyfinScaleFactor}" + + # Update .desktop file to include scale factor and TV mode arguments + mkdir -p $out/share/applications + rm -f $out/share/applications/org.jellyfin.JellyfinDesktop.desktop + substitute ${pkgs.qt-pinned.jellyfin-media-player}/share/applications/org.jellyfin.JellyfinDesktop.desktop \ + $out/share/applications/org.jellyfin.JellyfinDesktop.desktop \ + --replace-fail "Exec=jellyfin-desktop" "Exec=jellyfin-desktop --tv --scale-factor ${toString cfg.jellyfinScaleFactor}" + ''; + } + else pkgs.qt-pinned.jellyfin-media-player; +in +{ + options.roles.plasma-bigscreen = { + enable = mkEnableOption "Plasma Bigscreen TV interface"; + + autologin = mkOption { + type = types.bool; + default = false; + description = "Auto-login to Plasma Bigscreen session"; + }; + + user = mkOption { + type = types.str; + default = "kodi"; + description = "User account for the Bigscreen session"; + }; + + jellyfinScaleFactor = mkOption { + type = types.nullOr types.float; + default = null; + description = "Scale factor for Jellyfin Media Player UI (e.g., 1.0 for 100% scaling)"; + }; + + appLauncherServer = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable HTTP app launcher server for remote control"; + }; + port = mkOption { + type = types.int; + default = 8081; + description = "Port for the app launcher HTTP server"; + }; + }; + }; + + config = mkIf cfg.enable { + # Create the bigscreen user + users.extraUsers.${cfg.user} = { + isNormalUser = true; + extraGroups = [ "wheel" "networkmanager" "audio" "video" ]; + }; + + # Plasma Bigscreen is a Plasma 6 shell — needs Plasma 6 desktop manager + services.desktopManager.plasma6.enable = true; + + # Register the bigscreen session with the display manager + services.displayManager.sessionPackages = [ plasma-bigscreen ]; + xdg.portal.configPackages = [ plasma-bigscreen ]; + + # Fix homescreen not being focused after quitting app or on boot + environment.plasma6.excludePackages = with pkgs; [ + kdePackages.xwaylandvideobridge + ]; + + # Firewall for remote control + networking.firewall = { + allowedTCPPorts = optional cfg.appLauncherServer.enable cfg.appLauncherServer.port; + }; + + environment.systemPackages = with pkgs; [ + plasma-bigscreen + firefox + jellyfinMediaPlayerPkg + qt-pinned.stremio + wget + ] ++ optional cfg.appLauncherServer.enable pkgs.custom.app-launcher-server; + + nixpkgs.config.permittedInsecurePackages = lib.warn + "Allowing insecure package qtwebengine-5.15.19 as a jellyfin-media-player/stremio dependency." + [ + "qtwebengine-5.15.19" + ]; + + programs.kdeconnect.enable = true; + + systemd.user.services = mkIf cfg.appLauncherServer.enable { + app-launcher-server = { + description = "HTTP App Launcher Server"; + wantedBy = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.custom.app-launcher-server}/bin/app-launcher-server ${toString cfg.appLauncherServer.port}"; + Restart = "always"; + RestartSec = "5s"; + Environment = [ + "PATH=${pkgs.firefox}/bin:/run/current-system/sw/bin" + ]; + }; + }; + }; + + services.displayManager = mkIf cfg.autologin { + autoLogin.enable = true; + autoLogin.user = cfg.user; + defaultSession = "plasma-bigscreen-wayland"; + }; + }; +} diff --git a/roles/plasma-bigscreen/package.nix b/roles/plasma-bigscreen/package.nix new file mode 100644 index 0000000..966cbbd --- /dev/null +++ b/roles/plasma-bigscreen/package.nix @@ -0,0 +1,117 @@ +# Plasma Bigscreen — TV interface for Plasma 6 +# Not yet released or packaged in nixpkgs; built from upstream master. +# Upstream: https://invent.kde.org/plasma/plasma-bigscreen +# Tracking: https://github.com/NixOS/nixpkgs/issues/428077 +# Based on: https://github.com/NixOS/nixpkgs/pull/428353 +{ + mkKdeDerivation, + lib, + fetchFromGitLab, + pkg-config, + # KDE Frameworks 6 + ki18n, + kdeclarative, + kcmutils, + knotifications, + kio, + kwayland, + kwindowsystem, + ksvg, + kiconthemes, + kglobalaccel, + kdbusaddons, + # KDE Plasma 6 + plasma-workspace, + plasma-nano, + plasma-nm, + plasma-activities, + plasma-activities-stats, + milou, + libkscreen, + kdeconnect-kde, + # Qt 6 + qtmultimedia, + qtwebengine, + # Other + bluez-qt, + qcoro, + plasma-wayland-protocols, + wayland, + sdl3, +}: + +mkKdeDerivation { + pname = "plasma-bigscreen"; + version = "unstable-2026-03-07"; + + src = fetchFromGitLab { + domain = "invent.kde.org"; + owner = "plasma"; + repo = "plasma-bigscreen"; + rev = "bd143fea7e386bac1652b8150a3ed3d5ef7cf93c"; + # Build will fail with hash mismatch — copy the correct hash from the error + hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + }; + + extraNativeBuildInputs = [ + pkg-config + ]; + + extraBuildInputs = [ + # KDE Frameworks + ki18n + kdeclarative + kcmutils + knotifications + kio + kwayland + kwindowsystem + ksvg + kiconthemes + kglobalaccel + kdbusaddons + # Plasma + plasma-workspace + plasma-nano + plasma-nm + plasma-activities + plasma-activities-stats + milou + libkscreen + kdeconnect-kde + # Qt + qtmultimedia + qtwebengine + # Other + bluez-qt + qcoro + plasma-wayland-protocols + wayland + sdl3 + ]; + + postPatch = '' + substituteInPlace bin/plasma-bigscreen-wayland.in \ + --replace @KDE_INSTALL_FULL_LIBEXECDIR@ "${plasma-workspace}/libexec" + + # Plasma version numbers must match; we're building an unreleased package + # against a stable Plasma release. + substituteInPlace CMakeLists.txt \ + --replace-fail 'set(PROJECT_VERSION "6.5.80")' 'set(PROJECT_VERSION "${plasma-workspace.version}")' + ''; + + preFixup = '' + wrapQtApp $out/bin/plasma-bigscreen-wayland + ''; + + passthru.providedSessions = [ + "plasma-bigscreen-wayland" + ]; + + meta = { + description = "Plasma shell for TVs (Plasma Bigscreen)"; + homepage = "https://plasma-bigscreen.org"; + license = lib.licenses.gpl2Plus; + platforms = lib.platforms.linux; + }; +}