From c1e44c9d5d53d513c78f567edfbfb6737627d1ed Mon Sep 17 00:00:00 2001 From: Josh Cain Date: Wed, 13 May 2026 11:25:10 -0400 Subject: [PATCH 1/2] Add FlareSolverr, Maintainerr, Decluttarr, and Checkrr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes part of #37 — adds *arr-adjacent services from the user's running stack that weren't yet in the repo. - **flaresolverr** (port 8191, media_network): Cloudflare bypass proxy. Prowlarr is in the repo and depends on this for most protected indexers. No env required. - **maintainerr** (port 6246, media_network): rule-based Plex library cleanup. Bind mount under ${USERDIR}/maintainerr/data. - **decluttarr** (no port, download_network): removes stalled / failed downloads from Radarr/Sonarr queues. Needs RADARR_API_KEY and SONARR_API_KEY from .env, which are obtained from the *arr UIs *after* first boot — decluttarr starts with them blank and skips any service whose key isn't set. - **checkrr** (port 8585, media_network): scans media files for codec / corruption issues. Read-only mount of the media library. .env.example: re-adds RADARR_API_KEY and SONARR_API_KEY with a comment explaining the post-boot setup. CLAUDE.md env-var contract now has a third category for "populated after first boot" so the chicken-and-egg is documented, not lurking. README service table picks up the four new entries; network architecture and CLAUDE.md mirror the new memberships. Old "ERROR MONITORING" section header renamed to "LIBRARY MAINTENANCE" to fit decluttarr/checkrr/cleanarr together. Co-Authored-By: Claude Opus 4.7 --- .env.example | 7 +++++ CLAUDE.md | 7 +++-- README.md | 8 ++++-- docker-compose.yml | 69 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index 27d0979..6518437 100644 --- a/.env.example +++ b/.env.example @@ -36,6 +36,13 @@ TRANSMISSION_RPC_PASSWORD= # Host port to expose Grafana on. Defaults to 3000 if unset. GRAFANA_PORT=3000 +# ============ Decluttarr (queue cleanup for Radarr/Sonarr) ============ +# These keys come from Radarr's Settings -> General -> API Key (and Sonarr's +# equivalent) AFTER the stack is running. Decluttarr starts fine with them +# blank — it just skips any service whose key isn't set. +RADARR_API_KEY= +SONARR_API_KEY= + # ============ Tracearr (required — stack will refuse to start if blank) ============ # Use strong random strings, e.g. `openssl rand -base64 32` DB_PASSWORD= diff --git a/CLAUDE.md b/CLAUDE.md index 1ae4bfe..06db776 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -24,8 +24,8 @@ There is no test suite. After changing `docker-compose.yml`, always run `docker **Network isolation matters.** Services are split across four bridge networks and one host-mode service. A service can only reach another if they share a network — adding a new service requires picking the right one (or declaring multiple): - `monitoring_network` — tautulli, grafana, telegraf, watchtower, portainer, prometheus, cadvisor, node-exporter -- `media_network` — seerr, radarr, sonarr, prowlarr, bazarr -- `download_network` — transmission, watchlistarr, cleanarr, requestrr, radarr, sonarr +- `media_network` — seerr, radarr, sonarr, prowlarr, bazarr, flaresolverr, maintainerr, checkrr +- `download_network` — transmission, watchlistarr, cleanarr, requestrr, decluttarr, radarr, sonarr - `tracearr-network` — tracearr, timescale (PostgreSQL), redis - **host network** — plex only (required for proper streaming/discovery) @@ -62,5 +62,6 @@ The mounted config directory is `plex-meta-manager/config/`. Its structure is re 1. **Hard-required** (stack won't start): `DB_PASSWORD`, `JWT_SECRET`, `COOKIE_SECRET` (Tracearr); `OPENVPN_PROVIDER`, `OPENVPN_CONFIG`, `OPENVPN_USERNAME`, `OPENVPN_PASSWORD` (Transmission VPN). All use the `${VAR:?must be set}` fail-fast form. 2. **Effectively required for the feature to work**: `PUID`/`PGID`/`TZ`/`USERDIR` (everything), `PLEX_CLAIM` (first-boot only), `GRAFANA_PORT` (defaults to 3000 if unset), `LOCAL_NETWORK` (Transmission, defaults to `192.168.0.0/16`), `PMM_*` (Kometa), `TRANSMISSION_RPC_USERNAME`/`TRANSMISSION_RPC_PASSWORD` (optional web UI auth). +3. **Populated after first boot**: `RADARR_API_KEY`, `SONARR_API_KEY` (Decluttarr). These come from the Radarr/Sonarr UIs after the stack is up — Decluttarr starts fine with them blank and skips any service whose key isn't set. **Note:** this is a real exception to the "every var in `.env.example` is consumed by compose" rule above — flag this chicken-and-egg to users on first-boot questions, since the *arr API keys are only obtainable post-`up`. -If a user mentions an env var not in this list (e.g. `RADARR_API_KEY`, `DOCKER_INFLUXDB_*`, `PLEX_TOKEN`), it's from an older version of the stack — not consumed today. +If a user mentions an env var not in this list (e.g. `DOCKER_INFLUXDB_*`, `PLEX_TOKEN`, `EMAIL`/`PASSWORD`), it's from an older version of the stack — not consumed today. diff --git a/README.md b/README.md index 1b55110..89253f8 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,11 @@ A ready-to-use [Kometa](https://kometa.wiki/) (Plex Meta Manager) configuration | [Sonarr](https://sonarr.tv/) | TV show management and downloading | `8989` | | [Prowlarr](https://prowlarr.com/) | Indexer manager that feeds Radarr/Sonarr | `9696` | | [Bazarr](https://www.bazarr.media/) | Subtitle management for Radarr/Sonarr libraries | `6767` | +| [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) | Cloudflare bypass proxy for Prowlarr indexers | `8191` | +| [Maintainerr](https://github.com/jorenn92/Maintainerr) | Rule-based Plex library cleanup (auto-remove watched/aged items) | `6246` | | [Watchlistarr](https://github.com/nylonee/watchlistarr) | Syncs Plex watchlist to Radarr/Sonarr | N/A | +| [Decluttarr](https://github.com/ManiMatter/decluttarr) | Removes stalled / failed downloads from \*arr queues | N/A | +| [Checkrr](https://github.com/aetaric/checkrr) | Scans media files for codec / corruption issues | `8585` | | [Cleanarr](https://github.com/se1exin/Cleanarr) | Finds and removes duplicate content | N/A | | [Requestrr](https://github.com/darkalfx/requestrr) | Discord bot for content requests | `4545` | @@ -174,8 +178,8 @@ These services pair well with this stack but are not included in the default `do Services are isolated into separate Docker networks: - **`monitoring_network`** - Tautulli, Grafana, Telegraf, Watchtower, Portainer, Prometheus, cAdvisor, node-exporter -- **`media_network`** - Seerr, Radarr, Sonarr, Prowlarr, Bazarr -- **`download_network`** - Transmission, Watchlistarr, Cleanarr, Requestrr, Radarr, Sonarr +- **`media_network`** - Seerr, Radarr, Sonarr, Prowlarr, Bazarr, FlareSolverr, Maintainerr, Checkrr +- **`download_network`** - Transmission, Watchlistarr, Cleanarr, Requestrr, Decluttarr, Radarr, Sonarr - **`tracearr-network`** - Tracearr, TimescaleDB, Redis Plex runs in host network mode for optimal streaming performance. Radarr and Sonarr are attached to both `media_network` (so Seerr, Prowlarr, and Bazarr can reach them) and `download_network` (so Watchlistarr and Transmission can reach them). diff --git a/docker-compose.yml b/docker-compose.yml index 9192be4..a272a28 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -225,6 +225,36 @@ services: - ${USERDIR}/plex/media:/media restart: unless-stopped + # Cloudflare bypass proxy. Prowlarr (and any other indexer client) + # routes requests through this to reach indexer sites behind Cloudflare. + flaresolverr: + container_name: flaresolverr + image: ghcr.io/flaresolverr/flaresolverr:latest + networks: + - media_network + ports: + - "8191:8191" + environment: + - LOG_LEVEL=info + - TZ=${TZ} + restart: unless-stopped + + # Rule-based Plex library maintenance (auto-remove watched / aged items). + maintainerr: + container_name: maintainerr + image: ghcr.io/jorenn92/maintainerr:latest + networks: + - media_network + ports: + - "6246:6246" + environment: + - PUID=${PUID} + - PGID=${PGID} + - TZ=${TZ} + volumes: + - ${USERDIR}/maintainerr/data:/opt/data + restart: unless-stopped + # ============ MEDIA CENTER ============ watchlistarr: container_name: watchlistarr @@ -268,7 +298,44 @@ services: - ${USERDIR}/transmission/data:/data restart: unless-stopped - # ============ ERROR MONITORING ============ + # ============ LIBRARY MAINTENANCE ============ + # Cleans stalled/failed downloads out of Radarr/Sonarr queues. Skips any + # service whose API key is blank, so it's safe to leave keys empty on + # first boot and fill them in after the *arrs are running. + decluttarr: + container_name: decluttarr + image: ghcr.io/manimatter/decluttarr:latest + networks: + - download_network + environment: + - TZ=${TZ} + - LOG_LEVEL=INFO + - RADARR_URL=http://radarr:7878 + - RADARR_KEY=${RADARR_API_KEY:-} + - SONARR_URL=http://sonarr:8989 + - SONARR_KEY=${SONARR_API_KEY:-} + - REMOVE_TIMER=10 + - REMOVE_FAILED=True + - REMOVE_STALLED=True + - REMOVE_MISSING_FILES=True + - REMOVE_ORPHANS=True + restart: unless-stopped + + # Scans media files for codec / corruption issues. Web UI on :8585. + checkrr: + container_name: checkrr + image: ghcr.io/aetaric/checkrr:latest + networks: + - media_network + ports: + - "8585:8585" + environment: + - TZ=${TZ} + volumes: + - ${USERDIR}/checkrr/config:/etc/checkrr + - ${USERDIR}/plex/media:/media:ro + restart: unless-stopped + cleanarr: container_name: cleanarr image: cleanarr/cleanarr From 67141331da55ff469decacd29974b4009a8fb332 Mon Sep 17 00:00:00 2001 From: Josh Cain Date: Wed, 13 May 2026 14:49:36 -0400 Subject: [PATCH 2/2] Pin decluttarr to v1.50.2 Decluttarr v2 (released Nov 1, 2025) replaced RADARR_URL/RADARR_KEY/ SONARR_URL/SONARR_KEY/REMOVE_TIMER/REMOVE_FAILED with TIMER, REMOVE_FAILED_ DOWNLOADS and structured RADARR/SONARR blocks that require both base_url and api_key. v2 on :latest would silently ignore the v1 env vars; pinning v1.50.2 preserves the documented blank-keys-on-first-boot UX until v2 has a graceful "skip empty api_key" mode. Co-Authored-By: Claude Opus 4.7 --- docker-compose.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index a272a28..766fae5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -302,9 +302,13 @@ services: # Cleans stalled/failed downloads out of Radarr/Sonarr queues. Skips any # service whose API key is blank, so it's safe to leave keys empty on # first boot and fill them in after the *arrs are running. + # Pinned to v1: v2 (Nov 2025) requires both base_url and api_key in + # structured RADARR/SONARR blocks, which breaks the blank-keys-on-first-boot + # workflow this service is configured around. Re-evaluate if v2 ever + # gains a "skip instances with empty api_key" behavior. decluttarr: container_name: decluttarr - image: ghcr.io/manimatter/decluttarr:latest + image: ghcr.io/manimatter/decluttarr:v1.50.2 networks: - download_network environment: