profilarr: swap recyclarr for Dictionarry's Profilarr

Profilarr replaces the recyclarr/TRaSH-Guides flow with a stateful web
service that owns *arr profiles end-to-end via its own UI. Runs as an
oci-container on 127.0.0.1:6868, fronted by nginx at
profilarr.nordhammer.it behind Authelia (one_factor).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ediblerope 2026-04-30 20:00:33 +01:00
parent 91a94adc26
commit a9649be705
5 changed files with 31 additions and 148 deletions

View file

@ -31,7 +31,7 @@
./services/authelia.nix ./services/authelia.nix
./services/homepage.nix ./services/homepage.nix
./services/arr-interconnect.nix ./services/arr-interconnect.nix
./services/recyclarr.nix ./services/profilarr.nix
./services/adguard.nix ./services/adguard.nix
./services/router.nix ./services/router.nix
./services/crowdsec.nix ./services/crowdsec.nix

View file

@ -79,6 +79,7 @@ in
{ domain = "bazarr.nordhammer.it"; policy = "one_factor"; } { domain = "bazarr.nordhammer.it"; policy = "one_factor"; }
{ domain = "prowlarr.nordhammer.it"; policy = "one_factor"; } { domain = "prowlarr.nordhammer.it"; policy = "one_factor"; }
{ domain = "torrent.nordhammer.it"; policy = "one_factor"; } { domain = "torrent.nordhammer.it"; policy = "one_factor"; }
{ domain = "profilarr.nordhammer.it"; policy = "one_factor"; }
]; ];
}; };

View file

@ -111,6 +111,7 @@ in
"homepage.nordhammer.it" = protectedProxy 8082; "homepage.nordhammer.it" = protectedProxy 8082;
"7dtd.nordhammer.it" = protectedProxy 8090; "7dtd.nordhammer.it" = protectedProxy 8090;
"adguard.nordhammer.it" = protectedProxy 3000; "adguard.nordhammer.it" = protectedProxy 3000;
"profilarr.nordhammer.it" = protectedProxy 6868;
# --- Local-only: serves update history JSON to Homepage's customapi widget --- # --- Local-only: serves update history JSON to Homepage's customapi widget ---
"homepage-updates.local" = { "homepage-updates.local" = {

28
services/profilarr.nix Normal file
View file

@ -0,0 +1,28 @@
# services/profilarr.nix — Dictionarry's Profilarr quality-profile manager.
#
# Replaces the old recyclarr/TRaSH-Guides flow. Profilarr runs as a stateful
# web service with its own UI; *arr API keys, profile selections, custom
# formats, and sync schedule all live inside its own DB. Nix only owns the
# container, the storage dir, and the nginx vhost — everything else is
# configured at https://profilarr.nordhammer.it after first boot.
{ config, lib, ... }:
{
config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") {
systemd.tmpfiles.rules = [
"d /var/lib/profilarr 0755 root root -"
];
virtualisation.oci-containers.containers.profilarr = {
image = "ghcr.io/dictionarry-hub/profilarr:latest";
volumes = [
"/var/lib/profilarr:/config"
];
# Localhost-only; nginx fronts it at profilarr.nordhammer.it behind Authelia
ports = [ "127.0.0.1:6868:6868" ];
environment = {
TZ = "Europe/London";
};
};
};
}

View file

@ -1,147 +0,0 @@
# services/recyclarr.nix — TRaSH-Guide quality profiles for Sonarr & Radarr.
#
# Pulls the latest custom formats + quality profiles from TRaSH and pushes
# them into each *arr's API. API keys are extracted at runtime from each
# *arr's config.xml (same pattern as arr-interconnect.nix) so there's no
# secret to manage. Runs weekly via systemd timer; idempotent.
#
# Profiles installed:
# Sonarr: WEB-1080p (default) | WEB-2160p (per-show opt-in, WEB only)
# Radarr: HD Bluray + WEB (default) | UHD Bluray + WEB (per-movie opt-in)
#
# AV1 is banned across all 4 profiles (GPU lacks hardware decode).
#
# Manual sync: sudo systemctl start recyclarr-sync
{ config, lib, pkgs, ... }:
let
recyclarrConfig = pkgs.writeText "recyclarr.yml" ''
sonarr:
sonarr-main:
base_url: http://127.0.0.1:8989
api_key: !env_var SONARR_API_KEY
delete_old_custom_formats: true
replace_existing_custom_formats: true
quality_definition:
type: series
include:
- template: sonarr-quality-definition-series
- template: sonarr-v4-quality-profile-web-1080p
- template: sonarr-v4-custom-formats-web-1080p
- template: sonarr-v4-quality-profile-web-2160p
- template: sonarr-v4-custom-formats-web-2160p
custom_formats:
# AV1 ban — GPU has no hardware decode for AV1.
- trash_ids:
- 15a05bc7c1a36e2b57fd628f8977e2fc
assign_scores_to:
- name: WEB-1080p
score: -10000
- name: WEB-2160p
score: -10000
# x265 (HD) preference — TRaSH defaults this to -10000 because
# most x265-1080p is lazy re-encodes. We override to +500 to
# actively prefer HEVC for disk space. Bad encodes are still
# filtered by Scene/No-RlsGroup/Retags/Obfuscated (each -10000).
- trash_ids:
- 47435ece6b99a0b477caf360e79ba0bb
assign_scores_to:
- name: WEB-1080p
score: 500
radarr:
radarr-main:
base_url: http://127.0.0.1:7878
api_key: !env_var RADARR_API_KEY
delete_old_custom_formats: true
replace_existing_custom_formats: true
quality_definition:
type: movie
include:
- template: radarr-quality-definition-movie
- template: radarr-quality-profile-hd-bluray-web
- template: radarr-custom-formats-hd-bluray-web
- template: radarr-quality-profile-uhd-bluray-web
- template: radarr-custom-formats-uhd-bluray-web
custom_formats:
# AV1 ban
- trash_ids:
- cae4ca30163749b891686f95532519bd
assign_scores_to:
- name: HD Bluray + WEB
score: -10000
- name: UHD Bluray + WEB
score: -10000
# x265 (HD) preference — same rationale as Sonarr above.
- trash_ids:
- dc98083864ea246d05a42df0d05f81cc
assign_scores_to:
- name: HD Bluray + WEB
score: 2000
'';
syncScript = pkgs.writeShellScript "recyclarr-sync" ''
set -euo pipefail
PATH="${lib.makeBinPath [ pkgs.recyclarr pkgs.gnused pkgs.coreutils ]}:$PATH"
extract_arr_key() {
if [ -f "$1" ]; then
sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "$1"
fi
}
SONARR_API_KEY=$(extract_arr_key /var/lib/sonarr/config.xml)
RADARR_API_KEY=$(extract_arr_key /var/lib/radarr/config.xml)
if [ -z "$SONARR_API_KEY" ] || [ -z "$RADARR_API_KEY" ]; then
echo "Sonarr or Radarr API key not available yet skipping sync."
exit 0
fi
export SONARR_API_KEY RADARR_API_KEY
recyclarr sync --app-data /var/lib/recyclarr --config ${recyclarrConfig}
'';
in
{
config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") {
systemd.tmpfiles.rules = [
"d /var/lib/recyclarr 0700 root root -"
];
systemd.services.recyclarr-sync = {
description = "Sync TRaSH-Guide profiles into Sonarr & Radarr";
after = [
"sonarr.service"
"radarr.service"
"arr-interconnect.service"
"network-online.target"
];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = syncScript;
};
};
systemd.timers.recyclarr-sync = {
description = "Weekly TRaSH-Guide profile sync";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "weekly";
Persistent = true;
RandomizedDelaySec = "30m";
};
};
};
}