nixos/pinchflat: init

charludo 3e3b7747 0f505a0c

Changed files
+161
nixos
doc
manual
release-notes
modules
+2
nixos/doc/manual/release-notes/rl-2505.section.md
···
- [zwave-js-ui](https://zwave-js.github.io/zwave-js-ui/), a full featured Z-Wave Control Panel and MQTT Gateway. Available as [services.zwave-js-ui](#opt-services.zwave-js-ui.enable).
+
- [Pinchflat](https://github.com/kieraneglin/pinchflat), a selfhosted YouTube media manager used to track channels and download videos on release. Available as [services.pinchflat](#opt-services.pinchflat.enable).
+
- [Amazon CloudWatch Agent](https://github.com/aws/amazon-cloudwatch-agent), the official telemetry collector for AWS CloudWatch and AWS X-Ray. Available as [services.amazon-cloudwatch-agent](options.html#opt-services.amazon-cloudwatch-agent.enable).
- [Bat](https://github.com/sharkdp/bat), a {manpage}`cat(1)` clone with wings. Available as [programs.bat](options.html#opt-programs.bat).
+1
nixos/modules/module-list.nix
···
./services/misc/parsoid.nix
./services/misc/persistent-evdev.nix
./services/misc/pghero.nix
+
./services/misc/pinchflat.nix
./services/misc/pinnwand.nix
./services/misc/plex.nix
./services/misc/plikd.nix
+158
nixos/modules/services/misc/pinchflat.nix
···
+
{
+
config,
+
pkgs,
+
lib,
+
...
+
}:
+
+
let
+
cfg = config.services.pinchflat;
+
inherit (lib)
+
mkEnableOption
+
mkPackageOption
+
mkOption
+
types
+
mkIf
+
getExe
+
literalExpression
+
optional
+
attrValues
+
mapAttrs
+
;
+
+
stateDir = "/var/lib/pinchflat";
+
in
+
{
+
options = {
+
services.pinchflat = {
+
enable = mkEnableOption "pinchflat";
+
+
mediaDir = mkOption {
+
type = types.path;
+
default = "${stateDir}/media";
+
description = "The directory into which Pinchflat downloads videos.";
+
};
+
+
port = mkOption {
+
type = types.port;
+
default = 8945;
+
description = "Port on which the Pinchflat web interface is available.";
+
};
+
+
openFirewall = mkOption {
+
type = types.bool;
+
default = false;
+
description = "Open ports in the firewall for the Pinchflat web interface";
+
};
+
+
selfhosted = mkOption {
+
type = types.bool;
+
default = false;
+
description = "Use a weak secret. If true, you are not required to provide a {env}`SECRET_KEY_BASE` through the `secretsFile` option. Do not use this option in production!";
+
};
+
+
logLevel = mkOption {
+
type = types.enum [
+
"debug"
+
"info"
+
"warning"
+
"error"
+
];
+
default = "info";
+
description = "Log level for Pinchflat.";
+
};
+
+
extraConfig = mkOption {
+
type =
+
with types;
+
attrsOf (
+
nullOr (oneOf [
+
bool
+
int
+
str
+
])
+
);
+
default = { };
+
example = literalExpression ''
+
{
+
YT_DLP_WORKER_CONCURRENCY = 1;
+
}
+
'';
+
description = ''
+
The configuration of Pinchflat is handled through environment variables.
+
The available configuration options can be found in [the Pinchflat README](https://github.com/kieraneglin/pinchflat/README.md#environment-variables).
+
'';
+
};
+
+
secretsFile = mkOption {
+
type = with types; nullOr path;
+
default = null;
+
example = "/run/secrets/pinchflat";
+
description = ''
+
Secrets like {env}`SECRET_KEY_BASE` and {env}`BASIC_AUTH_PASSWORD`
+
should be passed to the service without adding them to the world-readable Nix store.
+
+
Note that either this file needs to be available on the host on which `pinchflat` is running,
+
or the option `selfhosted` must be `true`.
+
Further, {env}`SECRET_KEY_BASE` has a minimum length requirement of 64 bytes.
+
One way to generate such a secret is to use `openssl rand -hex 64`.
+
+
As an example, the contents of the file might look like this:
+
```
+
SECRET_KEY_BASE=...copy-paste a secret token here...
+
BASIC_AUTH_USERNAME=...basic auth username...
+
BASIC_AUTH_PASSWORD=...basic auth password...
+
```
+
'';
+
};
+
+
package = mkPackageOption pkgs "pinchflat" { };
+
};
+
};
+
+
config = mkIf cfg.enable {
+
assertions = [
+
{
+
assertion = cfg.selfhosted || !builtins.isNull cfg.secretsFile;
+
message = "Either `selfhosted` must be true, or a `secretsFile` must be configured.";
+
}
+
];
+
+
systemd.services.pinchflat = {
+
description = "pinchflat";
+
after = [ "network.target" ];
+
wantedBy = [ "multi-user.target" ];
+
+
serviceConfig = {
+
Type = "simple";
+
DynamicUser = true;
+
StateDirectory = baseNameOf stateDir;
+
Environment =
+
[
+
"PORT=${builtins.toString cfg.port}"
+
"TZ=${config.time.timeZone}"
+
"MEDIA_PATH=${cfg.mediaDir}"
+
"CONFIG_PATH=${stateDir}"
+
"DATABASE_PATH=${stateDir}/db/pinchflat.db"
+
"LOG_PATH=${stateDir}/logs/pinchflat.log"
+
"METADATA_PATH=${stateDir}/metadata"
+
"EXTRAS_PATH=${stateDir}/extras"
+
"TMPFILE_PATH=${stateDir}/tmp"
+
"TZ_DATA_PATH=${stateDir}/extras/elixir_tz_data"
+
"LOG_LEVEL=${cfg.logLevel}"
+
"PHX_SERVER=true"
+
]
+
++ optional cfg.selfhosted [ "RUN_CONTEXT=selfhosted" ]
+
++ attrValues (mapAttrs (name: value: name + "=" + builtins.toString value) cfg.extraConfig);
+
EnvironmentFile = optional (cfg.secretsFile != null) cfg.secretsFile;
+
ExecStartPre = "${lib.getExe' cfg.package "migrate"}";
+
ExecStart = "${getExe cfg.package} start";
+
Restart = "on-failure";
+
};
+
};
+
+
networking.firewall = mkIf cfg.openFirewall {
+
allowedTCPPorts = [ cfg.port ];
+
};
+
};
+
}