537 lines
17 KiB
Diff
537 lines
17 KiB
Diff
From 9d7860c7e7830d9bf82733cecd443ff167dc2174 Mon Sep 17 00:00:00 2001
|
|
From: Alexander Tomokhov <alexoundos@gmail.com>
|
|
Date: Thu, 14 Sep 2023 02:19:40 +0400
|
|
Subject: [PATCH 1/4] maintainers: add alexoundos
|
|
|
|
---
|
|
maintainers/maintainer-list.nix | 6 ++++++
|
|
1 file changed, 6 insertions(+)
|
|
|
|
diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
|
|
index e54123ac9e4907..bc28b303afaad5 100644
|
|
--- a/maintainers/maintainer-list.nix
|
|
+++ b/maintainers/maintainer-list.nix
|
|
@@ -759,6 +759,12 @@
|
|
github = "Alexnortung";
|
|
githubId = 1552267;
|
|
};
|
|
+ alexoundos = {
|
|
+ email = "alexoundos@gmail.com";
|
|
+ github = "AleXoundOS";
|
|
+ githubId = 464913;
|
|
+ name = "Alexander Tomokhov";
|
|
+ };
|
|
alexshpilkin = {
|
|
email = "ashpilkin@gmail.com";
|
|
github = "alexshpilkin";
|
|
|
|
From 17f036f4fbdd1024ebc91ff58686b9b8ce62990b Mon Sep 17 00:00:00 2001
|
|
From: misuzu <bakalolka@gmail.com>
|
|
Date: Mon, 13 Mar 2023 20:53:59 +0200
|
|
Subject: [PATCH 2/4] castopod: init at 1.6.4
|
|
|
|
---
|
|
pkgs/applications/audio/castopod/default.nix | 51 +++++++++++
|
|
pkgs/applications/audio/castopod/update.sh | 89 ++++++++++++++++++++
|
|
pkgs/top-level/all-packages.nix | 2 +
|
|
3 files changed, 142 insertions(+)
|
|
create mode 100644 pkgs/applications/audio/castopod/default.nix
|
|
create mode 100755 pkgs/applications/audio/castopod/update.sh
|
|
|
|
diff --git a/pkgs/applications/audio/castopod/default.nix b/pkgs/applications/audio/castopod/default.nix
|
|
new file mode 100644
|
|
index 00000000000000..e4cdb6025f313f
|
|
--- /dev/null
|
|
+++ b/pkgs/applications/audio/castopod/default.nix
|
|
@@ -0,0 +1,55 @@
|
|
+{ stdenv
|
|
+, fetchurl
|
|
+, ffmpeg-headless
|
|
+, lib
|
|
+, stateDirectory ? "/var/lib/castopod"
|
|
+}:
|
|
+stdenv.mkDerivation {
|
|
+ pname = "castopod";
|
|
+ version = "1.6.5";
|
|
+
|
|
+ src = fetchurl {
|
|
+ url = "https://code.castopod.org/adaures/castopod/uploads/5aaaa6cf2edaed25bd7253449e5f8584/castopod-1.6.5.tar.gz";
|
|
+ sha256 = "04gcq2vmfy5aa2fmsm1qqv1k8g024nikmysdrhy33wj460d529b5";
|
|
+ };
|
|
+
|
|
+ dontBuild = true;
|
|
+ dontFixup = true;
|
|
+
|
|
+ postPatch = ''
|
|
+ # not configurable at runtime unfortunately:
|
|
+ substituteInPlace app/Config/Paths.php \
|
|
+ --replace "__DIR__ . '/../../writable'" "'${stateDirectory}/writable'"
|
|
+
|
|
+ substituteInPlace modules/Admin/Controllers/DashboardController.php \
|
|
+ --replace "disk_total_space('./')" "disk_total_space('${stateDirectory}')"
|
|
+
|
|
+ # configuration file must be writable, place it to ${stateDirectory}
|
|
+ substituteInPlace modules/Install/Controllers/InstallController.php \
|
|
+ --replace "ROOTPATH" "'${stateDirectory}/'"
|
|
+ substituteInPlace public/index.php spark \
|
|
+ --replace "DotEnv(ROOTPATH)" "DotEnv('${stateDirectory}')"
|
|
+
|
|
+ # ffmpeg is required for Video Clips feature
|
|
+ substituteInPlace modules/MediaClipper/VideoClipper.php \
|
|
+ --replace "ffmpeg" "${ffmpeg-headless}/bin/ffmpeg"
|
|
+ substituteInPlace modules/Admin/Controllers/VideoClipsController.php \
|
|
+ --replace "which ffmpeg" "echo ${ffmpeg-headless}/bin/ffmpeg"
|
|
+ '';
|
|
+
|
|
+ installPhase = ''
|
|
+ mkdir -p $out/share/castopod
|
|
+ cp -r . $out/share/castopod
|
|
+ '';
|
|
+
|
|
+ passthru.stateDirectory = stateDirectory;
|
|
+ passthru.updateScript = ./update.sh;
|
|
+
|
|
+ meta = with lib; {
|
|
+ description = "An open-source hosting platform made for podcasters who want to engage and interact with their audience";
|
|
+ homepage = "https://castopod.org";
|
|
+ license = licenses.agpl3Only;
|
|
+ maintainers = with maintainers; [ alexoundos misuzu ];
|
|
+ platforms = platforms.all;
|
|
+ };
|
|
+}
|
|
diff --git a/pkgs/applications/audio/castopod/update.sh b/pkgs/applications/audio/castopod/update.sh
|
|
new file mode 100755
|
|
index 00000000000000..742788dc8ddfdd
|
|
--- /dev/null
|
|
+++ b/pkgs/applications/audio/castopod/update.sh
|
|
@@ -0,0 +1,89 @@
|
|
+#! /usr/bin/env nix-shell
|
|
+#! nix-shell -i bash -p curl jq
|
|
+set -euo pipefail
|
|
+
|
|
+nixpkgs="$(git rev-parse --show-toplevel)"
|
|
+castopod_nix="$nixpkgs/pkgs/applications/audio/castopod/default.nix"
|
|
+
|
|
+# https://www.meetup.com/api/guide/#p02-querying-section
|
|
+query='
|
|
+query allReleases($fullPath: ID!, $first: Int, $last: Int, $before: String, $after: String, $sort: ReleaseSort) {
|
|
+ project(fullPath: $fullPath) {
|
|
+ id
|
|
+ releases(
|
|
+ first: $first
|
|
+ last: $last
|
|
+ before: $before
|
|
+ after: $after
|
|
+ sort: $sort
|
|
+ ) {
|
|
+ nodes {
|
|
+ ...Release
|
|
+ __typename
|
|
+ }
|
|
+ __typename
|
|
+ }
|
|
+ __typename
|
|
+ }
|
|
+}
|
|
+
|
|
+fragment Release on Release {
|
|
+ id
|
|
+ name
|
|
+ tagName
|
|
+ releasedAt
|
|
+ createdAt
|
|
+ upcomingRelease
|
|
+ historicalRelease
|
|
+ assets {
|
|
+ links {
|
|
+ nodes {
|
|
+ id
|
|
+ name
|
|
+ url
|
|
+ directAssetUrl
|
|
+ linkType
|
|
+ __typename
|
|
+ }
|
|
+ __typename
|
|
+ }
|
|
+ __typename
|
|
+ }
|
|
+ __typename
|
|
+}
|
|
+'
|
|
+variables='{
|
|
+ "fullPath": "adaures/castopod",
|
|
+ "first": 1,
|
|
+ "sort": "RELEASED_AT_DESC"
|
|
+}'
|
|
+
|
|
+post=$(cat <<EOF
|
|
+{"query": "$(echo $query)", "variables": $(echo $variables)}
|
|
+EOF
|
|
+)
|
|
+
|
|
+json="$(curl -s -X POST https://code.castopod.org/api/graphql \
|
|
+ -H 'Content-Type: application/json' \
|
|
+ -d "$post")"
|
|
+
|
|
+echo "$json"
|
|
+TAG=$(echo $json | jq -r '.data.project.releases.nodes[].tagName')
|
|
+ASSET_URL=$(echo $json | jq -r '.data.project.releases.nodes[].assets.links.nodes[].url' | grep .tar.gz$)
|
|
+
|
|
+CURRENT_VERSION=$(nix eval -f "$nixpkgs" --raw castopod.version)
|
|
+VERSION=${TAG:1}
|
|
+
|
|
+if [[ "$CURRENT_VERSION" == "$VERSION" ]]; then
|
|
+ echo "castopod is up-to-date: ${CURRENT_VERSION}"
|
|
+ exit 0
|
|
+fi
|
|
+
|
|
+SHA256=$(nix-prefetch-url "$ASSET_URL")
|
|
+
|
|
+URL=$(echo $ASSET_URL | sed -e 's/[\/&]/\\&/g')
|
|
+
|
|
+sed -e "s/version =.*;/version = \"$VERSION\";/g" \
|
|
+ -e "s/url =.*;/url = \"$URL\";/g" \
|
|
+ -e "s/sha256 =.*;/sha256 = \"$SHA256\";/g" \
|
|
+ -i "$castopod_nix"
|
|
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
|
|
index 57e94596b541d1..fbdcbbfe318cea 100644
|
|
--- a/pkgs/top-level/all-packages.nix
|
|
+++ b/pkgs/top-level/all-packages.nix
|
|
@@ -3583,6 +3583,8 @@ with pkgs;
|
|
|
|
caroline = callPackage ../development/libraries/caroline { };
|
|
|
|
+ castopod = callPackage ../applications/audio/castopod { };
|
|
+
|
|
castget = callPackage ../applications/networking/feedreaders/castget { };
|
|
|
|
castxml = callPackage ../development/tools/castxml { };
|
|
|
|
From cf6e43a3dd32d1fce0a315afd365aa90ee19130d Mon Sep 17 00:00:00 2001
|
|
From: misuzu <bakalolka@gmail.com>
|
|
Date: Fri, 7 Apr 2023 15:59:08 +0300
|
|
Subject: [PATCH 3/4] nixos/castopod: init
|
|
|
|
---
|
|
nixos/modules/module-list.nix | 1 +
|
|
nixos/modules/services/audio/castopod.nix | 299 ++++++++++++++++++
|
|
2 files changed, 299 insertions(+)
|
|
create mode 100644 nixos/modules/services/audio/castopod.nix
|
|
|
|
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
|
|
index 206d5eaf75dedc..54fd5c7b040314 100644
|
|
--- a/nixos/modules/module-list.nix
|
|
+++ b/nixos/modules/module-list.nix
|
|
@@ -324,6 +324,7 @@
|
|
./services/amqp/rabbitmq.nix
|
|
./services/audio/alsa.nix
|
|
./services/audio/botamusique.nix
|
|
+ ./services/audio/castopod.nix
|
|
./services/audio/gmediarender.nix
|
|
./services/audio/gonic.nix
|
|
./services/audio/hqplayerd.nix
|
|
diff --git a/nixos/modules/services/audio/castopod.nix b/nixos/modules/services/audio/castopod.nix
|
|
new file mode 100644
|
|
index 00000000000000..b782b548914795
|
|
--- /dev/null
|
|
+++ b/nixos/modules/services/audio/castopod.nix
|
|
@@ -0,0 +1,298 @@
|
|
+{ config, lib, pkgs, ... }:
|
|
+let
|
|
+ cfg = config.services.castopod;
|
|
+ fpm = config.services.phpfpm.pools.castopod;
|
|
+
|
|
+ user = "castopod";
|
|
+
|
|
+ # https://docs.castopod.org/getting-started/install.html#requirements
|
|
+ phpPackage = pkgs.php.withExtensions ({ enabled, all }: with all; [
|
|
+ intl
|
|
+ curl
|
|
+ mbstring
|
|
+ gd
|
|
+ exif
|
|
+ mysqlnd
|
|
+ ] ++ enabled);
|
|
+in
|
|
+{
|
|
+ meta.maintainers = with lib.maintainers; [ alexoundos misuzu ];
|
|
+
|
|
+ options.services = {
|
|
+ castopod = {
|
|
+ enable = lib.mkEnableOption (lib.mdDoc "Castopod");
|
|
+ package = lib.mkOption {
|
|
+ type = lib.types.package;
|
|
+ default = pkgs.castopod;
|
|
+ defaultText = lib.literalMD "pkgs.castopod";
|
|
+ description = lib.mdDoc "Which Castopod package to use.";
|
|
+ };
|
|
+ database = {
|
|
+ createLocally = lib.mkOption {
|
|
+ type = lib.types.bool;
|
|
+ default = true;
|
|
+ description = lib.mdDoc ''
|
|
+ Create the database and database user locally.
|
|
+ '';
|
|
+ };
|
|
+ hostname = lib.mkOption {
|
|
+ type = lib.types.str;
|
|
+ default = "localhost";
|
|
+ description = lib.mdDoc "Database hostname.";
|
|
+ };
|
|
+ name = lib.mkOption {
|
|
+ type = lib.types.str;
|
|
+ default = "castopod";
|
|
+ description = lib.mdDoc "Database name.";
|
|
+ };
|
|
+ user = lib.mkOption {
|
|
+ type = lib.types.str;
|
|
+ default = user;
|
|
+ description = lib.mdDoc "Database user.";
|
|
+ };
|
|
+ passwordFile = lib.mkOption {
|
|
+ type = lib.types.nullOr lib.types.path;
|
|
+ default = null;
|
|
+ example = "/run/keys/castopod-dbpassword";
|
|
+ description = lib.mdDoc ''
|
|
+ A file containing the password corresponding to
|
|
+ [](#opt-services.castopod.database.user).
|
|
+ '';
|
|
+ };
|
|
+ };
|
|
+ settings = lib.mkOption {
|
|
+ type = with lib.types; attrsOf (oneOf [ str int bool ]);
|
|
+ default = { };
|
|
+ example = {
|
|
+ "email.protocol" = "smtp";
|
|
+ "email.SMTPHost" = "localhost";
|
|
+ "email.SMTPUser" = "myuser";
|
|
+ "email.fromEmail" = "castopod@example.com";
|
|
+ };
|
|
+ description = lib.mdDoc ''
|
|
+ Environment variables used for Castopod.
|
|
+ See [](https://code.castopod.org/adaures/castopod/-/blob/main/.env.example)
|
|
+ for available environment variables.
|
|
+ '';
|
|
+ };
|
|
+ environmentFile = lib.mkOption {
|
|
+ type = lib.types.nullOr lib.types.path;
|
|
+ default = null;
|
|
+ example = "/run/keys/castopod-env";
|
|
+ description = lib.mdDoc ''
|
|
+ Environment file to inject e.g. secrets into the configuration.
|
|
+ See [](https://code.castopod.org/adaures/castopod/-/blob/main/.env.example)
|
|
+ for available environment variables.
|
|
+ '';
|
|
+ };
|
|
+ configureNginx = lib.mkOption {
|
|
+ type = lib.types.bool;
|
|
+ default = true;
|
|
+ description = lib.mdDoc "Configure nginx as a reverse proxy for CastoPod.";
|
|
+ };
|
|
+ localDomain = lib.mkOption {
|
|
+ type = lib.types.str;
|
|
+ example = "castopod.example.org";
|
|
+ description = lib.mdDoc "The domain serving your CastoPod instance.";
|
|
+ };
|
|
+ poolSettings = lib.mkOption {
|
|
+ type = with lib.types; attrsOf (oneOf [ str int bool ]);
|
|
+ default = {
|
|
+ "pm" = "dynamic";
|
|
+ "pm.max_children" = "32";
|
|
+ "pm.start_servers" = "2";
|
|
+ "pm.min_spare_servers" = "2";
|
|
+ "pm.max_spare_servers" = "4";
|
|
+ "pm.max_requests" = "500";
|
|
+ };
|
|
+ description = lib.mdDoc ''
|
|
+ Options for Castopod's PHP pool. See the documentation on `php-fpm.conf` for details on configuration directives.
|
|
+ '';
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ config = lib.mkIf cfg.enable {
|
|
+ services.castopod.settings =
|
|
+ let
|
|
+ sslEnabled = with config.services.nginx.virtualHosts.${cfg.localDomain}; addSSL || forceSSL || onlySSL || enableACME || useACMEHost != null;
|
|
+ baseURL = "http${lib.optionalString sslEnabled "s"}://${cfg.localDomain}";
|
|
+ in
|
|
+ lib.mapAttrs (_name: lib.mkDefault) {
|
|
+ "app.forceGlobalSecureRequests" = sslEnabled;
|
|
+ "app.baseURL" = baseURL;
|
|
+
|
|
+ "media.baseURL" = baseURL;
|
|
+ "media.root" = "media";
|
|
+ "media.storage" = cfg.package.stateDirectory;
|
|
+
|
|
+ "admin.gateway" = "admin";
|
|
+ "auth.gateway" = "auth";
|
|
+
|
|
+ "database.default.hostname" = cfg.database.hostname;
|
|
+ "database.default.database" = cfg.database.name;
|
|
+ "database.default.username" = cfg.database.user;
|
|
+ "database.default.DBPrefix" = "cp_";
|
|
+
|
|
+ "cache.handler" = "file";
|
|
+ };
|
|
+
|
|
+ services.phpfpm.pools.castopod = {
|
|
+ inherit user;
|
|
+ group = config.services.nginx.group;
|
|
+ phpPackage = phpPackage;
|
|
+ phpOptions = ''
|
|
+ # https://code.castopod.org/adaures/castopod/-/blob/main/docker/production/app/uploads.ini
|
|
+ file_uploads = On
|
|
+ memory_limit = 512M
|
|
+ upload_max_filesize = 500M
|
|
+ post_max_size = 512M
|
|
+ max_execution_time = 300
|
|
+ max_input_time = 300
|
|
+ '';
|
|
+ settings = {
|
|
+ "listen.owner" = config.services.nginx.user;
|
|
+ "listen.group" = config.services.nginx.group;
|
|
+ } // cfg.poolSettings;
|
|
+ };
|
|
+
|
|
+ systemd.services.castopod-setup = {
|
|
+ after = lib.optional config.services.mysql.enable "mysql.service";
|
|
+ requires = lib.optional config.services.mysql.enable "mysql.service";
|
|
+ wantedBy = [ "multi-user.target" ];
|
|
+ path = [ pkgs.openssl phpPackage ];
|
|
+ script =
|
|
+ let
|
|
+ envFile = "${cfg.package.stateDirectory}/.env";
|
|
+ media = "${cfg.settings."media.storage"}/${cfg.settings."media.root"}";
|
|
+ in
|
|
+ ''
|
|
+ mkdir -p ${cfg.package.stateDirectory}/writable/{cache,logs,session,temp,uploads}
|
|
+
|
|
+ if [ ! -d ${lib.escapeShellArg media} ]; then
|
|
+ cp --no-preserve=mode,ownership -r ${cfg.package}/share/castopod/public/media ${lib.escapeShellArg media}
|
|
+ fi
|
|
+
|
|
+ if [ ! -f ${cfg.package.stateDirectory}/salt ]; then
|
|
+ openssl rand -base64 33 > ${cfg.package.stateDirectory}/salt
|
|
+ fi
|
|
+
|
|
+ cat <<'EOF' > ${envFile}
|
|
+ ${lib.generators.toKeyValue { } cfg.settings}
|
|
+ EOF
|
|
+
|
|
+ echo "analytics.salt=$(cat ${cfg.package.stateDirectory}/salt)" >> ${envFile}
|
|
+
|
|
+ ${if (cfg.database.passwordFile != null) then ''
|
|
+ echo "database.default.password=$(cat ${lib.escapeShellArg cfg.database.passwordFile})" >> ${envFile}
|
|
+ '' else ''
|
|
+ echo "database.default.password=" >> ${envFile}
|
|
+ ''}
|
|
+
|
|
+ ${lib.optionalString (cfg.environmentFile != null) ''
|
|
+ cat "$CREDENTIALS_DIRECTORY/envfile" >> ${envFile}
|
|
+ ''}
|
|
+
|
|
+ php spark castopod:database-update
|
|
+ '';
|
|
+ serviceConfig = {
|
|
+ StateDirectory = "castopod";
|
|
+ LoadCredential = lib.mkIf (cfg.environmentFile != null) [
|
|
+ "envfile:${cfg.environmentFile}"
|
|
+ ];
|
|
+ WorkingDirectory = "${cfg.package}/share/castopod";
|
|
+ Type = "oneshot";
|
|
+ RemainAfterExit = true;
|
|
+ User = user;
|
|
+ Group = config.services.nginx.group;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ systemd.services.castopod-scheduled = {
|
|
+ after = [ "castopod-setup.service" ];
|
|
+ wantedBy = [ "multi-user.target" ];
|
|
+ path = [ phpPackage ];
|
|
+ script = ''
|
|
+ php ${cfg.package}/share/castopod/spark tasks:run
|
|
+ '';
|
|
+ serviceConfig = {
|
|
+ StateDirectory = "castopod";
|
|
+ WorkingDirectory = "${cfg.package}/share/castopod";
|
|
+ Type = "oneshot";
|
|
+ User = user;
|
|
+ Group = config.services.nginx.group;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ systemd.timers.castopod-scheduled = {
|
|
+ wantedBy = [ "timers.target" ];
|
|
+ timerConfig = {
|
|
+ OnCalendar = "*-*-* *:*:00";
|
|
+ Unit = "castopod-scheduled.service";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ services.mysql = lib.mkIf cfg.database.createLocally {
|
|
+ enable = true;
|
|
+ package = lib.mkDefault pkgs.mariadb;
|
|
+ ensureDatabases = [ cfg.database.name ];
|
|
+ ensureUsers = [{
|
|
+ name = cfg.database.user;
|
|
+ ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
|
|
+ }];
|
|
+ };
|
|
+
|
|
+ services.nginx = lib.mkIf cfg.configureNginx {
|
|
+ enable = true;
|
|
+ resolver.addresses = [ "127.0.0.53" ];
|
|
+ virtualHosts."${cfg.localDomain}" = {
|
|
+ root = lib.mkForce "${cfg.package}/share/castopod/public";
|
|
+
|
|
+ extraConfig = ''
|
|
+ client_max_body_size 512m;
|
|
+ try_files $uri $uri/ /index.php?$args;
|
|
+ index index.php index.html;
|
|
+ '';
|
|
+
|
|
+ locations."@force_get" = {
|
|
+ extraConfig = ''
|
|
+ recursive_error_pages on;
|
|
+ proxy_method GET;
|
|
+ proxy_pass https://podcasts.dgnum.eu/$request_uri;
|
|
+ '';
|
|
+ };
|
|
+
|
|
+ locations."^~ /${cfg.settings."media.root"}/" = {
|
|
+ root = cfg.settings."media.storage";
|
|
+ extraConfig = ''
|
|
+ add_header Access-Control-Allow-Origin "*";
|
|
+ expires max;
|
|
+ access_log off;
|
|
+ '';
|
|
+ };
|
|
+
|
|
+ locations."~ \.php$" = {
|
|
+ fastcgiParams = {
|
|
+ SERVER_NAME = "$host";
|
|
+ };
|
|
+ extraConfig = ''
|
|
+ error_page 550 = @force_get;
|
|
+ if ($request_method = HEAD) { return 550; }
|
|
+ fastcgi_intercept_errors on;
|
|
+ fastcgi_index index.php;
|
|
+ fastcgi_pass unix:${fpm.socket};
|
|
+ try_files $uri =404;
|
|
+ fastcgi_read_timeout 3600;
|
|
+ fastcgi_send_timeout 3600;
|
|
+ '';
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ users.users.${user} = lib.mapAttrs (name: lib.mkDefault) {
|
|
+ description = "Castopod user";
|
|
+ isSystemUser = true;
|
|
+ group = config.services.nginx.group;
|
|
+ };
|
|
+ };
|
|
+}
|