{ config, lib, pkgs, ... }: with lib; let cfg = config.roles.kodi; in { options.roles.kodi = { enable = mkEnableOption "Enable Kodi"; autologin = mkOption { default = false; }; wayland = mkOption { default = true; }; jellyfinScaleFactor = mkOption { type = types.nullOr types.float; default = null; description = "Scale factor for Jellyfin Media Player UI (e.g., 1.5 for 150% 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 = let kodiBasePkg = if cfg.wayland then pkgs.kodi-wayland else pkgs.kodi; kodiPkg = kodiBasePkg.withPackages (pkgs: with pkgs; [ jellyfin steam-launcher steam-library youtube ]); jellyfinMediaPlayerPkg = if cfg.jellyfinScaleFactor != null then pkgs.symlinkJoin { name = "jellyfin-media-player-scaled"; paths = [ pkgs.jellyfin-media-player ]; nativeBuildInputs = [ pkgs.makeWrapper ]; postBuild = '' mkdir -p $out/bin rm -f $out/bin/jellyfin-desktop makeWrapper ${pkgs.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.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.jellyfin-media-player; in mkIf cfg.enable { users.extraUsers.kodi = { isNormalUser = true; extraGroups = [ "wheel" "networkmanager" "audio" "video" ]; }; networking.firewall = { allowedTCPPorts = [ 8080 ] ++ optional cfg.appLauncherServer.enable cfg.appLauncherServer.port; allowedUDPPorts = [ 8080 ]; }; environment.systemPackages = with pkgs; [ jellyfinMediaPlayerPkg kodiPkg wget firefox ] ++ 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 dependency. Remove this once jellyfin is updated to use qt6" [ "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:${kodiPkg}/bin:/run/current-system/sw/bin" ]; }; }; }; services.displayManager = mkIf cfg.autologin { autoLogin.enable = true; autoLogin.user = "kodi"; defaultSession = "plasma"; }; }; }