diff --git a/service-configs.nix b/service-configs.nix index e48a910..a3294bc 100644 --- a/service-configs.nix +++ b/service-configs.nix @@ -205,6 +205,17 @@ rec { torrent = { SavePath = torrents_path; TempPath = torrents_path + "/incomplete"; + categories = { + anime = torrents_path + "/anime"; + archive = torrents_path + "/archive"; + audiobooks = torrents_path + "/audiobooks"; + books = torrents_path + "/books"; + games = torrents_path + "/games"; + movies = torrents_path + "/movies"; + music = torrents_path + "/music"; + musicals = torrents_path + "/musicals"; + tvshows = torrents_path + "/tvshows"; + }; }; jellyfin = { diff --git a/services/arr/torrent-audit.nix b/services/arr/torrent-audit.nix index e59e211..95e8b1a 100644 --- a/services/arr/torrent-audit.nix +++ b/services/arr/torrent-audit.nix @@ -2,6 +2,7 @@ pkgs, config, service_configs, + lib, ... }: { @@ -34,7 +35,7 @@ RADARR_CONFIG = "${service_configs.radarr.dataDir}/config.xml"; SONARR_URL = "http://localhost:${builtins.toString service_configs.ports.private.sonarr.port}"; SONARR_CONFIG = "${service_configs.sonarr.dataDir}/config.xml"; - CATEGORIES = "tvshows,movies,anime"; + CATEGORIES = lib.concatStringsSep "," (builtins.attrNames service_configs.torrent.categories); TAG_TORRENTS = "true"; }; }; diff --git a/services/qbittorrent.nix b/services/qbittorrent.nix index c69f64b..0b12874 100644 --- a/services/qbittorrent.nix +++ b/services/qbittorrent.nix @@ -6,6 +6,11 @@ inputs, ... }: +let + categoriesFile = pkgs.writeText "categories.json" ( + builtins.toJSON (lib.mapAttrs (_: path: { save_path = path; }) service_configs.torrent.categories) + ); +in { imports = [ (lib.serviceMountWithZpool "qbittorrent" service_configs.zpool_hdds [ @@ -135,6 +140,22 @@ UMask = lib.mkForce "0007"; }; + # Pre-define qBittorrent categories with explicit save paths so every + # torrent routes to its category directory instead of the SavePath root. + systemd.tmpfiles.settings.qbittorrent-categories = { + "${config.services.qbittorrent.profileDir}/qBittorrent/config/categories.json"."L+" = { + argument = "${categoriesFile}"; + user = config.services.qbittorrent.user; + group = config.services.qbittorrent.group; + mode = "1400"; + }; + }; + + # Ensure category directories exist with correct ownership before first use. + systemd.tmpfiles.rules = lib.mapAttrsToList ( + _: path: "d ${path} 0770 ${config.services.qbittorrent.user} ${service_configs.media_group} -" + ) service_configs.torrent.categories; + services.caddy.virtualHosts."torrent.${service_configs.https.domain}".extraConfig = '' import ${config.age.secrets.caddy_auth.path} reverse_proxy ${config.vpnNamespaces.wg.namespaceAddress}:${builtins.toString config.services.qbittorrent.webuiPort}