Skip to content

feat: add Cacharr — rescue Riven items stuck in Scraped/Failed/Indexed via Prowlarr + RealDebrid#165

Open
rshearer1 wants to merge 3 commits intoI-am-PUID-0:devfrom
rshearer1:feature/cacharr-integration
Open

feat: add Cacharr — rescue Riven items stuck in Scraped/Failed/Indexed via Prowlarr + RealDebrid#165
rshearer1 wants to merge 3 commits intoI-am-PUID-0:devfrom
rshearer1:feature/cacharr-integration

Conversation

@rshearer1
Copy link
Copy Markdown

@rshearer1 rshearer1 commented Mar 19, 2026

Summary

Adds Cacharr as a first-class DUMB service — a daemon that rescues items stuck in Riven's Scraped, Failed, or Indexed states by independently searching Prowlarr for torrents and submitting them to RealDebrid to trigger server-side caching. Once RD finishes, Riven picks the item up automatically. Nothing downloads locally.

  • Web UI on port 8484 — live cycle progress, pending torrent queue with RD download bars, full resolve history, settings panel
  • Season-aware torrent selection — exact season match preferred, full-series pack as fallback, wrong-season rejected
  • Search-miss cooldown — exponential back-off (30 m → 1 h → 2 h → 4 h → 6 h max) after consecutive zero-result searches so dead-end shows don't burn Prowlarr quota
  • tried_hashes with 7-day TTL — hashes rejected by RD are automatically retried after a week
  • Stale RD content check — periodically verifies Completed items' RD torrents still exist; resets and re-queues if RD purged them
  • sync_library.py companion — scans the Radarr/Sonarr library for files already placed by Decypharr and marks matching Riven MediaItem records as Completed, preventing redundant re-scraping
  • Zero new runtime dependencies — uses only requests and psycopg2, both already present in DUMB's /venv

Files changed

File Change
cacharr/cacharr.py Main daemon (~2280 lines, self-contained)
cacharr/sync_library.py Optional Radarr/Sonarr → Riven bridge (226 lines)
utils/cacharr_settings.py Auto-injects Prowlarr API key and URL from config.xml / instance port on first start
utils/auto_update.py Post-start hook: runs patch_cacharr_config(), reloads fresh env before restart
utils/dependency_map.py cacharr depends on riven_backend
main.py cacharr added to grouped_keys (after riven_frontend)
utils/dumb_config.json Default cacharr config (disabled by default, port 8484)
utils/dumb_config_schema.json JSON schema for the cacharr config block (not in top-level required)
.env.example CACHARR_* env var documentation

Defaults

Cacharr is disabled by default. Enable it in the DUMB UI or via:

CACHARR_ENABLED=true

The Prowlarr API key and base URL are auto-injected from Prowlarr's config.xml and instance port on first start. The RealDebrid API key is read automatically from Riven's existing settings.json. Everything else runs on localhost defaults — no extra configuration needed for a standard DUMB setup.

Changes since initial commit (CodeRabbit review)

Issue Fix
cacharr in schema required[] breaks existing installs Removed from required — config validation no longer rejects older configs missing the key
_find_video nondeterministic (os.listdir order) Now sorts entries and filters sample/trailer/extras/featurette filenames before picking the main asset
Multi-episode filenames (S01E01E02, S01E01-03) only updated first episode New _extract_ep_nums() expands multi-episode and range tokens; loop iterates all episode numbers per file
Cacharr restarted with stale env snapshot (injected key missing) Reloads CONFIG_MANAGER.get("cacharr") after patch and merges into env before restarting; start_process return value now captured
Only PROWLARR_KEY injected, not PROWLARR_URL _discover_prowlarr() returns (api_key, base_url); both are injected when not already set so non-default ports work

Test plan

  • docker compose build && docker compose up -d — container starts without errors
  • Set CACHARR_ENABLED=true, confirm Cacharr process appears in DUMB UI
  • Confirm Cacharr web UI is reachable on port 8484
  • Confirm Prowlarr API key and URL are auto-injected (visible in Settings panel of web UI)
  • Confirm cacharr log appears at /log/cacharr.log
  • Confirm schema validates — no errors on DUMB startup related to cacharr config
  • Upgrade from existing config (no cacharr key) — confirm DUMB starts normally
  • CACHARR_ENABLED=false (default) — confirm DUMB starts normally without Cacharr

Related PRs

  • dmbdb frontend: nicocapalbo/dmbdb#164 — adds CACHARR service key enum and log parser so Cacharr appears in the DUMB UI with properly formatted logs

Context

This grew out of Discussion #164 where I shared Cacharr as a community tool after running it for ~2 months in my own DUMB setup (~370 items resolved, ~53% success rate). PUID-0 expressed interest in first-class integration, hence this PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added Cacharr service to sync existing media libraries into the backend.
    • Automatic discovery/injection of Prowlarr credentials to simplify Cacharr setup.
  • Chores

    • Added Cacharr config examples and schema entries.
    • Integrated Cacharr into startup dependency sequencing and added logic to patch and restart the service when needed.

Cacharr rescues items stuck in Riven's Scraped/Failed/Indexed states by
searching Prowlarr for torrents and adding them to RealDebrid to trigger
server-side caching, then resetting the item so Riven picks it up once
cached.  Nothing downloads locally — RD fetches from seeders to their
servers.

Changes:
- cacharr/cacharr.py  — main daemon (~2280 lines); season-aware torrent
  selection, search-miss cooldown with exponential back-off, tried-hash
  TTL, stale-RD-content detection, and a web UI on port 8484
- cacharr/sync_library.py — optional companion that marks Riven items as
  Completed when the file already exists in the Radarr/Sonarr library
- utils/cacharr_settings.py — auto-injects Prowlarr API key from
  config.xml into Cacharr's env config on first start
- utils/auto_update.py — post-start hook: runs patch_cacharr_config()
  and restarts Cacharr if the Prowlarr key was freshly injected
- utils/dependency_map.py — cacharr depends on riven_backend
- main.py — cacharr added to grouped_keys (after riven_frontend)
- utils/dumb_config.json — default cacharr config (disabled by default)
- utils/dumb_config_schema.json — schema for cacharr config block
- .env.example — CACHARR_* env var documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rshearer1 rshearer1 requested a review from I-am-PUID-0 as a code owner March 19, 2026 13:45
@I-am-PUID-0 I-am-PUID-0 self-assigned this Mar 19, 2026
@I-am-PUID-0
Copy link
Copy Markdown
Owner

GitKraken automatically performed 2 actions

Create your own automations at gitkraken.dev/automations

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 19, 2026

📝 Walkthrough

Walkthrough

Adds a new Cacharr service: environment/schema entries, startup integration and dependency mapping, Prowlarr credential injection with automatic restart, and a filesystem-to-database library sync script that marks MediaItems completed with symlink metadata.

Changes

Cohort / File(s) Summary
Environment & Config
\.env.example, utils/dumb_config.json, utils/dumb_config_schema.json
Add Cacharr configuration and schema: enable flag, process name, logging controls, port (8484), command, config/log paths, env vars (PROWLARR_URL, PROWLARR_KEY, DB_DSN, UI_PORT), and required fields in the cacharr schema.
Library Sync Module
cacharr/sync_library.py
New module scanning MOVIES/SHOWS dirs for {imdb-tt...}, selecting video files, extracting episode numbers, querying MediaItem/Season/Episode, and marking items Completed with symlink metadata via a parameterized UPDATE. Exposes sync_movies, sync_episodes, sync_all, and connection helper.
Prowlarr Auto-injection
utils/cacharr_settings.py
New helper to discover Prowlarr instances (parse config.xml), extract ApiKey/base URL, and patch_cacharr_config() to inject PROWLARR_KEY (and PROWLARR_URL if blank) into Cacharr config; returns (patched, error).
Process Startup & Auto-update
main.py, utils/auto_update.py, utils/dependency_map.py
Register cacharr in grouped startup keys, add post-start logic to call patch_cacharr_config() and restart Cacharr when patched, and add cacharr -> {riven_backend} to conditional dependency map.
Examples & Schema
utils/dumb_config.json, utils/dumb_config_schema.json
Add example config and JSON schema entries for the cacharr service (command, platforms, config paths, env) with cacharr object required fields.

Sequence Diagram

sequenceDiagram
    participant FS as Radarr/Sonarr Folders
    participant Sync as Cacharr Sync Script
    participant DB as Riven PostgreSQL
    participant Config as Cacharr Process/Config

    FS->>Sync: Enumerate movie/show folders\nExtract {imdb-tt...}, seasons, files
    Sync->>DB: Query MediaItem / Season / Episode by ids
    DB-->>Sync: Return records
    alt Item not already completed+symlinked
        Sync->>Sync: Resolve real file & folder (follow symlink)
        Sync->>DB: UPDATE MediaItem set last_state='Completed', symlinked=true,\nsymlinked_at=now(), symlink_path=..., file=..., folder=...
        DB-->>Sync: Commit
    end
    note right of Config: On service start, patch_cacharr_config() may inject\nPROWLARR_KEY and trigger Config restart
    Config->>Config: Restart when config patched
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through folders late at night,
Found little files by folder-light,
Prowlarr keys tucked safe and neat,
Marked each episode with a happy beat,
Hopped home, database feeling right.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main purpose of the pull request: adding Cacharr as a service to rescue Riven items stuck in certain states using Prowlarr and RealDebrid integration.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
utils/dumb_config_schema.json (1)

3520-3548: ⚠️ Potential issue | 🔴 Critical

Don't require cacharr during config validation yet.

CONFIG_MANAGER._load_and_validate_config() validates the persisted config before any default merge/migration runs. Existing installs upgrading from a config file that predates this service will now fail startup because the top-level cacharr key is missing, even though the service is disabled by default.

Suggested fix
   "required": [
     "puid",
     "pgid",
     "tz",
     "data_root",
     "dumb",
     "traefik",
     "cli_debrid",
     "cli_battery",
     "decypharr",
     "nzbdav",
     "emby",
     "jellyfin",
     "phalanx_db",
     "plex",
     "tautulli",
     "neutarr",
     "seerr_sync",
     "profilarr",
     "seerr",
     "plex_debrid",
     "postgres",
     "pgadmin",
     "prowlarr",
     "radarr",
     "rclone",
     "riven_backend",
     "riven_frontend",
-    "cacharr",
     "sonarr",
     "whisparr",
     "zilean",
     "zurg"
   ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/dumb_config_schema.json` around lines 3520 - 3548, The JSON schema
currently lists "cacharr" in the top-level "required" array causing
CONFIG_MANAGER._load_and_validate_config() to reject older configs; remove
"cacharr" from the required array in utils/dumb_config_schema.json (or make it
optional) so validation no longer fails when that top-level key is absent,
ensuring the existing merge/migration logic that adds defaults for the riven
services can run normally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cacharr/sync_library.py`:
- Line 114: The current ep_re only captures a single episode (first E##) so
filenames like S01E01E02 or S01E01-02 leave subsequent episodes unresolved;
update the logic around ep_re to extract all episode numbers by using a regex
that finds all episode tokens (e.g., multiple E## occurrences and ranges like
E01-03), then expand ranges into individual episode numbers and iterate over
them when marking files/records (update the variable ep_re and the code paths
that consume it in the block using ep_re and the code between the original ep_re
usage and the handling in lines ~170-198); ensure you replace single-match logic
with re.findall and range-expansion so every episode from the filename is
processed.
- Around line 45-59: _find_video currently returns the first video from
os.listdir() which is nondeterministic and can pick samples/trailers; change it
to collect all files in folder_path whose extensions are in VIDEO_EXTS, filter
out filenames containing keywords like "sample" or "trailer" (case-insensitive),
and if multiple candidates remain choose the most likely main asset by selecting
the largest file (use os.path.getsize) with a deterministic tie-breaker (e.g.,
sort by name) before returning os.path.join(folder_path, chosen); still return
None if no valid candidate or if os.listdir raises OSError.

In `@utils/auto_update.py`:
- Around line 2202-2221: The restart logic for "cacharr" uses the pre-patch env
snapshot and discards the second start result, so the restarted process still
gets the old PROWLARR_KEY and failures are ignored; after calling
patch_cacharr_config() (which mutates CONFIG_MANAGER) rebuild the env (or
re-read PROWLARR_KEY from CONFIG_MANAGER) before calling
process_handler.start_process, call stop_process first, then capture and return
the result/tuple from the second process_handler.start_process invocation
(instead of discarding it) so failures are propagated; keep the existing
shutting_down check around the flow and reference patch_cacharr_config,
CONFIG_MANAGER, PROWLARR_KEY, process_handler.stop_process and
process_handler.start_process when making the change.

In `@utils/cacharr_settings.py`:
- Around line 57-64: The code injects PROWLARR_KEY via _read_prowlarr_api_key()
but doesn't set PROWLARR_URL, so a non-standard local port is ignored; update
the logic that calls _read_prowlarr_api_key() to also discover or return the
local Prowlarr base URL (e.g., add or use a helper like _discover_prowlarr_url()
or have _read_prowlarr_api_key() return both key and url) and include
"PROWLARR_URL": discovered_url when calling CONFIG_MANAGER.update("cacharr",
{"env": {**env, "PROWLARR_KEY": api_key, "PROWLARR_URL": discovered_url}}) so
the injected key and correct URL are both persisted.

---

Outside diff comments:
In `@utils/dumb_config_schema.json`:
- Around line 3520-3548: The JSON schema currently lists "cacharr" in the
top-level "required" array causing CONFIG_MANAGER._load_and_validate_config() to
reject older configs; remove "cacharr" from the required array in
utils/dumb_config_schema.json (or make it optional) so validation no longer
fails when that top-level key is absent, ensuring the existing merge/migration
logic that adds defaults for the riven services can run normally.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e9bed70-fc16-4b53-9556-5919a2ad6902

📥 Commits

Reviewing files that changed from the base of the PR and between 8b4a7a9 and 2392a1a.

📒 Files selected for processing (9)
  • .env.example
  • cacharr/cacharr.py
  • cacharr/sync_library.py
  • main.py
  • utils/auto_update.py
  • utils/cacharr_settings.py
  • utils/dependency_map.py
  • utils/dumb_config.json
  • utils/dumb_config_schema.json

- dumb_config_schema.json: remove cacharr from top-level required list
  so existing configs without the key don't fail startup validation

- sync_library.py: _find_video now sorts entries and filters out
  sample/trailer/extras filenames before picking the main asset, falling
  back to the first video alphabetically if all files match the junk
  pattern; add _extract_ep_nums helper and update sync_episodes to
  iterate all episode numbers from multi-episode filenames (S01E01E02,
  S01E01-03 ranges) so every episode record gets marked Completed

- auto_update.py: after patch_cacharr_config() mutates CONFIG_MANAGER,
  reload the fresh env dict before restarting so the relaunched process
  receives the injected PROWLARR_KEY instead of the pre-patch snapshot;
  also capture the start_process return value so a failed restart is
  not silently swallowed

- cacharr_settings.py: rename _read_prowlarr_api_key to _discover_prowlarr
  which now returns (api_key, base_url); patch_cacharr_config injects
  PROWLARR_URL alongside PROWLARR_KEY so a non-default Prowlarr port is
  automatically picked up

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
utils/cacharr_settings.py (1)

35-35: Consider hardened XML parsing for security: defusedxml is not currently a declared dependency.

Line 35 uses stdlib xml.etree.ElementTree, which is vulnerable to XML bomb attacks (Billion Laughs, Quadratic blowup). Narrower exception handling is also recommended at line 39. If defusedxml is added as a dependency, update:

  • Import: from defusedxml import ElementTree as ET
  • Exception handler: except (ET.ParseError, OSError, ValueError) as exc:

Note: The same pattern exists in multiple files (prowlarr_settings.py, plex_settings.py, emby_settings.py, etc.).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/cacharr_settings.py` at line 35, Replace usage of xml.etree.ElementTree
with defusedxml's safe parser by changing the import to "from defusedxml import
ElementTree as ET" and update the error handling around ET.parse(config_file)
(the ET.parse call) to catch the narrower tuple of exceptions "ET.ParseError,
OSError, ValueError" (i.e., use except (ET.ParseError, OSError, ValueError) as
exc). Apply the same change pattern to the other modules that call ET.parse such
as prowlarr_settings.py, plex_settings.py, and emby_settings.py so all XML
parsing is hardened.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@utils/cacharr_settings.py`:
- Around line 26-28: The code assumes CONFIG_MANAGER.get("prowlarr") and nested
values are dicts and directly calls instances.items() and env.get(...), which
can raise AttributeError if the config shape is wrong; update the prowlarr
handling around prowlarr_cfg and instances to validate types (e.g., check
isinstance(prowlarr_cfg, dict) and isinstance(instances, dict) and default to {}
when not) and before using env.get(...) validate env is a dict (or coerce via
dict(env) safely) so that calls to instances.items() and env.get(...) are
guarded against malformed config values.

---

Nitpick comments:
In `@utils/cacharr_settings.py`:
- Line 35: Replace usage of xml.etree.ElementTree with defusedxml's safe parser
by changing the import to "from defusedxml import ElementTree as ET" and update
the error handling around ET.parse(config_file) (the ET.parse call) to catch the
narrower tuple of exceptions "ET.ParseError, OSError, ValueError" (i.e., use
except (ET.ParseError, OSError, ValueError) as exc). Apply the same change
pattern to the other modules that call ET.parse such as prowlarr_settings.py,
plex_settings.py, and emby_settings.py so all XML parsing is hardened.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91590c73-e309-4f57-9c6d-fd043df118be

📥 Commits

Reviewing files that changed from the base of the PR and between 2392a1a and 5a55d67.

📒 Files selected for processing (4)
  • cacharr/sync_library.py
  • utils/auto_update.py
  • utils/cacharr_settings.py
  • utils/dumb_config_schema.json
✅ Files skipped from review due to trivial changes (2)
  • utils/auto_update.py
  • cacharr/sync_library.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • utils/dumb_config_schema.json

- Add isinstance(instances, dict) guard in _discover_prowlarr() to handle
  unexpected config shapes gracefully
- Add isinstance(env, dict) guard in patch_cacharr_config() with warning log
- Rename inst_key to _inst_key (ruff B007 - unused loop variable)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
utils/cacharr_settings.py (1)

26-27: ⚠️ Potential issue | 🟠 Major

Guard prowlarr_cfg type before nested dict access

prowlarr_cfg.get("instances") can still throw if CONFIG_MANAGER.get("prowlarr") is not a dict. Line 26 should validate shape first.

Suggested fix
-    prowlarr_cfg = CONFIG_MANAGER.get("prowlarr") or {}
-    instances = prowlarr_cfg.get("instances") or {}
+    prowlarr_cfg = CONFIG_MANAGER.get("prowlarr") or {}
+    if not isinstance(prowlarr_cfg, dict):
+        logger.warning("Cacharr: invalid prowlarr config type: %s", type(prowlarr_cfg).__name__)
+        return "", ""
+    instances = prowlarr_cfg.get("instances") or {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/cacharr_settings.py` around lines 26 - 27, Validate that the value
returned by CONFIG_MANAGER.get("prowlarr") is a dict before calling .get on it:
replace the direct nested access using prowlarr_cfg.get("instances") with a
guarded check (e.g., if not isinstance(prowlarr_cfg, dict): prowlarr_cfg = {})
then assign instances = prowlarr_cfg.get("instances", {}) so that prowlarr_cfg
and the variable names prowlarr_cfg and instances are protected from non-dict
types and you avoid AttributeError during nested dict access.
🧹 Nitpick comments (1)
utils/cacharr_settings.py (1)

42-42: Narrow broad exception handlers to expected failure types

Lines 42 and 94 catch Exception, which masks unrelated failures. Catch expected exception types (ET.ParseError, OSError, and concrete config-write exceptions) and log context.

Also applies to: 94-94

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/cacharr_settings.py` at line 42, Replace the two broad "except
Exception as exc:" handlers in cacharr_settings.py (the one around the XML
parsing logic and the one around the config-write block) with narrow exception
clauses that only catch expected failures — for XML parsing use ET.ParseError,
for filesystem or IO issues use OSError (or more specific
IOError/FileNotFoundError as appropriate), and for config-write operations catch
the concrete exception(s) raised by your config writer; update the corresponding
processLogger.error calls to handle the specific exception variable so context
is preserved. Ensure you do not swallow other exceptions by letting unexpected
exceptions propagate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@utils/cacharr_settings.py`:
- Line 89: CONFIG_MANAGER.update(...) is not defined; use the provided
ConfigManager.set method instead. Replace the call to
CONFIG_MANAGER.update("cacharr", {"env": {**env, **updates}}) with a call to
CONFIG_MANAGER.set using the same key and merged env payload (i.e., invoke
ConfigManager.set("cacharr", {"env": {**env, **updates}}) so the settings are
persisted correctly). Verify the symbol CONFIG_MANAGER and method set(...) are
used consistently in cacharr_settings.py.
- Line 38: Replace the insecure xml.etree.ElementTree usage with defusedxml's
hardened parser: change the module import (where ET is currently from
xml.etree.ElementTree) to from defusedxml import ElementTree as ET and keep the
existing ET.parse(config_file) call in utils/cacharr_settings.py; ensure any
other usages of ET in that module remain compatible, and add defusedxml to
project dependencies (requirements/pyproject) so the secure parser is installed.

---

Duplicate comments:
In `@utils/cacharr_settings.py`:
- Around line 26-27: Validate that the value returned by
CONFIG_MANAGER.get("prowlarr") is a dict before calling .get on it: replace the
direct nested access using prowlarr_cfg.get("instances") with a guarded check
(e.g., if not isinstance(prowlarr_cfg, dict): prowlarr_cfg = {}) then assign
instances = prowlarr_cfg.get("instances", {}) so that prowlarr_cfg and the
variable names prowlarr_cfg and instances are protected from non-dict types and
you avoid AttributeError during nested dict access.

---

Nitpick comments:
In `@utils/cacharr_settings.py`:
- Line 42: Replace the two broad "except Exception as exc:" handlers in
cacharr_settings.py (the one around the XML parsing logic and the one around the
config-write block) with narrow exception clauses that only catch expected
failures — for XML parsing use ET.ParseError, for filesystem or IO issues use
OSError (or more specific IOError/FileNotFoundError as appropriate), and for
config-write operations catch the concrete exception(s) raised by your config
writer; update the corresponding processLogger.error calls to handle the
specific exception variable so context is preserved. Ensure you do not swallow
other exceptions by letting unexpected exceptions propagate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00851817-0f4a-4f97-8fa2-9b4075edc2a4

📥 Commits

Reviewing files that changed from the base of the PR and between 5a55d67 and 17f7e3e.

📒 Files selected for processing (1)
  • utils/cacharr_settings.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants