Merge pull request #98 from pierzchalski/eap/rationalise-readarr

`readarr{,-audiobook}`: use `service.${service}` config pattern
This commit is contained in:
Rasmus Kirk
2025-11-23 08:10:04 +00:00
committed by GitHub
3 changed files with 161 additions and 17 deletions
+93
View File
@@ -0,0 +1,93 @@
# Utilities for defining *arr service settings, options, and configs.
#
# Copied from nixpkgs master as of 2025-11-11: https://raw.githubusercontent.com/NixOS/nixpkgs/cf540f8c9840457ed90a315dd635bceecb78495a/nixos/modules/services/misc/servarr/settings-options.nix
{
lib,
pkgs,
}: {
mkServarrSettingsOptions = name: port:
lib.mkOption {
type = lib.types.submodule {
freeformType = (pkgs.formats.ini {}).type;
options = {
update = {
mechanism = lib.mkOption {
type = with lib.types;
nullOr (enum [
"external"
"builtIn"
"script"
]);
description = "which update mechanism to use";
default = "external";
};
automatically = lib.mkOption {
type = lib.types.bool;
description = "Automatically download and install updates.";
default = false;
};
};
server = {
port = lib.mkOption {
type = lib.types.port;
description = "Port Number";
default = port;
};
};
log = {
analyticsEnabled = lib.mkOption {
type = lib.types.bool;
description = "Send Anonymous Usage Data";
default = false;
};
};
};
};
example = lib.options.literalExpression ''
{
update.mechanism = "internal";
server = {
urlbase = "localhost";
port = ${toString port};
bindaddress = "*";
};
}
'';
default = {};
description = ''
Attribute set of arbitrary config options.
Please consult the documentation at the [wiki](https://wiki.servarr.com/useful-tools#using-environment-variables-for-config).
WARNING: this configuration is stored in the world-readable Nix store!
For secrets use [](#opt-services.${name}.environmentFiles).
'';
};
mkServarrEnvironmentFiles = name:
lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [];
description = ''
Environment file to pass secret configuration values.
Each line must follow the `${lib.toUpper name}__SECTION__KEY=value` pattern.
Please consult the documentation at the [wiki](https://wiki.servarr.com/useful-tools#using-environment-variables-for-config).
'';
};
mkServarrSettingsEnvVars = name: settings:
lib.pipe settings [
(lib.mapAttrsRecursive (
path: value:
lib.optionalAttrs (value != null) {
name = lib.toUpper "${name}__${lib.concatStringsSep "__" path}";
value = toString (
if lib.isBool value
then lib.boolToString value
else value
);
}
))
(lib.collect (x: lib.isString x.name or false && lib.isString x.value or false))
lib.listToAttrs
];
}
+60 -4
View File
@@ -6,9 +6,12 @@
}: }:
with lib; let with lib; let
cfg = config.nixarr.readarr-audiobook; cfg = config.nixarr.readarr-audiobook;
service-cfg = config.services.readarr-audiobook;
globals = config.util-nixarr.globals; globals = config.util-nixarr.globals;
nixarr = config.nixarr; nixarr = config.nixarr;
port = 9494; port = 9494;
arr-settings-options = import ../lib/arr-settings-options.nix {inherit lib pkgs;};
in { in {
options.nixarr.readarr-audiobook = { options.nixarr.readarr-audiobook = {
enable = mkOption { enable = mkOption {
@@ -69,6 +72,46 @@ in {
}; };
}; };
# A tweaked copy of services.readarr from nixpkgs
options.services.readarr-audiobook = {
enable = lib.mkEnableOption "Readarr-Audiobook, a Usenet/BitTorrent audiobook downloader";
dataDir = lib.mkOption {
type = lib.types.str;
description = "The directory where Readarr-Audiobook stores its data files.";
};
package = lib.mkPackageOption pkgs "readarr" {};
openFirewall = lib.mkOption {
type = lib.types.bool;
description = ''
Open ports in the firewall for Readarr-Audiobook.
'';
};
# Uses name in description to refer to
# `services.readarr-audiobook.environmentFiles`.
settings = arr-settings-options.mkServarrSettingsOptions "readarr-audiobook" port;
# Uses name in description to document `READARR__*` environment variables.
environmentFiles = arr-settings-options.mkServarrEnvironmentFiles "readarr";
user = lib.mkOption {
type = lib.types.str;
description = ''
User account under which Readarr-Audiobook runs.
'';
};
group = lib.mkOption {
type = lib.types.str;
description = ''
Group under which Readarr-Audiobook runs.
'';
};
};
config = mkIf (nixarr.enable && cfg.enable) { config = mkIf (nixarr.enable && cfg.enable) {
assertions = [ assertions = [
{ {
@@ -96,17 +139,30 @@ in {
"d '${nixarr.mediaDir}/library/audiobooks' 0775 ${globals.libraryOwner.user} ${globals.libraryOwner.group} - -" "d '${nixarr.mediaDir}/library/audiobooks' 0775 ${globals.libraryOwner.user} ${globals.libraryOwner.group} - -"
]; ];
services.readarr-audiobook = {
enable = cfg.enable;
package = cfg.package;
settings.server.port = cfg.port;
openFirewall = cfg.openFirewall;
dataDir = cfg.stateDir;
user = globals.readarr-audiobook.user;
group = globals.readarr-audiobook.group;
};
systemd.services.readarr-audiobook = { systemd.services.readarr-audiobook = {
description = "Readarr-Audiobook"; description = "Readarr-Audiobook";
after = ["network.target"]; after = ["network.target"];
wantedBy = ["multi-user.target"]; wantedBy = ["multi-user.target"];
environment.READARR__SERVER__PORT = builtins.toString cfg.port;
# Uses name to define `READARR__*` environment variables.
environment = arr-settings-options.mkServarrSettingsEnvVars "readarr" service-cfg.settings;
serviceConfig = { serviceConfig = {
Type = "simple"; Type = "simple";
User = globals.readarr-audiobook.user; User = service-cfg.user;
Group = globals.readarr-audiobook.group; Group = service-cfg.group;
ExecStart = "${lib.getExe cfg.package} -nobrowser -data=${cfg.stateDir}"; EnvironmentFile = service-cfg.environmentFiles;
ExecStart = "${lib.getExe service-cfg.package} -nobrowser -data=${service-cfg.dataDir}";
Restart = "on-failure"; Restart = "on-failure";
}; };
}; };
+8 -13
View File
@@ -94,19 +94,14 @@ in {
"d '${nixarr.mediaDir}/library/books' 0775 ${globals.libraryOwner.user} ${globals.libraryOwner.group} - -" "d '${nixarr.mediaDir}/library/books' 0775 ${globals.libraryOwner.user} ${globals.libraryOwner.group} - -"
]; ];
systemd.services.readarr = { services.readarr = {
description = "Readarr"; enable = cfg.enable;
after = ["network.target"]; package = cfg.package;
wantedBy = ["multi-user.target"]; settings.server.port = cfg.port;
environment.READARR__SERVER__PORT = builtins.toString cfg.port; openFirewall = cfg.openFirewall;
dataDir = cfg.stateDir;
serviceConfig = { user = globals.readarr.user;
Type = "simple"; group = globals.readarr.group;
User = globals.readarr.user;
Group = globals.readarr.group;
ExecStart = "${lib.getExe cfg.package} -nobrowser -data=${cfg.stateDir}";
Restart = "on-failure";
};
}; };
networking.firewall = mkIf cfg.openFirewall { networking.firewall = mkIf cfg.openFirewall {