Release Notes — Resource Optimization & Scheduler Fixes
🧠 RAM Optimization — Media Hunt Disable Fully Stops Background Processes
Disabling Media Hunt in General Settings now completely halts all related background activity, reducing RAM usage to near-zero for those subsystems.
What's gated by enable_media_hunt = false:
| Component | Before | After |
|---|---|---|
| NZB Hunt child process | Stayed alive, respawned on crash | Immediately killed, blocked from respawning |
| NZB Hunt idle watcher thread | Ran every 60s unconditionally | Checks flag → kills child if disabled, does no work |
| Tor Hunt child process | Stayed alive, respawned on crash | Immediately killed, blocked from respawning |
| Tor Hunt idle watcher thread | Ran every 60s unconditionally | Checks flag → kills child if disabled, does no work |
| Indexer Hunt health check | Made network calls every hour | Skips all work (including network calls) when disabled |
| Movie Hunt / TV Hunt background loops | Ran full processing cycles | Skips entirely, sleeps 60s between checks |
Files Modified:
src/primary/apps/nzb_hunt/download_process.py— Added_media_hunt_enabled()check to_ensure_alive()and_start_idle_watcher()src/primary/apps/tor_hunt/tor_hunt_process.py— Added_media_hunt_enabled()check to_ensure_alive()and_start_idle_watcher()src/primary/routes/indexer_hunt/health.py— Gated_health_check_loop()behindenable_media_huntflagsrc/primary/background.py— Skipsmovie_huntandtv_huntprocessing cycles when disabled
Key Design Decision:
All checks use load_settings("general", use_cache=False) to bypass the 30-second settings cache, ensuring toggles take effect immediately without restarting.
🚫 P2P Disabled by Default (Tor Hunt)
Tor Hunt's P2P functionality is now disabled by default on new installs via the enable_p2p setting.
Behavior:
enable_p2pdefaults toFalsewhen the setting is missing- When disabled:
TorHuntManager._p2p_enabled()returnsFalse- No torrent child process is spawned
- No libtorrent sessions are created
- Zero RAM overhead from torrent subsystem
- Uses
use_cache=Falsefor immediate toggle effect
Files Modified:
src/primary/apps/tor_hunt/tor_hunt_manager.py—_p2p_enabled()defaults toFalse, reads fresh from DB
🔒 Requestarr API Gate — enable_requestarr Now Enforced Backend
Previously, disabling Requests in General Settings only hid the sidebar link. All API endpoints remained fully accessible.
Now:
- All
/api/requestarr/*routes return HTTP 503 with{"disabled": true}whenenable_requestarrisfalse - Non-requestarr routes (like
/api/settings/feature-flags) are not affected - Re-enabling restores full API access immediately
Implementation:
Uses app.before_request() with a path check — avoids Flask's restriction on modifying blueprints after registration.
Files Modified:
src/primary/web_server.py— Added_requestarr_gate()as app-levelbefore_requesthandler
📅 Scheduler Fixes — Per-Instance Schedules for All Apps
Fixed a critical bug where per-instance schedules for Whisparr, Eros, and all other apps were silently being saved as "Global Apps" and lost on page refresh.
Root Cause (3 layers):
-
Race condition on page load — Two competing
populateInstanceDropdownfunctions existed: an inline script (fires at DOM parse time, before settings loaded) and a JS module (fires after async fetch). The inline version always ran first with empty data, setting the hiddenscheduleAppfield toglobal. -
Async dropdown overwrite — Every navigation to the Scheduling section triggered
refreshSchedulingInstances(), which rebuilt the instance dropdown from scratch and destroyed the user's current selection. -
Bundle out of sync — The compiled
bundle-features.jshad the old code baked in without fixes.
Fixes Applied:
| Fix | Description |
|---|---|
| Event-driven re-population | After async settings fetch completes, dispatches huntarr:scheduler-instances-ready event. The inline script listens for it and re-populates with real data.
|
| Selection preservation | populateInstanceDropdown() now saves previousVal before clearing options, then restores it after rebuild. Prevents async refresh from resetting user's choice.
|
addSchedule DOM fallback
| If the hidden scheduleApp field is stale/global but the visible dropdown shows a non-global app, re-derives the values from live DOM elements.
|
deleteSchedule cross-bucket search
| If a schedule isn't found in the expected bucket (legacy misroute), searches ALL buckets before giving up. Prevents silent delete failures. |
| Memory leak fix | last_executed_actions dict now prunes stale date-keyed entries from previous days each scheduler cycle, preventing unbounded growth.
|
Apps Affected (all fixed):
Sonarr, Radarr, Lidarr, Readarr, Whisparr, Eros, Movie Hunt, TV Hunt
Files Modified:
frontend/static/js/modules/features/scheduling.js— All frontend fixesfrontend/static/js/dist/bundle-features.js— Bundle kept in syncfrontend/templates/components/scheduling_section.html— Inline script fixessrc/primary/scheduler_engine.py— Memory leak fix in `check_and_execute_schedules()