{ config, pkgs, lib, ... }: let filebotScript = pkgs.callPackage ./filebot-process.nix {}; in { nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ "unrar" "filebot" ]; environment.systemPackages = with pkgs; [ unrar # Required for RAR archive extraction p7zip # Required for 7z and other archive formats ]; # Create directory structure 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 - -" # 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 (only if secrets.yaml exists) sops.secrets.filebot-license = { mode = "0440"; owner = "pyload"; group = "pyload"; path = "/var/lib/pyload/filebot-license.psm"; }; # PyLoad user with jellyfin group membership for multimedia access users.users.pyload = { isSystemUser = true; group = "pyload"; home = "/var/lib/pyload"; createHome = true; extraGroups = [ "jellyfin" ]; }; users.groups.pyload = {}; services.pyload = { enable = true; downloadDirectory = "/var/lib/downloads"; listenAddress = "0.0.0.0"; port = 8000; }; # Configure pyload service systemd.services.pyload = { # Add extraction tools to service PATH path = with pkgs; [ unrar # For RAR extraction p7zip # For 7z extraction ]; environment = { # Disable SSL certificate verification PYLOAD__GENERAL__SSL_VERIFY = "0"; # Download speed limiting (150 Mbit/s = 19200 KiB/s) PYLOAD__DOWNLOAD__LIMIT_SPEED = "1"; PYLOAD__DOWNLOAD__MAX_SPEED = "19200"; # Enable ExtractArchive plugin PYLOAD__EXTRACTARCHIVE__ENABLED = "1"; PYLOAD__EXTRACTARCHIVE__DELETE = "1"; PYLOAD__EXTRACTARCHIVE__DELTOTRASH = "0"; PYLOAD__EXTRACTARCHIVE__REPAIR = "1"; PYLOAD__EXTRACTARCHIVE__RECURSIVE = "1"; PYLOAD__EXTRACTARCHIVE__FULLPATH = "1"; # Enable ExternalScripts plugin for hooks PYLOAD__EXTERNALSCRIPTS__ENABLED = "1"; PYLOAD__EXTERNALSCRIPTS__UNLOCK = "1"; # Run hooks asynchronously }; serviceConfig = { # Bind-mount DNS configuration files into the sandboxed service BindReadOnlyPaths = [ "/etc/resolv.conf" "/etc/nsswitch.conf" "/etc/hosts" "/etc/ssl" "/etc/static/ssl" ]; # Bind mount multimedia directory as writable for FileBot hook scripts BindPaths = [ "/var/lib/multimedia" ]; # Override SystemCallFilter to allow @resources syscalls # FileBot (Java) needs resource management syscalls like setpriority # during cleanup operations. Still block privileged syscalls for security. SystemCallFilter = lib.mkForce [ "@system-service" "@resources" # Explicitly allow resource management syscalls "~@privileged" # Still block privileged operations "fchown" # Re-allow fchown for FileBot file operations "fchown32" # 32-bit compatibility ]; }; }; # Open firewall for PyLoad web interface networking.firewall.allowedTCPPorts = [ 8000 ]; }