# plungarr configuration — copy to .env and fill in. # If an app runs behind a URL base (e.g. http://host:8989/sonarr), include it. # Replace SERVER-IP with a hostname or address reachable from the container. # localhost inside the container refers to plungarr itself, not the Docker host. SONARR_URL=http://SERVER-IP:8989 SONARR_API_KEY= RADARR_URL=http://SERVER-IP:7878 RADARR_API_KEY= # More instances (anime Sonarr, 4K Radarr, ...): add _2 .. _9. Optional _NAME # labels the instance in logs and digests (defaults: sonarr-2, radarr-2, ...). # Configure every instance that shares your SABnzbd, or the stall watcher # cannot tell whose download it is looking at. #SONARR_2_URL=http://SERVER-IP:8990 #SONARR_2_API_KEY= #SONARR_2_NAME=anime # Seconds between queue checks. INTERVAL_SECONDS=300 # An item must be stuck at least this long before the janitor touches it # (avoids racing an import that is actively being processed). MIN_AGE_MINUTES=5 # Same junk release blocklisted this many times => stop searching for a replacement. LOOP_GUARD_LIMIT=2 # What to do with blocks plungarr recognises but that need a policy choice. # Each takes: replace (remove + blocklist + search for a different release), # discard (remove + blocklist, keep the library file, no new search), # notify (leave it alone and report it). # Archive the download client never extracted. ARCHIVE_ACTION=replace # Dangerous or executable file found in the download. DANGEROUS_FILE_ACTION=replace # File the arr flagged as a sample. Default notify: short-form shows trip the # sample detector on real episodes, and a replacement would be flagged again. SAMPLE_ACTION=notify # Download that is not an upgrade for the file already in the library. NOT_UPGRADE_ACTION=discard # true = log what would happen without doing it. DRY_RUN=false # User/group the service runs as inside the container. The entrypoint chowns # /state to this pair at start, so a bind-mounted folder just works. PUID=99 PGID=100 # Optional one-cycle execution; waits for periodic reviews before exiting. RUN_ONCE=false # --- stall watcher (dead usenet posts wedging the SABnzbd queue) --- # Both required to enable; without them the watcher is off. Watches for # old posts whose articles are gone and sit at the # head of the queue at ~0 B/s for days, starving everything behind them. SABNZBD_URL=http://SERVER-IP:8080 SABNZBD_API_KEY= # Head-of-queue slot making less than STALL_MIN_PROGRESS_MB of progress in # STALL_MINUTES => remove + blocklist + replacement search via the arr that tracks it. STALL_MINUTES=45 STALL_MIN_PROGRESS_MB=5 # Missing-article heuristics for actively downloading jobs only. These are # configurable thresholds, not proof that PAR2 cannot repair a job. STALL_MISSING_FRAC=0.12 STALL_MISSING_TRIED_FRAC=0.35 # Hard cap on stall/doomed removals per cycle — clears a wall of dead jobs one # by one instead of guessing about items that never got bandwidth. STALL_MAX_ACTIONS_PER_CYCLE=2 # --- notifications (optional; empty NOTIFY_URL keeps log-only behaviour) --- # Where digests are POSTed. Discord/Slack webhook URL, ntfy topic URL, # Gotify https://host/message, Apprise API notify URL, or your own endpoint. NOTIFY_URL= # discord | slack | ntfy | gotify | apprise | json NOTIFY_FORMAT=json # Optional. Bearer header for ntfy/apprise/json; X-Gotify-Key for gotify. NOTIFY_TOKEN= # Optional JSON object merged into every payload, e.g. {"username":"plungarr"} # for Discord, {"priority":8} for Gotify, {"urls":"..."} for stateless Apprise. # For ntfy the fields become request headers, e.g. {"Priority":"4","Tags":"tv"}. NOTIFY_EXTRA_JSON= # Per-category cadence: immediate | daily | weekly | monthly | none NOTIFY_ATTENTION=immediate NOTIFY_ERRORS=immediate NOTIFY_ACTIONS=daily NOTIFY_PROBLEMS=daily NOTIFY_CORRUPTION=weekly # Totals for the period (imported, replaced, discarded, ...) with no per-item lines. NOTIFY_SUMMARY=none # "plungarr alive" line even when nothing else happened. NOTIFY_HEARTBEAT=none # Digest schedule in the container's local time (set TZ on the container). NOTIFY_DIGEST_HOUR=8 NOTIFY_DIGEST_DAY=monday NOTIFY_DIGEST_DAY_OF_MONTH=1 # Re-send an attention item that is still unresolved after this many days. 0 = never. NOTIFY_REMIND_DAYS=7 # --- failure review (surface chronic search/grab failures from arr history) --- FAIL_REVIEW_ENABLED=true FAIL_REVIEW_HOURS=6 FAIL_REVIEW_WINDOW_HOURS=48 # An episode/movie with this many failed grabs in the window (and no import # since the last failure) gets a PROBLEM log line. Report-only, never acts. FAIL_REVIEW_FAIL_LIMIT=3 # --- corruption review (report-only; never deletes library files) --- CORRUPT_SWEEP_ENABLED=true # Hours between sweeps (first sweep runs at startup). CORRUPT_SWEEP_HOURS=24 # Small files and low estimated bitrates are inspection hints only. CORRUPT_STUB_MB=20 CORRUPT_MIN_KBPS=150 # Classifies missing-metadata reports by format. Never enables deletion. CORRUPT_ACT_EXTS=.mkv # Which suspect classes to report. Each suspect is reported once and again # only if it changes or after NOTIFY_REMIND_DAYS. # unreadable = CORRUPT_ACT_EXTS file with no media info (the real signal) # stub = tiny file with no media info # junk_readable = very low bitrate for its length # tiny_readable = small but readable; usually a legitimate short (opt-in) # scanner_blind = no media info in a format the scanner often skips (opt-in) CORRUPT_REPORT_CLASSES=unreadable,stub,junk_readable