From bf8eb5fb63c39b604ed4eca493e340d395b6c2ec Mon Sep 17 00:00:00 2001 From: rasmus-kirk Date: Fri, 1 Mar 2024 12:24:17 +0100 Subject: [PATCH] Added cross-seed support, still untested --- flake.nix | 1 - nixarr/openssh/default.nix | 12 +- nixarr/transmission/cross-seed/default.nix | 31 +++-- nixarr/transmission/default.nix | 125 ++++++++++++++++----- 4 files changed, 127 insertions(+), 42 deletions(-) diff --git a/flake.nix b/flake.nix index 73a91ce..a731e83 100644 --- a/flake.nix +++ b/flake.nix @@ -63,7 +63,6 @@ packages = { docs = pkgs.callPackage ./mkDocs.nix {inherit inputs;}; - pandoc = pkgs.callPackage ./mkPandoc.nix {inherit inputs;}; }; devshells.default = { diff --git a/nixarr/openssh/default.nix b/nixarr/openssh/default.nix index 52e3d1f..d563747 100644 --- a/nixarr/openssh/default.nix +++ b/nixarr/openssh/default.nix @@ -41,12 +41,12 @@ in { ''; }; - config = mkIf cfg.vpn.enable { + config = mkIf cfg.expose.vpn.enable { assertions = [ { - assertion = cfg.vpn.enable -> nixarr.vpn.enable; + assertion = cfg.expose.vpn.enable -> nixarr.vpn.enable; message = '' - The nixarr.openssh.vpn.enable option requires the + The nixarr.openssh.expose.vpn.enable option requires the nixarr.vpn.enable option to be set, but it was not. ''; } @@ -54,9 +54,9 @@ in { warnings = if config.services.openssh.enable then [ '' - nixarr.openssh.vpn.enable is set, but openssh is not enabled on your - system, so the openssh server is not running. This is probably not - what you wanted. You can add the following lines to enable it: + nixarr.openssh.expose.vpn.enable is set, but openssh is not enabled + on your system, so the openssh server is not running. This is probably + not what you wanted. You can add the following lines to enable it: services.openssh = { enable = true; diff --git a/nixarr/transmission/cross-seed/default.nix b/nixarr/transmission/cross-seed/default.nix index f6845e5..6ed2f10 100644 --- a/nixarr/transmission/cross-seed/default.nix +++ b/nixarr/transmission/cross-seed/default.nix @@ -6,19 +6,23 @@ }: with lib; let cfg = config.util-nixarr.services.cross-seed; - #settingsFormat = pkgs.formats.json {}; - #settingsFile = settingsFormat.generate "settings.json" cfg.settings; + settingsFormat = pkgs.formats.json {}; + settingsFile = settingsFormat.generate "settings.json" cfg.settings; cross-seedPkg = import ../../../pkgs/cross-seed { inherit (pkgs) stdenv lib fetchFromGitHub; }; in { options = { util-nixarr.services.cross-seed = { enable = mkEnableOption "cross-seed"; - configFile = mkOption { - type = with types; nullOr path; - default = null; - example = "/var/lib/secrets/cross-seed/settings.js"; - description = "cross-seed config file"; # TODO: todo + settings = mkOption { + type = types.attrs; + default = {}; + example = '' + { + delay = 10; + } + ''; + description = "cross-seed config"; # TODO: todo }; dataDir = mkOption { @@ -27,6 +31,12 @@ in { description = "cross-seed dataDir"; # TODO: todo }; + credentialsFile = mkOption { + type = types.path; + default = "/run/secrets/cross-seed/credentialsFile.json"; + description = "cross-seed dataDir"; # TODO: todo + }; + user = mkOption { type = types.str; default = "cross-seed"; @@ -54,9 +64,12 @@ in { environment.CONFIG_DIR = cfg.dataDir; serviceConfig = { + # Run as root in case that the cfg.credentialsFile is not readable by cross-seed ExecStartPre = [("+" + pkgs.writeShellScript "transmission-prestart" '' - mv ${cfg.configFile} ${cfg.dataDir} - '')]; + ${pkgs.jq}/bin/jq --slurp add ${settingsFile} '${cfg.credentialsFile}' | + install -D -m 600 -o '${cfg.user}' /dev/stdin '${cfg.dataDir}/config.json' + '' + )]; Type = "simple"; User = cfg.user; Group = cfg.group; diff --git a/nixarr/transmission/default.nix b/nixarr/transmission/default.nix index 4d9a146..c419b11 100644 --- a/nixarr/transmission/default.nix +++ b/nixarr/transmission/default.nix @@ -1,4 +1,3 @@ -# TODO: Dir creation and file permissions in nix { config, lib, @@ -9,19 +8,41 @@ with lib; let cfg = config.nixarr.transmission; nixarr = config.nixarr; dnsServers = config.lib.vpn.dnsServers; - get-indexers = with builtins; pkgs.writeShellApplication { - name = "get-indexers"; + cfg-cross-seed = config.nixarr.transmission.privateTrackers.cross-seed; + transmissionCrossSeedScript = with builtins; pkgs.writeShellApplication { + name = "mk-cross-seed-credentials"; - runtimeInputs = with pkgs; [ jq yq ]; + runtimeInputs = with pkgs; [ curl ]; text = '' - PROWLARR_API_KEY=$(xq '.Config.ApiKey' "${nixarr.prowlarr.stateDir}/config.xml") - '' - + toJson ( - map (x: - ''http://localhost:9696/${toString x}/api?apikey="$PROWLARR_API_KEY"'' - ) cfg.privateTrackers.cross-seed.indexIds - ); + curl -XPOST http://localhost:2468/api/webhook?apikey=YOUR_API_KEY --data-urlencode "infoHash=$TR_TORRENT_HASH" + ''; + }; + mkCrossSeedCredentials = with builtins; pkgs.writeShellApplication { + name = "mk-cross-seed-credentials"; + + runtimeInputs = with pkgs; [ jq yq ]; + + text = + "INDEX_LINKS=(" + + strings.concatMapStringsSep " " toString cfg.privateTrackers.cross-seed.indexIds + + ")" + '' + TMP_JSON=$(mktemp) + CRED_FILE="/run/secrets/cross-seed/credentialsFile.json" + PROWLARR_API_KEY=$(xq '.Config.ApiKey' "${nixarr.prowlarr.stateDir}/config.xml") + CRED_DIR=$(dirname "$filePath") + + echo '{}' > "$CRED_FILE" + chmod 400 "$CRED_FILE" + chown "${config.util-nixarr.services.cross-seed.user}" "$CRED_FILE" + + for i in "''${INDEX_LINKS[@]}" + do + LINK="http://localhost:9696/$i/api?apikey=$PROWLARR_API_KEY" + jq ".torznab += [\"$LINK\"]" "$CRED_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$CRED_FILE" + done + ''; }; in { options.nixarr.transmission = { @@ -69,19 +90,47 @@ in { their rules ¯\\_(ツ)_/¯. ''; }; + cross-seed = { enable = mkOption { type = types.bool; default = false; description = '' - Enable the cross-seed service. + **Required options:** [`nixarr.prowlarr.enable`](#nixarr.prowlarr.enable) + + Whether or not to enable the [cross-seed](https://www.cross-seed.org/) service. ''; }; + + stateDir = mkOption { + type = types.path; + default = "${nixarr.stateDir}/nixarr/cross-seed"; + description = '' + The state directory for Transmission. + ''; + }; + indexIds = mkOption { type = with types; listOf int; default = []; description = '' - list of indexers TODO: todo + List of indexer-ids, from prowlarr. These are from the RSS links + for the indexers, located by the "radio" or "RSS" logo on the + right of the indexer, you'll see the links have the form: + + `http://localhost:9696/1/api?apikey=aaaaaaaaaaaaa` + + Then the id needed here is the `1`. + ''; + }; + + extraSettings = mkOption { + type = types.attrs; + default = {}; + description = '' + Extra settings for the cross-seed + service, see [the cross-seed options + documentation](https://www.cross-seed.org/docs/basics/options) ''; }; }; @@ -113,7 +162,7 @@ in { description = "Transmission web-UI port."; }; - extraConfig = mkOption { + extraSettings = mkOption { type = types.attrs; default = {}; description = '' @@ -140,9 +189,10 @@ in { ''; } { - assertion = cfg.privateTrackers.cross-seed.enable -> nixarr.prowlarr.enable; + assertion = cfg-cross-seed.enable -> nixarr.prowlarr.enable; message = '' - TODO: todo + The nixarr.privateTrackers.cross-seed.enable option requires the + nixarr.prowlarr.enable option to be set, but it was not. ''; } ]; @@ -151,7 +201,34 @@ in { "d '${cfg.stateDir}' 0700 torrenter root - -" # This is fixes a bug in nixpks (https://github.com/NixOS/nixpkgs/issues/291883) "d '${cfg.stateDir}/.config/transmission-daemon' 0700 torrenter root - -" - ]; + ] ++ ( + if cfg-cross-seed.enable then + [ "d '${cfg-cross-seed.stateDir}' 0700 cross-seed root - -" ] + else [] + ); + + util-nixarr.services.cross-seed = mkIf cfg-cross-seed.enable { + enable = true; + dataDir = cfg-cross-seed.stateDir; + #group = "media"; + settings = { + torrentDir = "${nixarr.mediaDir}/torrents"; + outputDir = "${nixarr.mediaDir}/torrents/cross-seed"; + transmissionRpcUrl = "http://transmission:${builtins.toString cfg.uiPort}/transmission/rpc"; + rssCadence = "20 minutes"; + + # Enable infrequent periodic searches + searchCadence = "1 week"; + excludeRecentSearch = "1 year"; + excludeOlder = "1 year"; + } // cfg-cross-seed.extraSettings; + }; + # Run as root in case that the cfg.credentialsFile is not readable by cross-seed + systemd.services.cross-seed.serviceConfig = mkIf cfg-cross-seed.enable { + ExecStartPre = [(mkBefore + ("+" + (getExe mkCrossSeedCredentials)) + )]; + }; services.transmission = mkIf (!cfg.vpn.enable) { enable = true; @@ -192,6 +269,9 @@ in { anti-brute-force-enabled = true; anti-brute-force-threshold = 10; + script-torrent-done-enabled = true; + script-torrent-done-filename = getExe transmissionCrossSeedScript; + message-level = if cfg.messageLevel == "none" then 0 @@ -209,14 +289,7 @@ in { then 6 else null; } - // cfg.extraConfig; - }; - - services.cross-seed = mkIf cfg.cross-seed.enable { - enable = true; - group = "media"; - dataDir = cfg.privateTrackers.cross-seed.dataDir; - configFile = cfg.privateTrackers.cross-seed.configFile; + // cfg.extraSettings; }; util-nixarr.vpnnamespace = mkIf cfg.vpn.enable { @@ -309,7 +382,7 @@ in { # 0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace message-level = 3; } - // cfg.extraConfig; + // cfg.extraSettings; }; environment.systemPackages = with pkgs; [