{ pkgs, config, service_configs, lib, ... }: let radarrConfig = "${service_configs.radarr.dataDir}/config.xml"; sonarrConfig = "${service_configs.sonarr.dataDir}/config.xml"; configPath = "/var/lib/recyclarr/config.json"; # Runs as root (via + prefix) after the NixOS module writes config.json. # Extracts API keys from radarr/sonarr config.xml and injects them via jq. injectApiKeys = pkgs.writeShellScript "recyclarr-inject-api-keys" '' RADARR_KEY=$(${lib.extractArrApiKey radarrConfig}) SONARR_KEY=$(${lib.extractArrApiKey sonarrConfig}) ${pkgs.jq}/bin/jq \ --arg rk "$RADARR_KEY" \ --arg sk "$SONARR_KEY" \ '.radarr.movies.api_key = $rk | .sonarr.series.api_key = $sk' \ ${configPath} > ${configPath}.tmp mv ${configPath}.tmp ${configPath} chown recyclarr:recyclarr ${configPath} ''; in { imports = [ (lib.serviceMountWithZpool "recyclarr" service_configs.zpool_ssds [ service_configs.recyclarr.dataDir ]) ]; systemd.tmpfiles.rules = [ "d ${service_configs.recyclarr.dataDir} 0755 recyclarr recyclarr -" ]; services.recyclarr = { enable = true; command = "sync"; schedule = "daily"; user = "recyclarr"; group = "recyclarr"; configuration = { radarr.movies = { base_url = "http://localhost:${builtins.toString service_configs.ports.private.radarr.port}"; include = [ { template = "radarr-quality-definition-movie"; } { template = "radarr-quality-profile-remux-web-2160p"; } { template = "radarr-custom-formats-remux-web-2160p"; } ]; # Group WEB 2160p with 1080p in the same quality tier so custom # format scores -- not quality ranking -- decide the winner. # Native 4K with HDR/DV from good release groups scores high and # wins; AI upscales get -10000 from the Upscaled CF and are # blocked by min_format_score. Untagged upscales from unknown # groups (score ~0) lose to well-scored 1080p (Tier 01 = +1750). quality_profiles = [ { name = "Remux + WEB 2160p"; min_format_score = 0; reset_unmatched_scores.enabled = true; upgrade = { allowed = true; until_quality = "Remux-2160p"; until_score = 10000; }; qualities = [ { name = "Remux-2160p"; } { name = "WEB/Bluray"; qualities = [ "WEBDL-2160p" "WEBRip-2160p" "Remux-1080p" "Bluray-1080p" "WEBDL-1080p" "WEBRip-1080p" ]; } { name = "HDTV-1080p"; } { name = "Bluray-720p"; } { name = "WEB 720p"; qualities = [ "WEBDL-720p" "WEBRip-720p" ]; } { name = "HDTV-720p"; } ]; } ]; custom_formats = [ # DV (w/o HDR fallback) - block releases with DV that lack HDR10 fallback { trash_ids = [ "923b6abef9b17f937fab56cfcf89e1f1" ]; assign_scores_to = [ { name = "Remux + WEB 2160p"; } ]; } # Upscaled - block AI upscales and other upscaled-to-2160p releases { trash_ids = [ "bfd8eb01832d646a0a89c4deb46f8564" ]; assign_scores_to = [ { name = "Remux + WEB 2160p"; score = -10000; } ]; } ]; }; sonarr.series = { base_url = "http://localhost:${builtins.toString service_configs.ports.private.sonarr.port}"; include = [ { template = "sonarr-quality-definition-series"; } { template = "sonarr-v4-quality-profile-web-2160p"; } { template = "sonarr-v4-custom-formats-web-2160p"; } ]; # Group WEB 2160p with 1080p in the same quality tier so custom # format scores -- not quality ranking -- decide the winner. # Native 4K with HDR/DV from good release groups scores high and # wins; AI upscales get -10000 from the Upscaled CF and are # blocked by min_format_score. Untagged upscales from unknown # groups (score ~0) lose to well-scored 1080p (Tier 01 = +1750). quality_profiles = [ { name = "WEB-2160p"; min_format_score = 0; reset_unmatched_scores.enabled = true; upgrade = { allowed = true; until_quality = "WEB/Bluray"; until_score = 10000; }; qualities = [ { name = "WEB/Bluray"; qualities = [ "WEBDL-2160p" "WEBRip-2160p" "Bluray-1080p Remux" "Bluray-1080p" "WEBDL-1080p" "WEBRip-1080p" ]; } { name = "HDTV-1080p"; } { name = "Bluray-720p"; } { name = "WEB 720p"; qualities = [ "WEBDL-720p" "WEBRip-720p" ]; } { name = "HDTV-720p"; } ]; } ]; custom_formats = [ # DV (w/o HDR fallback) - block releases with DV that lack HDR10 fallback { trash_ids = [ "9b27ab6498ec0f31a3353992e19434ca" ]; assign_scores_to = [ { name = "WEB-2160p"; } ]; } # Upscaled - block AI upscales and other upscaled-to-2160p releases { trash_ids = [ "23297a736ca77c0fc8e70f8edd7ee56c" ]; assign_scores_to = [ { name = "WEB-2160p"; score = -10000; } ]; } ]; }; }; }; # Re-sync immediately on deploy when the recyclarr config changes systemd.services.recyclarr = { restartTriggers = [ (builtins.toJSON config.services.recyclarr.configuration) ]; after = [ "network-online.target" "radarr.service" "sonarr.service" ]; wants = [ "network-online.target" ]; serviceConfig.ExecStartPre = [ "+${injectApiKeys}" ]; }; }