Fixed docs

This commit is contained in:
rasmus-kirk
2024-03-01 22:49:56 +01:00
parent d396bd3a11
commit 13dfd643d0
14 changed files with 359 additions and 353 deletions
Generated
+3 -17
View File
@@ -90,22 +90,6 @@
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1709218635,
"narHash": "sha256-nytX/MkfqeTD4z7bMq4QRXcHxO9B3vRo9tM6fMtPFA8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "068d4db604958d05d0b46c47f79b507d84dbc069",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devshell": "devshell",
@@ -153,7 +137,9 @@
},
"vpnconfinement": {
"inputs": {
"nixpkgs": "nixpkgs_2"
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1709159289,
+1 -4
View File
@@ -37,7 +37,6 @@
flake-root.flakeModule
treefmt-nix.flakeModule
devshell.flakeModule
#vpnconfinement.nixosModules.default
];
systems = [
"x86_64-linux"
@@ -45,10 +44,7 @@
flake = {
nixosModules = rec {
#vpnconfinement = vpnconfinement.nixosModules.default;
nixarr = (import ./nixarr vpnconfinement);
#imports = [ vpnconfinement.nixosModules.default ];
#nixarr.imports = [ vpnconfinement ];
default = nixarr;
};
};
@@ -56,6 +52,7 @@
perSystem = {
config,
pkgs,
lib,
...
}: {
treefmt.config = {
+1 -1
View File
@@ -10,7 +10,7 @@
{
config._module.check = false;
}
./nixarr
./nixarr/nixarr.nix
];
};
optionsDocNixos = nixosOptionsDoc {
+4 -237
View File
@@ -1,241 +1,8 @@
vpnconfinement: {
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.nixarr;
in {
vpnconfinement:
{ ... }:
{
imports = [
vpnconfinement.nixosModules.default
./jellyfin
./ddns
./radarr
./lidarr
./readarr
./sonarr
./openssh
./prowlarr
./transmission
../util
./nixarr.nix
];
options.nixarr = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether or not to enable the nixarr module. Has the following features:
- **Run services through a VPN:** You can run any service that this module
supports through a VPN, fx `nixarr.transmission.vpn.enable = true;`
- **Automatic Directories, Users and Permissions:** The module automatically
creates directories and users for your media library. It also sets sane
permissions.
- **State Management:** All services support state management and all state
that they manage is located by default in `/data/.state/nixarr/*`
- **Optional Automatic Port Forwarding:** This module has a UPNP support that
lets services request ports from your router automatically, if you enable it.
It is possible, _but not recommended_, to run the "*Arrs" behind a VPN,
because it can cause rate limiting issues. Generally, you should use
VPN on transmission and maybe jellyfin, depending on your setup.
The following services are supported:
- [Jellyfin](#nixarr.jellyfin.enable)
- [Lidarr](#nixarr.lidarr.enable)
- [Prowlarr](#nixarr.prowlarr.enable)
- [Radarr](#nixarr.radarr.enable)
- [Readarr](#nixarr.readarr.enable)
- [Sonarr](#nixarr.sonarr.enable)
- [Transmission](#nixarr.transmission.enable)
Remember to read the options.
'';
};
mediaDir = mkOption {
type = types.path;
default = "/data/media";
description = ''
The location of the media directory for the services.
'';
};
stateDir = mkOption {
type = types.path;
default = "/data/.state";
description = ''
The location of the state directory for the services.
'';
};
vpn = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
**Required options:** [`nixarr.vpn.wgConf`](#nixarr.vpn.wgconf)
Whether or not to enable VPN support for the services that nixarr
supports.
'';
};
wgConf = mkOption {
type = types.nullOr types.path;
default = null;
description = "The path to the wireguard configuration file.";
};
vpnTestService = {
enable = mkEnableOption ''
the vpn test service. Useful for testing DNS leaks or if the VPN
port forwarding works correctly.
'';
port = mkOption {
type = with types; nullOr port;
default = null;
description = ''
The port that netcat listens to on the vpn test service. If set to
`null`, then netcat will not be started.
'';
example = 58403;
};
};
openTcpPorts = mkOption {
type = with types; listOf port;
default = [];
description = ''
What TCP ports to allow traffic from. You might need this if you're
port forwarding on your VPN provider and you're setting up services
not covered in by this module that uses the VPN.
'';
example = [46382 38473];
};
openUdpPorts = mkOption {
type = with types; listOf port;
default = [];
description = ''
What UDP ports to allow traffic from. You might need this if you're
port forwarding on your VPN provider and you're setting up services
not covered in by this module that uses the VPN.
'';
example = [46382 38473];
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.vpn.enable -> cfg.vpn.wgConf != null;
message = ''
The nixarr.vpn.enable option requires the nixarr.vpn.wgConf option
to be set, but it was not.
'';
}
];
# TODO: move this to modules, at least the "*Arrs"...
users.groups = {
media = {};
streamer = {};
torrenter = {};
};
users.users = {
streamer = {
isSystemUser = true;
group = "streamer";
};
torrenter = {
isSystemUser = true;
group = "torrenter";
};
};
systemd.tmpfiles.rules = [
# Media dirs
"d '${cfg.mediaDir}' 0775 root media - -"
"d '${cfg.mediaDir}/library' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/shows' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/movies' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/music' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/books' 0775 streamer media - -"
"d '${cfg.mediaDir}/torrents' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/.incomplete' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/.watch' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/manual' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/liadarr' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/radarr' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/sonarr' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/readarr' 0755 torrenter media - -"
];
# TODO: wtf to do about openports
vpnnamespaces.wg = {
enable = cfg.vpn.enable ;
accessibleFrom = [
"192.168.1.0/24"
"127.0.0.1"
];
wireguardConfigFile = cfg.vpn.wgConf;
};
# TODO: openports
systemd.services.vpn-test-service = {
enable = cfg.vpn.vpnTestService.enable;
vpnconfinement = {
enable = true;
vpnnamespace = "wg";
};
script = let
vpn-test = pkgs.writeShellApplication {
name = "vpn-test";
runtimeInputs = with pkgs; [util-linux unixtools.ping coreutils curl bash libressl netcat-gnu openresolv dig];
text = ''
cd "$(mktemp -d)"
# Print resolv.conf
echo "/etc/resolv.conf contains:"
cat /etc/resolv.conf
# Query resolvconf
echo "resolvconf output:"
resolvconf -l
echo ""
# Get ip
echo "Getting IP:"
curl -s ipinfo.io
echo -ne "DNS leak test:"
curl -s https://raw.githubusercontent.com/macvk/dnsleaktest/b03ab54d574adbe322ca48cbcb0523be720ad38d/dnsleaktest.sh -o dnsleaktest.sh
chmod +x dnsleaktest.sh
./dnsleaktest.sh
'' + (if cfg.vpn.vpnTestService.port != null then ''
echo "starting netcat on port ${builtins.toString cfg.vpn.vpnTestService.port}:"
nc -vnlp ${builtins.toString cfg.vpn.vpnTestService.port}
'' else "");
};
in "${vpn-test}/bin/vpn-test";
bindsTo = ["netns@wg.service"];
requires = ["network-online.target"];
after = ["wg.service"];
serviceConfig = {
#User = "torrenter";
NetworkNamespacePath = "/var/run/netns/wg";
BindReadOnlyPaths = ["/etc/netns/wg/resolv.conf:/etc/resolv.conf:norbind" "/data/test.file:/etc/test.file:norbind"];
};
};
};
}
+1 -1
View File
@@ -13,7 +13,7 @@ in with lib; {
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/nixarr/jellyfin";
default = "${nixarr.stateDir}/jellyfin";
description = "The state directory for Jellyfin.";
};
+1 -1
View File
@@ -12,7 +12,7 @@ in {
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/nixarr/lidarr";
default = "${nixarr.stateDir}/lidarr";
description = "The state directory for Lidarr";
};
+240
View File
@@ -0,0 +1,240 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.nixarr;
in {
imports = [
./jellyfin
./ddns
./radarr
./lidarr
./readarr
./sonarr
./openssh
./prowlarr
./transmission
../util
];
options.nixarr = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether or not to enable the nixarr module. Has the following features:
- **Run services through a VPN:** You can run any service that this module
supports through a VPN, fx `nixarr.transmission.vpn.enable = true;`
- **Automatic Directories, Users and Permissions:** The module automatically
creates directories and users for your media library. It also sets sane
permissions.
- **State Management:** All services support state management and all state
that they manage is located by default in `/data/.state/nixarr/*`
- **Optional Automatic Port Forwarding:** This module has a UPNP support that
lets services request ports from your router automatically, if you enable it.
It is possible, _but not recommended_, to run the "*Arrs" behind a VPN,
because it can cause rate limiting issues. Generally, you should use
VPN on transmission and maybe jellyfin, depending on your setup.
The following services are supported:
- [Jellyfin](#nixarr.jellyfin.enable)
- [Lidarr](#nixarr.lidarr.enable)
- [Prowlarr](#nixarr.prowlarr.enable)
- [Radarr](#nixarr.radarr.enable)
- [Readarr](#nixarr.readarr.enable)
- [Sonarr](#nixarr.sonarr.enable)
- [Transmission](#nixarr.transmission.enable)
Remember to read the options.
'';
};
mediaDir = mkOption {
type = types.path;
default = "/data/media";
description = ''
The location of the media directory for the services.
'';
};
stateDir = mkOption {
type = types.path;
default = "/data/.state/nixarr";
description = ''
The location of the state directory for the services.
'';
};
vpn = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
**Required options:** [`nixarr.vpn.wgConf`](#nixarr.vpn.wgconf)
Whether or not to enable VPN support for the services that nixarr
supports.
'';
};
wgConf = mkOption {
type = types.nullOr types.path;
default = null;
description = "The path to the wireguard configuration file.";
};
vpnTestService = {
enable = mkEnableOption ''
the vpn test service. Useful for testing DNS leaks or if the VPN
port forwarding works correctly.
'';
port = mkOption {
type = with types; nullOr port;
default = null;
description = ''
The port that netcat listens to on the vpn test service. If set to
`null`, then netcat will not be started.
'';
example = 58403;
};
};
openTcpPorts = mkOption {
type = with types; listOf port;
default = [];
description = ''
What TCP ports to allow traffic from. You might need this if you're
port forwarding on your VPN provider and you're setting up services
not covered in by this module that uses the VPN.
'';
example = [46382 38473];
};
openUdpPorts = mkOption {
type = with types; listOf port;
default = [];
description = ''
What UDP ports to allow traffic from. You might need this if you're
port forwarding on your VPN provider and you're setting up services
not covered in by this module that uses the VPN.
'';
example = [46382 38473];
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.vpn.enable -> cfg.vpn.wgConf != null;
message = ''
The nixarr.vpn.enable option requires the nixarr.vpn.wgConf option
to be set, but it was not.
'';
}
];
# TODO: move this to modules, at least the "*Arrs"...
users.groups = {
media = {};
streamer = {};
torrenter = {};
};
users.users = {
streamer = {
isSystemUser = true;
group = "streamer";
};
torrenter = {
isSystemUser = true;
group = "torrenter";
};
};
systemd.tmpfiles.rules = [
# Media dirs
"d '${cfg.mediaDir}' 0775 root media - -"
"d '${cfg.mediaDir}/library' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/shows' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/movies' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/music' 0775 streamer media - -"
"d '${cfg.mediaDir}/library/books' 0775 streamer media - -"
"d '${cfg.mediaDir}/torrents' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/.incomplete' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/.watch' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/manual' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/liadarr' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/radarr' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/sonarr' 0755 torrenter media - -"
"d '${cfg.mediaDir}/torrents/readarr' 0755 torrenter media - -"
];
# TODO: wtf to do about openports
vpnnamespaces.wg = {
enable = cfg.vpn.enable ;
accessibleFrom = [
"192.168.1.0/24"
"127.0.0.1"
];
wireguardConfigFile = cfg.vpn.wgConf;
};
# TODO: openports
systemd.services.vpn-test-service = {
enable = cfg.vpn.vpnTestService.enable;
vpnconfinement = {
enable = true;
vpnnamespace = "wg";
};
script = let
vpn-test = pkgs.writeShellApplication {
name = "vpn-test";
runtimeInputs = with pkgs; [util-linux unixtools.ping coreutils curl bash libressl netcat-gnu openresolv dig];
text = ''
cd "$(mktemp -d)"
# Print resolv.conf
echo "/etc/resolv.conf contains:"
cat /etc/resolv.conf
# Query resolvconf
echo "resolvconf output:"
resolvconf -l
echo ""
# Get ip
echo "Getting IP:"
curl -s ipinfo.io
echo -ne "DNS leak test:"
curl -s https://raw.githubusercontent.com/macvk/dnsleaktest/b03ab54d574adbe322ca48cbcb0523be720ad38d/dnsleaktest.sh -o dnsleaktest.sh
chmod +x dnsleaktest.sh
./dnsleaktest.sh
'' + (if cfg.vpn.vpnTestService.port != null then ''
echo "starting netcat on port ${builtins.toString cfg.vpn.vpnTestService.port}:"
nc -vnlpu ${builtins.toString cfg.vpn.vpnTestService.port}
'' else "");
};
in "${vpn-test}/bin/vpn-test";
bindsTo = ["netns@wg.service"];
requires = ["network-online.target"];
after = ["wg.service"];
serviceConfig = {
#User = "torrenter";
NetworkNamespacePath = "/var/run/netns/wg";
BindReadOnlyPaths = ["/etc/netns/wg/resolv.conf:/etc/resolv.conf:norbind" "/data/test.file:/etc/test.file:norbind"];
};
};
};
}
+1 -3
View File
@@ -18,7 +18,7 @@ in {
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/nixarr/prowlarr";
default = "${nixarr.stateDir}/prowlarr";
description = "The state directory for Prowlarr.";
};
@@ -48,8 +48,6 @@ in {
"d '${cfg.stateDir}' 0700 prowlarr root - -"
];
users.groups.prowlarr = {};
util-nixarr.services.prowlarr = {
enable = true;
dataDir = cfg.stateDir;
+3 -1
View File
@@ -70,6 +70,8 @@ in {
};
};
users.groups = mkIf (cfg.group == "prowlarr") {};
users.groups = mkIf (cfg.group == "prowlarr") {
prowlarr = { };
};
};
}
+1 -1
View File
@@ -14,7 +14,7 @@ in {
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/nixarr/radarr";
default = "${nixarr.stateDir}/radarr";
description = "The state directory for radarr.";
};
+1 -1
View File
@@ -12,7 +12,7 @@ in {
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/nixarr/readarr";
default = "${nixarr.stateDir}/readarr";
description = "The state directory for Readarr";
};
+51 -5
View File
@@ -8,7 +8,37 @@ with lib; let
cfg = config.util-nixarr.services.cross-seed;
settingsFormat = pkgs.formats.json {};
settingsFile = settingsFormat.generate "settings.json" cfg.settings;
cross-seedPkg = import ../../../pkgs/cross-seed { inherit (pkgs) stdenv lib fetchFromGitHub; };
cross-seedPkg = pkgs.callPackage ../../../pkgs/cross-seed {};
configJs = pkgs.writeText "config.js" ''
// Loads a json.config
"use strict";
const fs = require('fs');
const jsonPath = '${cfg.dataDir}/config.json'
// Synchronously read the JSON-configuration file
const configFileContent = fs.readFileSync(jsonPath, { encoding: 'utf8' });
// Parse the JSON content into a JavaScript object
let config = JSON.parse(configFileContent);
// Function to recursively replace null values with undefined
/*
function replaceNullWithUndefined(obj) {
Object.keys(obj).forEach(key => {
if (obj[key] === null) {
obj[key] = undefined;
} else if (typeof obj[key] === 'object') {
replaceNullWithUndefined(obj[key]);
}
});
}
replaceNullWithUndefined(config);
*/
// Export the configuration object
module.exports = config;
'';
in {
options = {
util-nixarr.services.cross-seed = {
@@ -52,10 +82,24 @@ in {
};
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
assertions = [
{
assertion = cfg.enable -> cfg.settings.outputDir != null;
message = ''
The settings.outputDir must be set if cross-seed is enabled.
'';
}
];
systemd.tmpfiles.rules = [
"L+ '${cfg.dataDir}'/config.js - - - - ${configJs}"
"d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
] ++ (
if cfg.settings.outputDir != null then
[ "d '${cfg.settings.outputDir}' 0755 ${cfg.user} ${cfg.group} - -" ]
else []
);
systemd.services.cross-seed = {
description = "cross-seed";
after = ["network.target"];
@@ -73,7 +117,7 @@ in {
Type = "simple";
User = cfg.user;
Group = cfg.group;
ExecStart = "${getExe cross-seedPkg} daemon";
ExecStart = "${cross-seedPkg}/bin/cross-seed daemon";
Restart = "on-failure";
};
};
@@ -85,6 +129,8 @@ in {
};
};
users.groups = mkIf (cfg.group == "cross-seed") {};
users.groups = mkIf (cfg.group == "cross-seed") {
cross-seed = { };
};
};
}
+36 -13
View File
@@ -9,12 +9,25 @@ with lib; let
nixarr = config.nixarr;
cfg-cross-seed = config.nixarr.transmission.privateTrackers.cross-seed;
transmissionCrossSeedScript = with builtins; pkgs.writeShellApplication {
name = "mk-cross-seed-credentials";
name = "transmission-cross-seed-script";
runtimeInputs = with pkgs; [ curl ];
text = ''
curl -XPOST http://localhost:2468/api/webhook?apikey=YOUR_API_KEY --data-urlencode "infoHash=$TR_TORRENT_HASH"
PROWLARR_API_KEY=$(cat prowlarr-api-key)
curl -XPOST http://localhost:2468/api/webhook?apikey="$PROWLARR_API_KEY" --data-urlencode "infoHash=$TR_TORRENT_HASH"
'';
};
importProwlarrApi = with builtins; pkgs.writeShellApplication {
name = "import-prowlarr-api";
runtimeInputs = with pkgs; [ yq ];
text = ''
touch ${cfg.stateDir}/prowlarr-api-key
chmod 400 ${cfg.stateDir}/prowlarr-api-key
chown torrenter ${cfg.stateDir}/prowlarr-api-key
xq -r '.Config.ApiKey' "${nixarr.prowlarr.stateDir}/config.xml" > "${cfg.stateDir}/prowlarr-api-key"
'';
};
mkCrossSeedCredentials = with builtins; pkgs.writeShellApplication {
@@ -24,14 +37,17 @@ with lib; let
text =
"INDEX_LINKS=("
+ strings.concatMapStringsSep " " toString cfg.privateTrackers.cross-seed.indexIds
+ (strings.concatMapStringsSep " " toString cfg.privateTrackers.cross-seed.indexIds)
+ ")"
''
+ "\n"
+ ''
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")
PROWLARR_API_KEY=$(xq -r '.Config.ApiKey' "${nixarr.prowlarr.stateDir}/config.xml")
# shellcheck disable=SC2034
CRED_DIR=$(dirname "$CRED_FILE")
mkdir -p "$CRED_DIR"
echo '{}' > "$CRED_FILE"
chmod 400 "$CRED_FILE"
chown "${config.util-nixarr.services.cross-seed.user}" "$CRED_FILE"
@@ -49,7 +65,7 @@ in {
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/nixarr/transmission";
default = "${nixarr.stateDir}/transmission";
description = ''
The state directory for Transmission.
'';
@@ -103,7 +119,7 @@ in {
stateDir = mkOption {
type = types.path;
default = "${nixarr.stateDir}/nixarr/cross-seed";
default = "${nixarr.stateDir}/cross-seed";
description = ''
The state directory for Transmission.
'';
@@ -212,8 +228,8 @@ in {
#group = "media";
settings = {
torrentDir = "${nixarr.mediaDir}/torrents";
outputDir = "${nixarr.mediaDir}/torrents/cross-seed";
transmissionRpcUrl = "http://transmission:${builtins.toString cfg.uiPort}/transmission/rpc";
outputDir = "${nixarr.mediaDir}/torrents/.cross-seed";
transmissionRpcUrl = "http://localhost:${builtins.toString cfg.uiPort}/transmission/rpc";
rssCadence = "20 minutes";
# Enable infrequent periodic searches
@@ -224,11 +240,16 @@ in {
};
# 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))
ExecStartPre = mkBefore [(
"+" + "${mkCrossSeedCredentials}/bin/mk-cross-seed-credentials"
)];
};
systemd.services.transmission.serviceConfig = mkIf cfg-cross-seed.enable {
ExecStartPre = mkBefore [(
"+" + "${importProwlarrApi}/bin/import-prowlarr-api"
)];
};
services.transmission = {
enable = true;
user = "torrenter";
@@ -270,7 +291,9 @@ in {
anti-brute-force-threshold = 10;
script-torrent-done-enabled = cfg-cross-seed.enable;
script-torrent-done-filename = if cfg-cross-seed.enable then transmissionCrossSeedScript else null;
script-torrent-done-filename = if cfg-cross-seed.enable then
"${transmissionCrossSeedScript}/bin/transmission-cross-seed-script"
else null;
message-level =
if cfg.messageLevel == "none"
+15 -68
View File
@@ -1,75 +1,22 @@
{
config,
pkgs,
lib,
...
}:
with lib; let
cfg = config.util-nixarr.services.prowlarr;
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.prowlarr = {
enable = mkEnableOption "cross-seed";
{ lib, buildNpmPackage, fetchFromGitHub }:
configFile = mkOption {
type = with types; nullOr path;
default = null;
example = "/var/lib/secrets/cross-seed/settings.json";
description = "";
};
buildNpmPackage rec {
pname = "cross-seed";
version = "5.9.2";
dataDir = mkOption {
type = types.path;
default = "/var/lib/cross-seed";
};
user = mkOption {
type = types.str;
default = "cross-seed";
description = "User account under which cross-seed runs.";
};
group = mkOption {
type = types.str;
default = "cross-seed";
description = "Group under which cross-seed runs.";
};
};
src = fetchFromGitHub {
owner = "cross-seed";
repo = pname;
rev = "v${version}";
hash = "sha256-E0AlsFV9RP01YVwjw6ZQ8Lf1IVyuudxrb5oJ61EfIyo=";
};
config = mkIf cfg.enable {
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 ${cfg.user} ${cfg.group} - -"
];
npmDepsHash = "sha256-hZKLv+bzRFiMjNemydCUC1d7xul7Mm+vOPtCUD7p9XQ=";
systemd.services.prowlarr = {
description = "cross-seed";
after = ["network.target"];
wantedBy = ["multi-user.target"];
environment.CONFIG_DIR = cfg.dataDir;
serviceConfig = {
ExecStartPre = [("+" + pkgs.writeShellScript "transmission-prestart" ''
mv ${cfg.configFile} ${cfg.dataDir}
'')];
Type = "simple";
User = cfg.user;
Group = cfg.group;
ExecStart = "${getExe cross-seedPkg} daemon";
Restart = "on-failure";
};
};
users.users = mkIf (cfg.user == "cross-seed") {
cross-seed = {
group = cfg.group;
};
};
users.groups = mkIf (cfg.group == "cross-seed") {};
meta = with lib; {
description = "cross-seed is an app designed to help you download torrents that you can cross seed based on your existing torrents";
homepage = "https://www.cross-seed.org";
license = licenses.asl20;
maintainers = with maintainers; [ rasmus-kirk ];
};
}