pinchflat: init at 2025.3.17, nixos/pinchflat: init (#364135)
This commit is contained in:
@@ -4188,6 +4188,12 @@
|
||||
githubId = 1774239;
|
||||
name = "Charlie Egan";
|
||||
};
|
||||
charludo = {
|
||||
email = "github@charlotteharludo.com";
|
||||
github = "charludo";
|
||||
githubId = 47758554;
|
||||
name = "Charlotte Harludo";
|
||||
};
|
||||
chayleaf = {
|
||||
email = "chayleaf-nix@pavluk.org";
|
||||
github = "chayleaf";
|
||||
|
||||
@@ -116,6 +116,8 @@
|
||||
|
||||
- [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).
|
||||
|
||||
- [Fluent Bit](https://github.com/fluent/fluent-bit), a fast Log, Metrics and Traces Processor and Forwarder. Available as [services.fluent-bit](#opt-services.fluent-bit.enable).
|
||||
|
||||
@@ -859,6 +859,7 @@
|
||||
./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
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
{
|
||||
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 ];
|
||||
};
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
{
|
||||
lib,
|
||||
fetchFromGitHub,
|
||||
fetchYarnDeps,
|
||||
beamPackages,
|
||||
yarn,
|
||||
nodejs,
|
||||
esbuild,
|
||||
tailwindcss,
|
||||
fixup-yarn-lock,
|
||||
apprise,
|
||||
yt-dlp,
|
||||
}:
|
||||
beamPackages.mixRelease rec {
|
||||
pname = "pinchflat";
|
||||
version = "2025.3.17";
|
||||
src = fetchFromGitHub {
|
||||
owner = "kieraneglin";
|
||||
repo = "pinchflat";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-XHYCYC3SEVyheBV6diE2pn1AJARml+aNNUjJw2tVKTk=";
|
||||
};
|
||||
|
||||
mixNixDeps = import ./mix.nix {
|
||||
inherit beamPackages lib;
|
||||
};
|
||||
removeCookie = false;
|
||||
|
||||
yarnOfflineCache = fetchYarnDeps {
|
||||
yarnLock = "${src}/assets/yarn.lock";
|
||||
sha256 = "sha256-xJL+qcohtu+OmZ31E1QU9uqBWAFGejKIO3XRd+R6z/4=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
fixup-yarn-lock
|
||||
tailwindcss
|
||||
yarn
|
||||
];
|
||||
buildInputs = [ nodejs ];
|
||||
|
||||
postBuild = ''
|
||||
export HOME=$PWD
|
||||
fixup-yarn-lock ~/assets/yarn.lock
|
||||
yarn --cwd assets config --offline set yarn-offline-mirror $yarnOfflineCache
|
||||
yarn --cwd assets install --offline --frozen-lockfile --ignore-engines --ignore-scripts --no-progress
|
||||
patchShebangs ~/assets/node_modules
|
||||
|
||||
# phoenixframework expects platform-specific tailwind/esbuild binaries in a specific location:
|
||||
# https://github.com/phoenixframework/tailwind/blob/194ab0f979782e4ccf2fe796042bf8e20967df93/lib/tailwind.ex#L243-L251
|
||||
targets="linux-x64 linux-arm64 macos-x64 macos-arm64"
|
||||
for target in $targets; do
|
||||
ln -s "${tailwindcss}/bin/tailwindcss" "_build/tailwind-$target"
|
||||
ln -s "${esbuild}/bin/esbuild" "_build/esbuild-$target"
|
||||
done
|
||||
|
||||
mix do deps.loadpaths --no-deps-check, tailwind default --minify + esbuild default --minify + phx.digest
|
||||
'';
|
||||
postInstall = ''
|
||||
wrapProgram $out/bin/pinchflat --prefix PATH : ${
|
||||
lib.makeBinPath [
|
||||
apprise
|
||||
yt-dlp
|
||||
]
|
||||
}
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "Your next YouTube media manager";
|
||||
homepage = "https://github.com/kieraneglin/pinchflat";
|
||||
license = lib.licenses.agpl3Only;
|
||||
maintainers = with lib.maintainers; [ charludo ];
|
||||
platforms = lib.platforms.unix;
|
||||
mainProgram = "pinchflat";
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user