{ config, pkgs, ... }: let cids = import ../staticids.nix; networkPrefix = config.networkPrefix; filebotScript = pkgs.callPackage ./filebot-process.nix {}; pyloadUser = { isSystemUser = true; uid = cids.uids.pyload; group = "pyload"; home = "/var/lib/pyload"; createHome = true; extraGroups = [ "jellyfin" ]; # Access to multimedia directories }; pyloadGroup = { gid = cids.gids.pyload; }; jellyfinUser = { isSystemUser = true; uid = cids.uids.jellyfin; group = "jellyfin"; home = "/var/lib/jellyfin"; createHome = true; extraGroups = [ "render" "video" ]; }; jellyfinGroup = { gid = cids.gids.jellyfin; }; in { users.users.pyload = pyloadUser; users.groups.pyload = pyloadGroup; users.users.jellyfin = jellyfinUser; users.groups.jellyfin = jellyfinGroup; # Create the directory structure on the host systemd.tmpfiles.rules = [ "d /var/lib/downloads 0755 pyload pyload - -" "d /var/lib/multimedia 0775 root jellyfin - -" "d /var/lib/multimedia/movies 0775 jellyfin jellyfin - -" "d /var/lib/multimedia/tv-shows 0775 jellyfin jellyfin - -" "d /var/lib/multimedia/music 0755 jellyfin jellyfin - -" "d /var/lib/jellyfin 0755 jellyfin jellyfin - -" # PyLoad hook scripts directory "d /var/lib/pyload/config 0755 pyload pyload - -" "d /var/lib/pyload/config/scripts 0755 pyload pyload - -" "d /var/lib/pyload/config/scripts/package_extracted 0755 pyload pyload - -" "L+ /var/lib/pyload/config/scripts/package_extracted/filebot-process.sh - - - - ${filebotScript}/bin/filebot-process" ]; # FileBot license secret sops.secrets.filebot-license = { mode = "0440"; owner = "pyload"; group = "pyload"; }; containers.pyload = { autoStart = true; ephemeral = false; privateNetwork = true; hostBridge = "server"; hostAddress = "${networkPrefix}.97.1"; localAddress = "${networkPrefix}.97.11/24"; # GPU device passthrough for hardware transcoding allowedDevices = [ { modifier = "rwm"; node = "/dev/dri/card0"; } { modifier = "rwm"; node = "/dev/dri/renderD128"; } ]; bindMounts = { "/dev/dri" = { hostPath = "/dev/dri"; isReadOnly = false; }; "/run/opengl-driver" = { hostPath = "/run/opengl-driver"; isReadOnly = true; }; "/nix/store" = { hostPath = "/nix/store"; isReadOnly = true; }; "/var/lib/pyload" = { hostPath = "/var/lib/pyload"; isReadOnly = false; }; "/var/lib/jellyfin" = { hostPath = "/var/lib/jellyfin"; isReadOnly = false; }; "/downloads" = { hostPath = "/var/lib/downloads"; isReadOnly = false; }; "/multimedia" = { hostPath = "/var/lib/multimedia"; isReadOnly = false; }; "/var/lib/pyload/filebot-license.psm" = { hostPath = config.sops.secrets.filebot-license.path; isReadOnly = true; }; }; config = { lib, config, pkgs, ... }: { nixpkgs.overlays = [ (import ../../utils/overlays/packages.nix) ]; imports = [ ./pyload.nix ./jellyfin.nix ]; nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "unrar" "filebot" ]; networking = { hostName = "pyload"; useHostResolvConf = false; defaultGateway = { address = "${networkPrefix}.97.1"; interface = "eth0"; }; nameservers = [ "${networkPrefix}.97.1" ]; firewall.enable = false; }; # Ensure render/video groups exist with consistent GIDs for GPU access users.groups.render = { gid = 303; }; users.groups.video = { gid = 26; }; users.users.pyload = pyloadUser; users.groups.pyload = pyloadGroup; users.users.jellyfin = jellyfinUser; users.groups.jellyfin = jellyfinGroup; system.stateVersion = "24.05"; }; }; }