ytdl-web/nix/module.nix

230 lines
6.7 KiB
Nix

{ config, lib, pkgs, ... }:
let
inherit (lib.options) mkOption mkEnableOption mkPackageOption;
inherit (lib.modules) mkIf;
inherit (lib.types) str enum int path submodule nullOr bool;
cfg = config.services.ytdl-web;
in
{
options.services.ytdl-web = {
enable = mkEnableOption "ytdl-web";
package = mkPackageOption pkgs "ytdl-web" { };
user = mkOption {
type = str;
default = "ytdl-web";
description = ''
The user account ytdl-web will run under.
'';
};
group = mkOption {
type = str;
default = "ytdl-web";
description = ''
The group ytdl-web will run under.
'';
};
appEnvironment = mkOption {
type = enum [ "Development" "Staging" "Production" ];
default = "Production";
description = ''
The application environment mode.
'';
};
ytdlPackage = mkPackageOption pkgs "yt-dlp" { };
port = mkOption {
type = int;
default = 8080;
description = ''
The tcp port for the web server to listen on.
'';
};
listen = mkOption {
type = str;
default = "0.0.0.0";
example = "127.0.0.1";
description = ''
The address for the web server to listen on.
'';
};
openFirewall = mkOption {
type = bool;
default = false;
example = literalExpression "true";
description = ''
Open ports in the firewall for the ytdl-web server.
'';
};
basePath = mkOption {
type = str;
default = "/";
example = "/ytdl-web";
description = ''
The base path that the web application is hosted under.
Useful for reverse-proxies that proxy the app with a path prefix.
'';
};
cacheTTL = mkOption {
type = str;
default = "1h";
example = "2m";
description = ''
How long to keep cached metadata for.
A duration string is a possibly signed sequence of decimal numbers,
each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
'';
};
cacheDir = mkOption {
type = path;
default = "/var/cache/ytdl-web";
example = "/tmp/ytdl-web";
description = ''
The directory containing the ytdl metadata cache.
'';
};
cookies = mkOption {
type = submodule {
options = {
enable = mkEnableOption "ytdl cookies";
file = mkOption {
type = nullOr path;
default = null;
example = "/etc/ytdl-web/cookies.txt";
description = ''
The file that contains the netscape formatted cookies.
'';
};
fromBrowser = mkOption {
description = ''
Settings for obtaining cookies from a local browser's cookie storage.
'';
type = submodule {
options = {
browser = mkOption {
type = nullOr (enum [ "brave" "chrome" "chromium" "edge" "firefox" "opera" "safari" "vivaldi" ]);
default = null;
description = ''
The name of the browser to load cookies from.
'';
};
keyring = mkOption {
type = nullOr (enum [ "basictext" "gnomekeyring" "kwallet" ]);
default = null;
description = ''
The name of the keyring to use to decrypt cookies when using the chromium browser.
'';
};
profile = mkOption {
type = nullOr str;
default = null;
description = ''
The name of the browser profile to load the cookies from.
'';
};
container = mkOption {
type = nullOr str;
default = null;
description = ''
The container name to load the cookies from when using the firefox browser.
'';
};
};
};
};
};
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.cookies.file != null && cfg.cookies.fromBrowser.browser != null;
message = "The `services.ytdl-web.cookies.file` and `services.ytdl-web.cookies.fromBrowser.browser` options are mutually exclusive.";
}
{
assertion = cfg.cookies.fromBrowser.browser != null &&
!(builtins.elem cfg.cookies.fromBrowser.browser [ "brave" "chrome" "chromium" "edge" "opera" "vivaldi" ]) &&
cfg.cookies.fromBrowser.keyring != null;
message = "The `services.ytdl-web.cookies.fromBrowser.keyring` only functions with a chromium-based browser.";
}
{
assertion = cfg.cookies.fromBrowser.browser != null &&
cfg.cookies.fromBrowser.browser != "firefox" &&
cfg.cookies.fromBrowser.container != null;
message = "The `services.ytdl-web.cookies.fromBrowser.container` only functions with the firefox browser.";
}
];
systemd.services.ytdl-web = {
description = "ytdl-web";
after = [ "networking.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
YTDL_ENV = cfg.appEnvironment;
YTDL_BINARY_PATH = toString cfg.ytdlPackage;
YTDL_HTTP_PORT = toString cfg.port;
YTDL_HTTP_LISTEN = cfg.listen;
YTDL_HTTP_BASEPATH = cfg.basePath;
YTDL_CACHE_TTL = cfg.cacheTTL;
YTDL_CACHE_DIRPATH = cfg.cacheDir;
YTDL_COOKIES_ENABLED = if cfg.cookies.enable then "true" else "false";
YTDL_COOKIES_FILEPATH = cfg.cookies.file;
YTDL_COOKIES_FROMBROWSER_BROWSER = cfg.cookies.fromBrowser.browser;
YTDL_COOKIES_FROMBROWSER_KEYRING = cfg.cookies.fromBrowser.keyring;
YTDL_COOKIES_FROMBROWSER_PROFILE = cfg.cookies.fromBrowser.profile;
YTDL_COOKIES_FROMBROWSER_CONTAINER = cfg.cookies.fromBrowser.container;
};
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
ExecStart = "${lib.getExe cfg.package} serve";
Restart = "on-failure";
};
};
systemd.tmpfiles.rules = [
"d ${cfg.cacheDir} 0770 ${cfg.user} ${cfg.group} -"
];
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
users = {
users = mkIf (cfg.user == "ytdl-web") {
ytdl-web = {
isSystemUser = true;
group = cfg.group;
};
};
groups = mkIf (cfg.group == "ytdl-web") {
ytdl-web = { };
};
};
};
}