initial commit
This commit is contained in:
commit
cfff41f486
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
result
|
8
default.nix
Normal file
8
default.nix
Normal file
|
@ -0,0 +1,8 @@
|
|||
(import (let
|
||||
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
||||
in
|
||||
fetchTarball {
|
||||
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||
}) {src = ./.;})
|
||||
.defaultNix
|
78
flake.lock
Normal file
78
flake.lock
Normal file
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1693985761,
|
||||
"narHash": "sha256-K5b+7j7Tt3+AqbWkcw+wMeqOAWyCD1MH26FPZyWXpdo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0bffda19b8af722f8069d09d8b6a24594c80b352",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"utils": "utils"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1692799911,
|
||||
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
44
flake.nix
Normal file
44
flake.nix
Normal file
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
description = "Piped - A alternate frontend for YouTube";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
utils,
|
||||
...
|
||||
}:
|
||||
{
|
||||
nixosModules."piped" = import ./module/default.nix;
|
||||
nixosModules.default = self.nixosModules.piped;
|
||||
|
||||
overlay = final: prev: {
|
||||
piped-frontend = final.callPackage ./packages/frontend {};
|
||||
piped-backend = final.callPackage ./packages/backend {
|
||||
jre = final.openjdk19_headless;
|
||||
jdk = final.openjdk19;
|
||||
};
|
||||
piped-proxy = final.callPackage ./packages/proxy {};
|
||||
};
|
||||
}
|
||||
// utils.lib.eachSystem (utils.lib.defaultSystems) (system: let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [self.overlay];
|
||||
};
|
||||
in {
|
||||
packages = {
|
||||
inherit (pkgs) piped-frontend;
|
||||
inherit (pkgs) piped-backend;
|
||||
inherit (pkgs) piped-proxy;
|
||||
};
|
||||
});
|
||||
}
|
15
meta.json
Normal file
15
meta.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"frontend": {
|
||||
"rev": "caa3e83ab83c93d117fe89649b7834d46ce9d53d",
|
||||
"sha256": "sha256-nsLrSJlQBJ//qubPN1kHDlLcK7iDgJh5nMcNybFygeY="
|
||||
},
|
||||
"backend": {
|
||||
"rev": "a8e6907305a2f2f29d88e6cd07a2d392ece922af",
|
||||
"sha256": "sha256-QJPyz//CtJB5e7egrvemYh/hBjlN58QRpVb8KAJtSZ4=",
|
||||
"deps-sha256": "sha256-CS6gu7U8loktSh5xLq98vnBFWHuuv9sLYmgAZtrdP4Y="
|
||||
},
|
||||
"proxy": {
|
||||
"rev": "e642b968a8d73e8af281fa9a70a6798393670ac0",
|
||||
"sha256": "sha256-LzCsUIjOl5D96tVW9K9zng/xiYCMthpFWtV5qX5WrEo="
|
||||
}
|
||||
}
|
138
module/backend.nix
Normal file
138
module/backend.nix
Normal file
|
@ -0,0 +1,138 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.services.piped;
|
||||
|
||||
backend_config =
|
||||
{
|
||||
PORT = cfg.internalBackendPort;
|
||||
HTTP_WORKERS = cfg.httpWorkers;
|
||||
PROXY_PART = "https://${cfg.proxyDomain}";
|
||||
API_URL = "https://${cfg.backendDomain}";
|
||||
FRONTEND_URL = "https://${cfg.frontendDomain}";
|
||||
DISABLE_REGISTRATION = cfg.disableRegistrations;
|
||||
COMPROMISED_PASSWORD_CHECK = cfg.enableCompromisedPasswordCheck;
|
||||
FEED_RETENTION = cfg.feedRetentionDays;
|
||||
SUBSCRIPTIONS_EXPIRY = cfg.subscriptionRetentionDays;
|
||||
SPONSORBLOCK_SERVERS = concatStringsSep "," cfg.sponsorblockServers;
|
||||
DISABLE_RYD = cfg.disableRYD;
|
||||
DISABLE_LBRY = cfg.disableLBRYStreams;
|
||||
RYD_PROXY_URL = cfg.rydAPIURL;
|
||||
SENTRY_DSN = cfg.sentryDSN;
|
||||
"hibernate.connection.url" = "jdbc:postgresql://${cfg.postgresHost}:${toString cfg.postgresPort}/${cfg.postgresDB}";
|
||||
"hibernate.connection.driver_class" = "org.postgresql.Driver";
|
||||
"hibernate.dialect" = "org.hibernate.dialect.PostgreSQLDialect";
|
||||
"hibernate.connection.username" = "${cfg.postgresUsername}";
|
||||
"hibernate.connection.password" =
|
||||
if cfg.postgresPasswordFile == null
|
||||
then cfg.postgresPassword
|
||||
else "POSTGRES_PASSWORD";
|
||||
}
|
||||
// (optionalAttrs cfg.enableCaptcha {
|
||||
CAPTCHA_API_URL = cfg.captchaAPIURL;
|
||||
# This is substituted in the PreStart of piped-backend.service
|
||||
CAPTCHA_API_KEY =
|
||||
if cfg.captchaAPIKeyFile != ""
|
||||
then "CAPTCHA_API_KEY_FILE"
|
||||
else cfg.captchaAPIKey;
|
||||
})
|
||||
// (optionalAttrs cfg.enableFederation {
|
||||
MATRIX_SERVER = cfg.matrixServerAddr;
|
||||
# also substituted
|
||||
MATRIX_TOKEN =
|
||||
if cfg.matrixTokenFile != ""
|
||||
then "MATRIX_TOKEN_FILE"
|
||||
else cfg.matrixToken;
|
||||
});
|
||||
|
||||
cfgToString = v:
|
||||
if builtins.isBool v
|
||||
then boolToString v
|
||||
else toString v;
|
||||
backend_config_file =
|
||||
pkgs.writeText "config.properties"
|
||||
(concatStringsSep "\n"
|
||||
(mapAttrsToList (n: v: "${n}:${cfgToString v}") backend_config));
|
||||
in {
|
||||
config = lib.mkIf (cfg.enable && !cfg.disableBackend) {
|
||||
systemd.tmpfiles.rules = ["d /run/piped-backend - piped piped"];
|
||||
|
||||
systemd.services.piped-backend = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
serviceConfig = {
|
||||
WorkingDirectory = "/run/piped-backend";
|
||||
ExecStartPre = let
|
||||
confFile = "/run/piped-backend/config.properties";
|
||||
in "${pkgs.writeShellScript "piped-backend-init" ''
|
||||
[ -f "${confFile}" ] && rm ${confFile}
|
||||
cp ${backend_config_file} ${confFile}
|
||||
chmod 660 ${confFile}
|
||||
${optionalString (cfg.enableCaptcha && cfg.captchaAPIKeyFile != "") ''
|
||||
sed -i "s/CAPTCHA_API_KEY_FILE/$(cat ${cfg.captchaAPIKeyFile} | sed "s#/#\\\/#")/" ${confFile}
|
||||
''}
|
||||
${optionalString
|
||||
(cfg.enableFederation && cfg.matrixTokenFile != "") ''
|
||||
sed -i "s/MATRIX_TOKEN_FILE/$(cat ${cfg.matrixTokenFile} | sed "s#/#\\\/#")/" ${confFile}
|
||||
''}
|
||||
${optionalString
|
||||
(cfg.postgresPasswordFile != null) ''
|
||||
sed -i "s/POSTGRES_PASSWORD/$(cat ${cfg.postgresPasswordFile} | sed "s#/#\\\/#")/" ${confFile}
|
||||
''}
|
||||
''}";
|
||||
ExecStart = "${pkgs.piped-backend}/bin/piped-backend";
|
||||
|
||||
RestartSec = "5s";
|
||||
User = "piped";
|
||||
|
||||
CapabilityBoundingSet = "";
|
||||
PrivateDevices = true;
|
||||
PrivateUsers = true;
|
||||
ProtectHome = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectProc = "invisible";
|
||||
RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
|
||||
RestrictNamespaces = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = ["@system-service" "~@privileged" "~@resources"];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.piped-password = lib.mkIf (!cfg.disablePostgres) {
|
||||
serviceConfig.Type = "oneshot";
|
||||
wantedBy = ["piped-backend.service"];
|
||||
wants = ["postgresql.service"];
|
||||
after = ["postgresql.service"];
|
||||
script = ''
|
||||
${pkgs.postgresql}/bin/psql -c "ALTER USER piped WITH PASSWORD '${
|
||||
if cfg.postgresPasswordFile != null
|
||||
then "$(cat ${cfg.postgresPasswordFile} | sed \"s#'#\\\'#\")"
|
||||
else cfg.postgresPassword
|
||||
}';"
|
||||
'';
|
||||
serviceConfig.User = "postgres";
|
||||
};
|
||||
|
||||
services.postgresql = lib.mkIf (!cfg.disablePostgres) {
|
||||
enable = true;
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "piped";
|
||||
ensurePermissions."DATABASE piped" = "ALL PRIVILEGES";
|
||||
}
|
||||
];
|
||||
ensureDatabases = ["piped"];
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."${cfg.backendDomain}" = lib.mkIf (!cfg.disableNginx) {
|
||||
forceSSL = cfg.nginxForceSSL;
|
||||
enableACME = cfg.nginxEnableACME;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString cfg.internalBackendPort}";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
265
module/default.nix
Normal file
265
module/default.nix
Normal file
|
@ -0,0 +1,265 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.services.piped;
|
||||
in {
|
||||
options.services.piped = {
|
||||
enable = mkEnableOption "piped";
|
||||
|
||||
frontendDomain = mkOption {type = types.str;};
|
||||
backendDomain = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Set to null to use project default backend";
|
||||
};
|
||||
proxyDomain = mkOption {type = types.str;};
|
||||
#rydProxyDomain = mkOption { type = types.str; };
|
||||
|
||||
disableNginx = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
nginxForceSSL = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
nginxEnableACME = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
disableFrontend = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Don't host frontend";
|
||||
};
|
||||
|
||||
disableBackend = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Don't host backend";
|
||||
};
|
||||
|
||||
disableProxy = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Don't host proxy";
|
||||
};
|
||||
|
||||
disablePostgres = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Manually configure postgres instead";
|
||||
};
|
||||
|
||||
postgresHost = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Host postgres is on";
|
||||
};
|
||||
|
||||
postgresPort = mkOption {
|
||||
type = types.number;
|
||||
default = 5432;
|
||||
description = "Port postgres is on";
|
||||
};
|
||||
|
||||
postgresDB = mkOption {
|
||||
type = types.str;
|
||||
default = "piped";
|
||||
description = "Database name for piped";
|
||||
};
|
||||
|
||||
postgresUsername = mkOption {
|
||||
type = types.str;
|
||||
default = "piped";
|
||||
description = "Host postgres is on";
|
||||
};
|
||||
|
||||
postgresPassword = mkOption {
|
||||
type = types.str;
|
||||
default = "password";
|
||||
description = "Password to use for postgres";
|
||||
};
|
||||
|
||||
postgresPasswordFile = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Password file to use for postgres, loaded at runtime";
|
||||
};
|
||||
|
||||
proxyIPv4Only = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Only use IPv4 querying youtube's servers for proxy";
|
||||
};
|
||||
|
||||
proxyNginxExtraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
proxy_buffering on;
|
||||
proxy_buffers 1024 16k;
|
||||
proxy_set_header X-Forwarded-For "";
|
||||
proxy_set_header CF-Connecting-IP "";
|
||||
proxy_hide_header "alt-svc";
|
||||
sendfile on;
|
||||
sendfile_max_chunk 512k;
|
||||
tcp_nopush on;
|
||||
aio threads=default;
|
||||
aio_write on;
|
||||
directio 16m;
|
||||
proxy_hide_header Cache-Control;
|
||||
proxy_hide_header etag;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection keep-alive;
|
||||
proxy_max_temp_file_size 32m;
|
||||
access_log off;
|
||||
'';
|
||||
description = "Extra config for nginx on piped-proxy";
|
||||
};
|
||||
|
||||
httpWorkers = mkOption {
|
||||
type = types.number;
|
||||
default = 2;
|
||||
description = "Number of workers for HTTP backend tasks";
|
||||
};
|
||||
|
||||
feedRetentionDays = mkOption {
|
||||
type = types.number;
|
||||
default = 30;
|
||||
description = "Days feed is stored for";
|
||||
};
|
||||
|
||||
subscriptionRetentionDays = mkOption {
|
||||
type = types.number;
|
||||
default = 30;
|
||||
description = "Days subscriptions are stored for unauthenticated users";
|
||||
};
|
||||
|
||||
sponsorblockServers = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = ["https://sponsor.ajay.app" "https://sponsorblock.kavin.rocks"];
|
||||
description = "Days subscriptions are stored for unauthenticated users";
|
||||
};
|
||||
|
||||
disableRegistrations = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Disable user registrations";
|
||||
};
|
||||
|
||||
disableLBRYStreams = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Disable showing streams provided by LBRY Youtube Partnership";
|
||||
};
|
||||
|
||||
enableCompromisedPasswordCheck = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Use the haveibeenpwned API to check if user password have been compromised";
|
||||
};
|
||||
|
||||
enableCaptcha = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable captcha for registrations";
|
||||
};
|
||||
|
||||
sentryDSN = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Public DSN for sentry error reporting";
|
||||
};
|
||||
|
||||
captchaAPIURL = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "API URL for Captcha";
|
||||
};
|
||||
|
||||
# TODO: Key & KeyFile should be only one or the other used
|
||||
|
||||
captchaAPIKey = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "API Key for Captcha";
|
||||
};
|
||||
|
||||
captchaAPIKeyFile = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "API Key File for Captcha";
|
||||
};
|
||||
|
||||
# TODO: run this, requires a go app and Tor server for proxy
|
||||
#enableRYDServer = mkOption {
|
||||
# type = types.bool;
|
||||
# default = true;
|
||||
# description = "Run a RYD Proxy Server to use";
|
||||
#};
|
||||
|
||||
disableRYD = mkOption {
|
||||
type = types.bool;
|
||||
#default = if cfg.enableRYDServer then false else true;
|
||||
default = false;
|
||||
description = "Disables querying a Return YouTube Dislike server";
|
||||
};
|
||||
|
||||
rydAPIURL = mkOption {
|
||||
type = types.str;
|
||||
#default = if cfg.enableRYDServer then cfg.rydProxyDomain else "https://ryd-proxy.kavin.rocks";
|
||||
default = "https://ryd-proxy.kavin.rocks";
|
||||
description = "API URL for a Return YouTube Dislike server";
|
||||
};
|
||||
|
||||
# for Piped's Federation Shenanigan
|
||||
# https://github.com/TeamPiped/piped-federation#how-to-join
|
||||
enableFederation = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable federation of something";
|
||||
};
|
||||
|
||||
matrixServerAddr = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Matrix server address for federation";
|
||||
};
|
||||
|
||||
# TODO: make so only one of these options can be used
|
||||
matrixToken = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Matrix access token";
|
||||
};
|
||||
|
||||
matrixTokenFile = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Matrix access token file";
|
||||
};
|
||||
|
||||
internalBackendPort = mkOption {
|
||||
type = types.number;
|
||||
default = 3001;
|
||||
};
|
||||
|
||||
internalProxyPort = mkOption {
|
||||
type = types.number;
|
||||
default = 3002;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.enable && (!cfg.disableBackend || !cfg.disableProxy)) {
|
||||
users.users."piped" = {
|
||||
isSystemUser = true;
|
||||
group = "piped";
|
||||
};
|
||||
users.groups.piped = {};
|
||||
};
|
||||
}
|
27
module/frontend.nix
Normal file
27
module/frontend.nix
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.services.piped;
|
||||
frontend-package =
|
||||
pkgs.piped-frontend.override {backendDomain = cfg.backendDomain;};
|
||||
in {
|
||||
config = mkIf (cfg.enable && !cfg.disableFrontend && !cfg.disableNginx) {
|
||||
# https://github.com/TeamPiped/Piped/blob/master/docker/nginx.conf
|
||||
services.nginx.virtualHosts."${cfg.frontendDomain}" = {
|
||||
forceSSL = cfg.nginxForceSSL;
|
||||
enableACME = cfg.nginxEnableACME;
|
||||
locations."/" = {
|
||||
root = "${frontend-package}/share/piped-frontend";
|
||||
index = "index.html index.htm";
|
||||
};
|
||||
# I have no idea why try_files for Single Page Apps doesn't work here
|
||||
extraConfig = ''
|
||||
error_page 404 =200 /index.html;
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
11
module/nginx.nix
Normal file
11
module/nginx.nix
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
cfg = config.services.piped;
|
||||
in {
|
||||
config = lib.mkIf (cfg.enable && !cfg.disableNginx) {
|
||||
services.nginx.enable = true;
|
||||
};
|
||||
}
|
55
module/proxy.nix
Normal file
55
module/proxy.nix
Normal file
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.services.piped;
|
||||
in {
|
||||
config = mkIf (cfg.enable && !cfg.disableProxy) {
|
||||
systemd.services.piped-proxy = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
environment.BIND = "0.0.0.0:${toString cfg.internalProxyPort}";
|
||||
environment.IPV4_ONLY = mkIf cfg.proxyIPv4Only "1";
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.piped-proxy}/bin/piped-proxy";
|
||||
|
||||
RestartSec = "5s";
|
||||
User = "piped";
|
||||
|
||||
CapabilityBoundingSet = "";
|
||||
PrivateDevices = true;
|
||||
PrivateUsers = true;
|
||||
ProtectHome = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectProc = "invisible";
|
||||
RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
|
||||
RestrictNamespaces = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = ["@system-service" "~@privileged" "~@resources"];
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."${cfg.proxyDomain}" = lib.mkIf (!cfg.disableNginx) {
|
||||
forceSSL = cfg.nginxForceSSL;
|
||||
enableACME = cfg.nginxEnableACME;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:${toString cfg.internalProxyPort}";
|
||||
extraConfig =
|
||||
cfg.proxyNginxExtraConfig
|
||||
+ ''
|
||||
add_header Cache-Control "public, max-age=604800";
|
||||
'';
|
||||
};
|
||||
locations."~ (/videoplayback|/api/v4/|/api/manifest/)" = {
|
||||
proxyPass = "http://localhost:${toString cfg.internalProxyPort}";
|
||||
extraConfig =
|
||||
cfg.proxyNginxExtraConfig
|
||||
+ ''
|
||||
add_header Cache-Control private always;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
84
packages/backend/default.nix
Normal file
84
packages/backend/default.nix
Normal file
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
stdenv,
|
||||
runtimeShell,
|
||||
fetchFromGitHub,
|
||||
jdk,
|
||||
jre,
|
||||
gradle,
|
||||
perl,
|
||||
writeText,
|
||||
callPackage,
|
||||
}: let
|
||||
meta = builtins.fromJSON (builtins.readFile ../../meta.json);
|
||||
|
||||
deps =
|
||||
callPackage ./deps.nix {inherit stdenv fetchFromGitHub jdk gradle perl;};
|
||||
|
||||
gradleInit = writeText "init.gradle" ''
|
||||
logger.lifecycle 'Replacing Maven repositories with ${deps}...'
|
||||
gradle.projectsLoaded {
|
||||
rootProject.allprojects {
|
||||
buildscript {
|
||||
repositories {
|
||||
clear()
|
||||
maven { url '${deps}' }
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
clear()
|
||||
maven { url '${deps}' }
|
||||
}
|
||||
}
|
||||
}
|
||||
settingsEvaluated { settings ->
|
||||
settings.pluginManagement {
|
||||
repositories {
|
||||
maven { url '${deps}' }
|
||||
}
|
||||
}
|
||||
}
|
||||
'';
|
||||
in
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "piped-backend";
|
||||
version = "latest-${meta.backend.rev}";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "TeamPiped";
|
||||
repo = "Piped-Backend";
|
||||
rev = "${meta.backend.rev}";
|
||||
sha256 = "${meta.backend.sha256}";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [gradle jdk];
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
export JAVA_HOME=${jdk}
|
||||
export GRADLE_USER_HOME=$(mktemp -d)
|
||||
|
||||
gradle -P org.gradle.java.installations.fromEnv=JAVA_HOME --offline --init-script ${gradleInit} shadowJar
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
ls -R build
|
||||
|
||||
mkdir -p "$out/share/piped-backend"
|
||||
cp build/libs/piped-1.0-all.jar "$out/share/piped-backend"
|
||||
|
||||
mkdir -p "$out/bin"
|
||||
cat <<EOF >$out/bin/piped-backend
|
||||
#!${runtimeShell}
|
||||
export JAVA_HOME=${jre}
|
||||
exec ${jre}/bin/java -jar "$out/share/piped-backend/piped-1.0-all.jar" "\$@"
|
||||
EOF
|
||||
chmod a+x "$out/bin/piped-backend"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
60
packages/backend/deps.nix
Normal file
60
packages/backend/deps.nix
Normal file
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
fetchurl,
|
||||
gradle,
|
||||
jdk,
|
||||
perl,
|
||||
}: let
|
||||
meta = builtins.fromJSON (builtins.readFile ../../meta.json);
|
||||
|
||||
extraDeps = [
|
||||
{
|
||||
filename = "okio-3.2.0.jar";
|
||||
path = "com/squareup/okio/okio/3.2.0";
|
||||
url = "https://repo1.maven.org/maven2/com/squareup/okio/okio/3.2.0/okio-3.2.0.jar";
|
||||
sha256 = "sha256-3KkyyyAptsniZ3D4fbCLFNSB/+gTGlnzaaI4XBG+Ti0=";
|
||||
}
|
||||
];
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "piped-backend-deps";
|
||||
version = "latest-${meta.backend.rev}";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "TeamPiped";
|
||||
repo = "Piped-Backend";
|
||||
rev = "${meta.backend.rev}";
|
||||
sha256 = "${meta.backend.sha256}";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [gradle jdk perl];
|
||||
|
||||
buildPhase = ''
|
||||
export JAVA_HOME=${jdk}
|
||||
export GRADLE_USER_HOME=$(mktemp -d);
|
||||
gradle -P org.gradle.java.installations.fromEnv=JAVA_HOME --no-daemon assemble shadowJar
|
||||
'';
|
||||
|
||||
# perl code mavenizes paths (com.squareup.okio/okio/1.13.0/a9283170b7305c8d92d25aff02a6ab7e45d06cbe/okio-1.13.0.jar -> com/squareup/okio/okio/1.13.0/okio-1.13.0.jar)
|
||||
installPhase =
|
||||
''
|
||||
find $GRADLE_USER_HOME/caches/modules-2 -type f -regex '.*\.\(jar\|pom\)' \
|
||||
| perl -pe 's#(.*/([^/]+)/([^/]+)/([^/]+)/[0-9a-f]{30,40}/([^/\s]+))$# ($x = $2) =~ tr|\.|/|; "install -Dm444 $1 \$out/$x/$3/$4/$5" #e' \
|
||||
| sh
|
||||
''
|
||||
+ lib.concatStringsSep "\n" (lib.forEach extraDeps (dep: ''
|
||||
mkdir -p $out/${dep.path}
|
||||
cp ${fetchurl {
|
||||
url = dep.url;
|
||||
sha256 = dep.sha256;
|
||||
}} $out/${dep.path}/${dep.filename}
|
||||
''));
|
||||
|
||||
dontStrip = true;
|
||||
|
||||
outputHashAlgo = "sha256";
|
||||
outputHashMode = "recursive";
|
||||
outputHash = "${meta.backend.deps-sha256}";
|
||||
}
|
53
packages/frontend/default.nix
Normal file
53
packages/frontend/default.nix
Normal file
|
@ -0,0 +1,53 @@
|
|||
{
|
||||
mkYarnPackage,
|
||||
rsync,
|
||||
fetchFromGitHub,
|
||||
# Backend domain override, if unset then use project default
|
||||
backendDomain ? null,
|
||||
}: let
|
||||
meta = builtins.fromJSON (builtins.readFile ../../meta.json);
|
||||
rev = meta.frontend.rev;
|
||||
in
|
||||
mkYarnPackage rec {
|
||||
pname = "piped-frontend";
|
||||
version = "latest-${rev}";
|
||||
src = fetchFromGitHub {
|
||||
owner = "TeamPiped";
|
||||
repo = "Piped";
|
||||
inherit rev;
|
||||
sha256 = "${meta.frontend.sha256}";
|
||||
};
|
||||
|
||||
packageJSON = "${src}/package.json";
|
||||
yarnLock = ./yarn.lock;
|
||||
yarnNix = ./yarn.nix;
|
||||
|
||||
patchPhase = ''
|
||||
${
|
||||
if backendDomain != null
|
||||
then ''
|
||||
sed -i "s#pipedapi.kavin.rocks#${backendDomain}#g" src/main.js
|
||||
sed -i "s#pipedapi.kavin.rocks#${backendDomain}#g" src/components/PreferencesPage.vue
|
||||
''
|
||||
else ""
|
||||
}
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
cp ${./yarn.lock} yarn.lock
|
||||
yarn --offline build
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p "$out/share/piped-frontend"
|
||||
${rsync}/bin/rsync --recursive deps/piped/dist/ "$out/share/piped-frontend"
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
doDist = false;
|
||||
}
|
4887
packages/frontend/yarn.lock
Normal file
4887
packages/frontend/yarn.lock
Normal file
File diff suppressed because it is too large
Load diff
5315
packages/frontend/yarn.nix
Normal file
5315
packages/frontend/yarn.nix
Normal file
File diff suppressed because it is too large
Load diff
20
packages/proxy/default.nix
Normal file
20
packages/proxy/default.nix
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
rustPlatform,
|
||||
fetchFromGitHub,
|
||||
}: let
|
||||
meta = builtins.fromJSON (builtins.readFile ../../meta.json);
|
||||
rev = meta.proxy.rev;
|
||||
in
|
||||
rustPlatform.buildRustPackage rec {
|
||||
pname = "piped-proxy";
|
||||
version = "latest-${rev}";
|
||||
src = fetchFromGitHub {
|
||||
owner = "TeamPiped";
|
||||
repo = "piped-proxy";
|
||||
inherit rev;
|
||||
sha256 = "${meta.proxy.sha256}";
|
||||
};
|
||||
|
||||
cargoLock = {lockFile = "${src}/Cargo.lock";};
|
||||
doCheck = false;
|
||||
}
|
63
update.sh
Executable file
63
update.sh
Executable file
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p curl jq git moreutils nodejs_20 yarn2nix yarn nix
|
||||
set -euo pipefail
|
||||
|
||||
BASE_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd "${BASE_DIR}"
|
||||
|
||||
json_get() {
|
||||
jq -r "$1" < 'meta.json'
|
||||
}
|
||||
|
||||
json_set() {
|
||||
jq --arg x "$2" "$1 = \$x" < 'meta.json' | sponge 'meta.json'
|
||||
}
|
||||
|
||||
# Frontend
|
||||
old_frontend_rev=$(json_get '.frontend.rev')
|
||||
new_frontend_rev=$(curl -L "https://api.github.com/repos/TeamPiped/Piped/commits" 2>/dev/null | jq ".[0].sha" -r)
|
||||
if [ "$new_frontend_rev" != "$old_frontend_rev" ] || [ "${FORCE_UPDATE-}" != "" ]; then
|
||||
echo "Frontend is out of date. Updating..."
|
||||
json_set '.frontend.rev' "$new_frontend_rev"
|
||||
json_set '.frontend.sha256' ""
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
pushd "$TMP"
|
||||
git clone https://github.com/TeamPiped/Piped
|
||||
pushd Piped
|
||||
git reset --hard "$new_frontend_rev"
|
||||
#yarn install --no-lockfile
|
||||
yarn install --mode update-lockfile
|
||||
nix run "github:NixOS/nixpkgs/nixos-unstable#yarn2nix" > "${BASE_DIR}/packages/frontend/yarn.nix"
|
||||
cp yarn.lock "${BASE_DIR}/packages/frontend/yarn.lock"
|
||||
popd
|
||||
popd
|
||||
rm -rf "$TMP"
|
||||
fi
|
||||
|
||||
# Backend
|
||||
old_backend_rev=$(json_get '.backend.rev')
|
||||
new_backend_rev=$(curl -L "https://api.github.com/repos/TeamPiped/Piped-Backend/commits" 2>/dev/null | jq ".[0].sha" -r)
|
||||
if [ "$new_backend_rev" != "$old_backend_rev" ] || [ "${FORCE_UPDATE-}" != "" ]; then
|
||||
echo "Backend is out of date. Updating..."
|
||||
json_set '.backend.rev' "$new_backend_rev"
|
||||
json_set '.backend.sha256' ""
|
||||
json_set '.backend."deps-sha256"' ""
|
||||
fi
|
||||
|
||||
# Proxy
|
||||
old_proxy_rev=$(json_get '.proxy.rev')
|
||||
new_proxy_rev=$(curl -L "https://api.github.com/repos/TeamPiped/piped-proxy/commits" 2>/dev/null | jq ".[0].sha" -r)
|
||||
if [ "$new_proxy_rev" != "$old_proxy_rev" ] || [ "${FORCE_UPDATE-}" != "" ]; then
|
||||
echo "Proxy is out of date. Updating..."
|
||||
json_set '.proxy.rev' "$new_proxy_rev"
|
||||
json_set '.proxy.sha256' ""
|
||||
fi
|
||||
|
||||
# gotta manually update shasums using output from these
|
||||
echo "building frontend"
|
||||
nix build .#piped-frontend || true
|
||||
|
||||
echo "building backend"
|
||||
nix build .#piped-backend || true
|
||||
|
Loading…
Reference in a new issue