Add prowlarr

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-07-06 18:59:59 +01:00
parent 5c098a8aa9
commit bf1c84c057
32 changed files with 523 additions and 32 deletions

View File

@@ -11,7 +11,7 @@ in
(import ./authelia { inherit user home; })
(import ./gitea { inherit user home; })
(import ./grafana { inherit user home; })
(import ./jellyfin { inherit user home; })
(import ./media { inherit user home; })
(import ./nextcloud { inherit user home; })
(import ./ntfy { inherit user home; })
(import ./outline { inherit user home; })

View File

@@ -12,16 +12,28 @@
let
selfPkgs = inputs.self.packages.${system};
hmConfig = config.home-manager.users.${user};
inherit (hmConfig.virtualisation.quadlet) volumes networks;
autheliaClientId = "59TRpNutxEeRRCAZbDsK7rsnrA5NC69HAdAO45CEfc740xl4hgIacDy2u03oiFc89Exb67udBQvmfwxgeAQtJPiNAJxA5OzGmdQf";
inherit (hmConfig.virtualisation.quadlet) containers volumes networks;
jellyfinAutheliaClientId = "59TRpNutxEeRRCAZbDsK7rsnrA5NC69HAdAO45CEfc740xl4hgIacDy2u03oiFc89Exb67udBQvmfwxgeAQtJPiNAJxA5OzGmdQf";
in
{
home-manager.users.${user} = {
systemd.user.tmpfiles.rules = [
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data 700 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/films 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/shows 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/anime-films 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/anime-shows 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/music 755 storm storm"
];
sops = {
secrets = {
"jellyfin/admin".sopsFile = ../../../../../../secrets/secrets.yaml;
"jellyfin/authelia/password".sopsFile = ../../../../../../secrets/secrets.yaml;
"jellyfin/authelia/digest".sopsFile = ../../../../../../secrets/secrets.yaml;
"prowlarr/apiKey".sopsFile = ../../../../../../secrets/secrets.yaml;
};
templates = {
@@ -45,7 +57,7 @@ in
clients = [
{
client_id = autheliaClientId;
client_id = jellyfinAutheliaClientId;
client_name = "Jellyfin";
client_secret = hmConfig.sops.placeholder."jellyfin/authelia/digest";
redirect_uris = [ "https://media.karaolidis.com/sso/OID/redirect/authelia" ];
@@ -63,26 +75,27 @@ in
};
}
);
prowlarr-env.content = ''
PROWLARR_API_KEY=${hmConfig.sops.placeholder."prowlarr/apiKey"}
'';
};
};
systemd.user.tmpfiles.rules = [
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data 700 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/films 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/shows 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/anime-films 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/anime-shows 755 storm storm"
"d /mnt/storage/private/storm/containers/storage/volumes/media/_data/music 755 storm storm"
];
virtualisation.quadlet = {
networks.jellyfin = { };
networks = {
media = { };
jellyfin = { };
flaresolverr = { };
};
volumes = {
jellyfin-config = { };
jellyfin-data = { };
jellyfin-log = { };
jellyfin-cache = { };
prowlarr = { };
};
containers = {
@@ -98,19 +111,19 @@ in
setup = pkgs.writeTextFile {
name = "setup.sh";
executable = true;
text = builtins.readFile ./setup.sh;
text = builtins.readFile ./jellyfin/setup.sh;
};
in
[
"/mnt/storage/private/storm/containers/storage/volumes/media/_data:/var/lib/media"
"${setup}:/etc/jellyfin/setup.sh:ro"
"${./libraries}:/etc/jellyfin/libraries:ro"
"${./jellyfin/libraries}:/etc/jellyfin/libraries:ro"
"${volumes.jellyfin-config.ref}:/etc/jellyfin"
"${volumes.jellyfin-data.ref}:/var/lib/jellyfin"
"${volumes.jellyfin-log.ref}:/var/log/jellyfin"
"${volumes.jellyfin-cache.ref}:/tmp/jellyfin"
];
environments.JELLYFIN_OIDC_CLIENT_ID = autheliaClientId;
environments.JELLYFIN_OIDC_CLIENT_ID = jellyfinAutheliaClientId;
environmentFiles = [ hmConfig.sops.templates.jellyfin-env.path ];
labels = [
"traefik.enable=true"
@@ -123,9 +136,78 @@ in
unitConfig.After = [ "sops-nix.service" ];
};
authelia.containerConfig.volumes = [
"${hmConfig.sops.templates.authelia-jellyfin.path}:/etc/authelia/conf.d/jellyfin.yaml:ro"
];
flaresolverr.containerConfig = {
image = "docker-archive:${selfPkgs.docker-flaresolverr}";
networks = [ networks.flaresolverr.ref ];
};
prowlarr = {
containerConfig = {
image = "docker-archive:${selfPkgs.docker-prowlarr}";
networks = [
networks.media.ref
networks.transmission.ref
networks.flaresolverr.ref
networks.traefik.ref
];
volumes =
let
setup = pkgs.writeTextFile {
name = "setup.sh";
executable = true;
text = builtins.readFile ./prowlarr/setup.sh;
};
postStart = pkgs.writeTextFile {
name = "post-start.sh";
executable = true;
text = builtins.readFile ./prowlarr/post-start.sh;
};
in
[
"${setup}:/etc/prowlarr/setup.sh:ro"
"${postStart}:/etc/prowlarr/post-start.sh:ro"
"${./prowlarr/indexers}:/etc/prowlarr/indexers:ro"
"${volumes.prowlarr.ref}:/var/lib/prowlarr"
];
environments.PROWLARR_URL_BASE = "/indexers";
environmentFiles = [ hmConfig.sops.templates.prowlarr-env.path ];
labels = [
"traefik.enable=true"
"traefik.http.routers.prowlarr.rule=Host(`media.karaolidis.com`) && PathPrefix(`/indexers`)"
"traefik.http.routers.prowlarr.middlewares=authelia@docker"
];
};
unitConfig.After = [ "sops-nix.service" ];
};
authelia.containerConfig.volumes =
let
mediaConfig = (pkgs.formats.yaml { }).generate "media.yaml" {
access_control.rules = [
{
domain = "media.karaolidis.com";
policy = "one_factor";
resources = [ "^/(indexers|films|shows|anime-films|anime-shows)([/?].*)?$" ];
subject = [ "group:media" ];
}
{
domain = "media.karaolidis.com";
policy = "deny";
resources = [ "^/(indexers|films|shows|anime-films|anime-shows)([/?].*)?$" ];
}
{
domain = "media.karaolidis.com";
policy = "bypass";
}
];
};
in
[
"${mediaConfig}:/etc/authelia/conf.d/media.yaml:ro"
"${hmConfig.sops.templates.authelia-jellyfin.path}:/etc/authelia/conf.d/jellyfin.yaml:ro"
];
};
};
};

View File

@@ -78,14 +78,14 @@ for filepath in /etc/jellyfin/libraries/*/*.json; do
collectionType=$(jq -rn --arg s "$(basename "$(dirname "$filepath")")" '$s|@uri')
name=$(jq -rn --arg s "$(basename "$filepath" .json)" '$s|@uri')
curl -sf "${JELLYFIN_HOST}/Library/VirtualFolders?collectionType=${collectionType}&name=${name}" \
curl -sf "$JELLYFIN_HOST/Library/VirtualFolders?collectionType=$collectionType&name=$name" \
-X POST \
-H "Content-Type: application/json" \
-H 'Authorization: MediaBrowser Token="'"$token"'"' \
--data-binary @"${filepath}"
--data-binary @"$filepath"
done
curl -sf "${JELLYFIN_HOST}/Plugins/505ce9d1-d916-42fa-86ca-673ef241d7df/Configuration" \
curl -sf "$JELLYFIN_HOST/Plugins/505ce9d1-d916-42fa-86ca-673ef241d7df/Configuration" \
-X POST \
-H 'Content-Type: application/json' \
-H 'Authorization: MediaBrowser Token="'"$token"'"' \

View File

@@ -0,0 +1,19 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "1337x",
"fields": [
{
"name": "definitionFile",
"value": "1337x"
},
{
"name": "baseUrl",
"value": "https://1337x.to/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings",
"tags": [1]
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "Internet Archive",
"fields": [
{
"name": "definitionFile",
"value": "internetarchive"
},
{
"name": "baseUrl",
"value": "https://archive.org/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "LimeTorrents",
"fields": [
{
"name": "definitionFile",
"value": "limetorrents"
},
{
"name": "baseUrl",
"value": "https://www.limetorrents.lol/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,30 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "Nyaa.si",
"fields": [
{
"name": "definitionFile",
"value": "nyaasi"
},
{
"name": "baseUrl",
"value": "https://nyaa.si/"
},
{
"name": "sonarr_compatibility",
"value": true
},
{
"name": "strip_s01",
"value": true
},
{
"name": "radarr_compatibility",
"value": true
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "The Pirate Bay",
"fields": [
{
"name": "definitionFile",
"value": "thepiratebay"
},
{
"name": "baseUrl",
"value": "https://thepiratebay.org/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "TheRARBG",
"fields": [
{
"name": "definitionFile",
"value": "therarbg"
},
{
"name": "baseUrl",
"value": "https://therarbg.to/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "Torlock",
"fields": [
{
"name": "definitionFile",
"value": "torlock"
},
{
"name": "baseUrl",
"value": "https://www.torlock.com/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "TorrentDownload",
"fields": [
{
"name": "definitionFile",
"value": "torrentdownload"
},
{
"name": "baseUrl",
"value": "https://www.torrentdownload.info/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "Torrent Downloads",
"fields": [
{
"name": "definitionFile",
"value": "torrentdownloads"
},
{
"name": "baseUrl",
"value": "https://www.torrentdownloads.pro/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "YourBittorrent",
"fields": [
{
"name": "definitionFile",
"value": "yourbittorrent"
},
{
"name": "baseUrl",
"value": "https://yourbittorrent.com/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,19 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "kickasstorrents.to",
"fields": [
{
"name": "definitionFile",
"value": "kickasstorrents-to"
},
{
"name": "baseUrl",
"value": "https://kickass.torrentbay.st/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings",
"tags": [1]
}

View File

@@ -0,0 +1,18 @@
{
"enable": true,
"appProfileId": 1,
"priority": 25,
"name": "kickasstorrents.ws",
"fields": [
{
"name": "definitionFile",
"value": "kickasstorrents-ws"
},
{
"name": "baseUrl",
"value": "https://kickass.ws/"
}
],
"implementation": "Cardigann",
"configContract": "CardigannSettings"
}

View File

@@ -0,0 +1,9 @@
# shellcheck shell=sh
for filepath in /etc/prowlarr/indexers/*.json; do
curl -sf --retry 10 "$PROWLARR_HOST/api/v1/indexer?forceSave=true" \
-X POST \
-H "Content-Type: application/json" \
-H "X-Api-Key: $PROWLARR_API_KEY" \
--data-binary @"$filepath" || true
done

View File

@@ -0,0 +1,61 @@
# shellcheck shell=sh
# Tag ID: 1
curl -sf "$PROWLARR_HOST/api/v1/tag" \
-X POST \
-H 'Content-Type: application/json' \
-H "X-Api-Key: $PROWLARR_API_KEY" \
--data-raw '{"label": "flaresolverr"}'
curl -sf "$PROWLARR_HOST/api/v1/indexerProxy?forceSave=true" \
-X POST \
-H 'Content-Type: application/json' \
-H "X-Api-Key: $PROWLARR_API_KEY" \
--data-binary @- <<EOF
{
"name": "FlareSolverr",
"fields": [
{
"name": "host",
"value": "http://flaresolverr:8191/"
},
{
"name": "requestTimeout",
"value": 60
}
],
"implementation": "FlareSolverr",
"configContract": "FlareSolverrSettings",
"tags": [ 1 ]
}
EOF
curl -sf "$PROWLARR_HOST/api/v1/downloadclient?forceSave=true" \
-X POST \
-H 'Content-Type: application/json' \
-H "X-Api-Key: $PROWLARR_API_KEY" \
--data-binary @- <<EOF
{
"enable": true,
"protocol": "torrent",
"priority": 1,
"name": "Transmission",
"fields": [
{
"name": "host",
"value": "transmission"
},
{
"name": "port",
"value": 9091
},
{
"name": "urlBase",
"value": ""
}
],
"categories": [],
"implementation": "Transmission",
"configContract": "TransmissionSettings"
}
EOF

View File

@@ -1,6 +1,5 @@
#!/bin/sh
mkdir -p /tmp
PIPE=$(mktemp -u)
mkfifo "$PIPE"