Skip to content

Recyclarr Config Generator

Generates a recyclarr configuration from live Sonarr and Radarr instances, instead of hand-writing one and syncing it the other way.

Point it at each *arr, and it reads what is already configured — quality profiles, custom format scores, quality definition sizes, naming formats — and renders the equivalent recyclarr.yml. Custom formats are matched back to their TRaSH Guides trash_id by name, so the output is guide-backed and safe to recyclarr sync.

This is a one-way snapshot tool. Once the config exists, recyclarr becomes the source of truth and you edit the YAML, not the UI.

  • Python 3.9+
  • pip install -r requirements.txt (requests, PyYAML)
  • Network access to each *arr, and to GitHub once (the TRaSH Guides tarball is cached under ~/.cache/recyclarr-config-generator/ and refreshed daily)

Only Sonarr and Radarr are supported. recyclarr does not manage Prowlarr, Lidarr, Readarr or Bazarr, so those stacks have no config to generate.

Terminal window
cd utils/recyclarr-config-generator
pip install -r requirements.txt
cp instances.example.yml instances.yml # then edit: one entry per *arr
python generate_recyclarr_config.py # writes recyclarr.yml + secrets.yml

Preview without writing anything:

Terminal window
python generate_recyclarr_config.py --stdout

Each *arr’s key is under Settings → General → API Key.

Keys should not live in instances.yml. Leave api_key out and the generator reads an environment variable — api_key_env if set, otherwise <KEY>_API_KEY derived from the instance key. That fits the repo’s BWS convention:

Terminal window
bws run --access-token "$BWS_ACCESS_TOKEN" -- python generate_recyclarr_config.py

--api-key-mode controls how the key is referenced in the output:

ModeOutputNotes
secret (default)api_key: !secret sonarr_...also writes secrets.yml (mode 600)
envapi_key: !env_var SONARR_..recyclarr reads it from its own environment
inlineapi_key: "abc123..."plain text in the config — avoid committing

instances.yml, secrets.yml, recyclarr.yml and configs/ are all gitignored here.

FlagEffect
--splitone file per instance in --output dir, for recyclarr’s configs
--reset-unmatched-scoresadd reset_unmatched_scores.enabled to every profile
--include-zero-scoresalso emit custom formats currently scored 0
--no-modernizekeep retired formats as comments instead of migrating them
--no-quality-definitionskip the quality_definition block
--no-media-namingskip the media_naming block
--insecureskip TLS verification (internal Step CA certs)
--refresh-guidesforce a re-download of the TRaSH Guides
--guides-tarball PATHuse a local Guides tarball; no network needed

Per-instance, verify_ssl: false does the same as --insecure for one entry.

From the APIInto the config
qualityprofilequality_profiles — upgrade/cutoff, min scores, enabled qualities and groups (top-first)
qualityprofilecustom_formats — trash_ids grouped by identical per-profile score assignments
qualitydefinitionquality_definition — closest guide size set, plus per-quality overrides where the instance differs
config/namingmedia_naming — the guide key whose format string matches exactly

Every emitted trash_id carries the custom format’s name as a trailing comment, matching the convention in the recyclarr docs.

Custom formats you invented yourself are skipped. recyclarr only syncs formats that exist in the TRaSH Guides, so anything with no counterpart is listed as a comment at the end of that instance’s block and stays hand-managed in the UI. The same applies to naming formats you customised — the guide key cannot be inferred, so the raw format is left as a comment.

Profiles are emitted with the qualities that are currently enabled, highest-first. Anything not listed gets disabled by recyclarr on sync, which reproduces the profile as it stands.

Instances keep whatever name a format was imported under while the guide renames things, so matching runs in three stages, stopping at the first hit:

  1. Exact name, case- and punctuation-insensitive — DTS-X finds DTS X.
  2. Identical specifications — the matching rules fingerprint the format, so it is found however far the name drifted (DV (WEBDL) → DV (w/o HDR fallback)).
  3. Normalized name — drops a trailing parenthetical and reads v2 as 2 (Anime BD Tier 01 (Top SeaDex Muxers) → Anime BD Tier 01).

Stage 3 alone is not trustworthy, so a stage-3 hit is accepted only when both formats are built from the same kinds of rules: HDR (undefined) matches release groups while the guide’s HDR matches title tags, so that pairing is rejected and reported rather than silently mis-scored. Every stage-2 and stage-3 match is printed as it happens.

TRaSH replaced the per-flavour HDR formats with a single HDR plus additive boost formats. Rather than emitting the old ones as dead comments, the generator rewrites them, scoring each boost at the difference from the profile’s plain HDR score so the totals a profile was tuned around survive:

DV, DV HDR10, DV HDR10+, DV HLG, DV SDR at 1500 -> HDR 500 + DV Boost 1000
HDR10+ at 600 -> HDR 500 + HDR10+ Boost 100
HDR10, PQ, HDR (undefined) at 500 -> dropped, already covered by HDR 500

An existing HDR score wins as the base; a flavour scoring no higher than HDR is simply dropped. Substitutions are printed as they run and recorded as a comment block in the config. --no-modernize turns the pass off.

Formats with no clean equivalent are never guessed at — Sonarr’s retired UHD Streaming Cut resembles the current UHD Streaming Boost but covers different services and is scored the other way, so it is reported for you to decide.

Always preview before the first sync — it shows exactly what recyclarr would change:

Terminal window
recyclarr sync --preview

Expect small diffs on the first run: scores the guide has but your instance never set, and qualities whose sizes were left at *arr defaults. Review them, then sync for real.