Commit Graph
796 Commits
Author SHA1 Message Date
Gmer4Lfe cdce877601 Add a second GPU card to the monitor page
The 3080 was invisible because the stats parser only ever described GPU 0.
2026-08-01 20:37:58 -04:00
Gmer4Lfe 77b24e9823 Resolve network watchdog host config after detect_hosts
MY_ID is not exported and is unset until detect_hosts runs, so the DDNS and NPM checks
were silently resolving empty config and skipping themselves every cycle.
2026-08-01 20:37:58 -04:00
Gmer4Lfe 3f5ad22632 Only apply --delete on merge-run when the pull pass completed
A capped or failed pull leaves the remote holding content the local never received, so
deleting against it destroys the only copy.
2026-08-01 20:37:58 -04:00
Gmer4Lfe ce580d9935 Remove dead rc.emhttp mapping from adapter.sh
No such rc.d service exists on Unraid (emhttpd isn't managed via a
standalone rc.emhttp script) and nothing in the codebase calls
platform_restart_service/platform_stop_service with 'emhttp' — confirmed
during a post-7.3.2-upgrade audit of all platform-specific paths.
2026-08-01 11:49:05 -04:00
Gmer4Lfe 3ae24939cc Fix array-stop event hook folder name (disks_unmounting -> unmounting_disks)
Unraid's real event name is unmounting_disks, not disks_unmounting — the
mismatch meant emhttp_event never found this hook, so array_stopping.sh
never ran on real array stop.
2026-08-01 11:41:39 -04:00
Gmer4Lfe 7162f16c1a Correct docs that placed lidarr_missing_art in the 4-hour tier when it runs daily 2026-07-28 18:51:13 -04:00
Gmer4Lfe 19a9f6410d Cache fanart.tv misses so the nightly art run stops re-querying artwork upstream has never had 2026-07-28 18:51:06 -04:00
Gmer4Lfe a1db8f7b2d Restore executable bit on the three arr cleanup scripts 2026-07-27 18:38:46 -04:00
Gmer4Lfe d680bd0549 Gate arr orphan deletion on ctime and stop the nightly permissions pass from restamping it — imports preserve the release's original mtime, so the age gate never actually fired for real content 2026-07-27 18:38:18 -04:00
Gmer4Lfe 3084546b32 Delete download orphans the arr cannot match instead of holding them forever — past the age gate an unnameable entry will never import, and clearing it lets a monitored title search for a copy the arr can parse 2026-07-27 17:38:49 -04:00
Gmer4Lfe 74ea1a5218 Run the download orphan cleaner daily — a weekly batch of newly-eligible orphans can exceed the delete cap, which aborts the whole pass and rolls the backlog into an even larger next run 2026-07-27 17:24:40 -04:00
Gmer4Lfe 7505bffcee Play state sync: replace per-item date-fork and PLAY_SYNC_DAYS window with jq epoch parsing and a response-hash change probe that skips the full comparison when nothing changed since the last run 2026-07-26 19:10:02 -04:00
Gmer4Lfe 0061ddef72 Update rsync docs: emby-fallback profile removed, Emby watch state now synced by play_state_sync.sh 2026-07-26 11:10:35 -04:00
Gmer4Lfe 19036621dc Remove dangling emby-fallback example from host critical-sync template 2026-07-26 10:57:09 -04:00
Gmer4Lfe d96ddc8649 Condense conf redundancy: drop dead emby-fallback profile, no-op PROFILE_RETRY_COUNT, and default-valued profile rows; compose MEDIA patterns and Radarr protected patterns by reference 2026-07-26 10:51:31 -04:00
Gmer4Lfe 895347f20f Add weekly download orphan cleaner — nothing covered the SAB Completed folders and 755G of orphans accumulated since 2022 2026-07-26 09:55:17 -04:00
Gmer4Lfe 5e92d9920a Add Radarr/Movies coverage to arr_corruption_scan.sh
Extends the Sonarr-only corruption scan into a generic per-arr loop (same
pattern as arr_full_rescan.sh) instead of a second script, since the
scan/strike/remediate logic is identical and only the API shape differs.
Radarr's moviefile list is fetched batched to include secondary/alternate-
edition files, not just each movie's primary file.

Also fixes two bugs found while testing: build_arr_path_map()'s internal
non-local `for key in ...` loop was clobbering the per-arr API key
variable, and arr_api()'s error output (stdout, not stderr) was getting
appended into the batch fetch file on any single failed call, corrupting
jq's parse of the whole batch and silently zeroing out that arr's results.
2026-07-21 18:05:26 -04:00
Gmer4Lfe b2d6e1bcfd Fix Emby/critical-data never restarting in weekly sync window
stop_local_containers() reads LOCAL_CRITICAL_CONTAINER_NAMES, which was
never set here — only rsync.sh sets it, in a child process that can't
propagate back. Local stop always no-op'd, so the rebuild-on-new-image
step never had anything to act on.
2026-07-21 16:50:38 -04:00
Gmer4Lfe 35f870c650 Auto-prune skip-list/intentional-stop entries for uninstalled containers
Neither remove_from_skip_list() nor clear_intentional_stop() can ever
fire for a container that's been fully uninstalled — both only trigger
on seeing it running again. Confirmed live 2026-07-19: Healarr sat on
the skip list nagging "manual intervention needed" every single cycle
for weeks after being removed. Now checks docker inspect for each
entry every cycle and drops it automatically if the container no
longer exists at all.
2026-07-19 17:22:35 -04:00
Gmer4Lfe de12c1fada Widen unraid-api key lookup timeout to stop false "renewed" alarms
Measured live: the apikey --name lookup takes 2.2-2.7s baseline with
the system idle, against a 5s timeout that left almost no margin.
Load spikes (confirmed correlated with resource_watchdog pressure
events in the same log window) pushed it over 5s, and the script
couldn't distinguish "timed out" from "genuinely missing" — it fell
through to the create path and logged a false renewal every time,
even though the on-disk key file's timestamp never actually changed.
Bumped to 15s for real headroom.
2026-07-19 17:20:09 -04:00
Gmer4Lfe ec518d4758 Prune stale chronic failure counts once an item stops being a problem
FAILURE_COUNTS persisted across runs but was never reset on success —
confirmed live 2026-07-19 that Sekirei S06E04 sat permanently flagged
chronic at count 4 despite already having hasFile=true. "Consecutive
failures" was really being measured as cumulative-for-all-time. Now
prunes any media_id's count at the end of each arr's pass if it no
longer appears in that run's problem-item set, so a resolved item's
history doesn't linger and falsely trip the circuit breaker later.
2026-07-19 17:00:15 -04:00
Gmer4Lfe 9425d16c19 Skip redundant restart for containers docker_update.sh already rebuilt
docker_update.sh rebuilds (stop+recreate) any container whose image
changed, in every mode — but for daily/weekly that was always followed
by the restart script's own unconditional pass, stopping and starting
the same container twice back to back. docker_update.sh now records
which containers it rebuilt this run to a file; docker_daily_restart.sh
and docker_weekly_restart.sh read it and skip those specifically,
still restarting everything else as before. A file older than
DOCKER_UPDATE_REBUILT_STALE_HOURS (default 12) is discarded rather
than trusted, so a missed or failed update run can't suppress a
restart indefinitely.
2026-07-19 16:09:55 -04:00
Gmer4Lfe 7252d4aad3 Fix try_smart_import() silently failing every ManualImport it fires
The candidate objects from /manualimport only nest ids under .series.id
and .movie.id, but Sonarr/Radarr's ManualImport command requires them
flattened to top-level seriesId/episodeIds or movieId — every call was
failing instantly with "Series/Movie with ID 0 does not exist" while the
caller only checked for HTTP 201 (accepted), so every "smart-imported"
this script has ever logged was actually a silent no-op. Now flattens
the ids before submitting and briefly polls the command afterward so a
fast failure falls through to the normal blocklist+research path instead
of being reported as success.
2026-07-19 10:36:37 -04:00
Gmer4Lfe 54919db13f Sync Sonarr/Radarr PROTECTED_PATTERNS template with live config
Template was missing theme.mkv/theme.mp4 and all trailer patterns,
including trailer-*.* for Trailarr's hyphenated TV trailer naming
(trailer-2.mkv) — a fresh install would hit the same false-positive
orphan bug just fixed live on prod.
2026-07-19 10:22:12 -04:00
Gmer4Lfe 2ce368abba Fix radarr_cleanup.sh missing secondary edition files as false-positive orphans
Radarr 6+ supports multiple tracked files per movie (alternate editions/extras),
but the movie list's embedded movieFile.path only ever reflects the primary one.
Relying on it alone flagged legitimately-tracked secondary edition files as
orphans. Now batch-fetches /moviefile?movieId=X across all tracked movies to
catch every file, not just the primary.
2026-07-19 10:04:47 -04:00
Gmer4Lfe 2a09529e75 Document expanded FFPROBE_PATH_MAP coverage pattern in host.conf.template 2026-07-18 23:28:09 -04:00
Gmer4Lfe efa2f2edf8 Schedule arr_corruption_scan.sh --remediate weekly in master.conf.template 2026-07-18 22:54:22 -04:00
Gmer4Lfe 004bde2c62 Add strike system to arr_corruption_scan.sh — require repeat corrupt detections before remediating 2026-07-18 22:50:19 -04:00
Gmer4Lfe e528d23c68 Add media-server auto-detection — pick Emby or Jellyfin by actual running state 2026-07-18 22:26:07 -04:00
Gmer4Lfe 43716a2c74 Fix trailers/ dir ownership+mode in trailer_folder_migration.sh 2026-07-18 21:43:21 -04:00
Gmer4Lfe a7bf45faaf Add trailer_folder_migration.sh — one-off tool to migrate TV trailers into trailers/ convention 2026-07-18 21:41:39 -04:00
Gmer4Lfe 77845829ad Add --filter to arr_corruption_scan.sh for targeted testing
Full-library scans are slow to reach any one show by chance — this lets a test
target a specific known-corrupt file/show without waiting on scan order.
2026-07-18 16:50:33 -04:00
Gmer4Lfe ab35fcd84d Add arr_corruption_scan.sh — sequential ffprobe-based corruption scan for Sonarr
Healarr does the same job but crashes on a Go concurrency bug (unsynchronized
map access) whenever multiple corruption events land close together — confirmed
via its own crash log, not fixable from our side. Processing one file at a time
here sidesteps the whole bug class instead of trying to work around it.

Delete + explicit EpisodeSearch rather than relying on Sonarr's own background
missing-search cycle, since that skips unmonitored episodes and this shouldn't.
2026-07-18 16:48:32 -04:00
Gmer4Lfe d5d1403ebf Raise Radarr cleanup safety threshold to 30GB
15GB was tripping on legitimate quality-upgrade orphan batches.
2026-07-18 12:05:21 -04:00
Gmer4Lfe 7bf47be106 Poll MoveMovie command to completion instead of trusting DB fields
Mirrors the Sonarr fix — same MoveMovieService one-at-a-time drain architecture,
never confirmed live on the Radarr side but the DB-instant/move-async split
is identical, so the same batch-verification race applies.
2026-07-17 23:00:08 -04:00
Gmer4Lfe 4f0cd1083a Poll MoveSeries command to completion instead of trusting DB fields
Confirmed live: DB fields flip instantly on the moveFiles=true PUT but the
physical move drains async, one command at a time — a batch could report
every series moved while most were still sitting at the old path.
2026-07-17 22:54:44 -04:00
Gmer4Lfe 1e1129687f Move arr_cache_prefill to intermediate tier, add classification scans to daily
arr_cache_prefill moved from critical (30min) to intermediate (4h) —
nothing in the critical tier reads this cache, and every actual
consumer already tolerates staleness well past 4h. Classification
scans run in daily, after the cleanup scripts (not before) — cleanup
frees disk space from orphans/junk first, so the searches --move
triggers for undownloaded relocated entries have headroom for the
resulting grabs.
2026-07-17 13:13:30 -04:00
Gmer4Lfe 79059c20fa Add --move mode to sonarr_classification_scan.sh, matching Radarr
Acts on forward misplacements and reverse-kids-leak (adult content in
the kids root — not a judgment call, same reasoning as the Radarr
side), moving to the new SONARR_GENERAL_ROOT config var. Reverse-anime
-leak stays report-only — deliberate style placements like Castlevania
are common and valid there. episodeFileCount is Sonarr's hasFile
equivalent: series with 0 files get relocated + an immediate
SeriesSearch instead of a file move. One series at a time, verified
after each — matches the race condition found doing this by hand for
the Fate/Zero and Fate/Stay Night moves earlier in the session.
2026-07-17 13:02:22 -04:00
Gmer4Lfe 9c05692a24 Include reverse-kids-leak in --move — it's not actually a judgment call
Unlike reverse-anime-leak (deliberate style placements like Castlevania
are common and valid there), reverse-kids-leak's signal is specifically
"adult certification with zero Family/Animation genre" — confirmed live
the 4 titles it catches (Addams Family, Saving Mr. Banks, Dark Shadows,
The DUFF) are all genuinely non-kids content. Moves them to the new
RADARR_GENERAL_ROOT config var (container-path literal for the general
Movies root, needed since RADARR_MOVIES_ROOT is a filesystem path).
2026-07-17 12:20:23 -04:00
Gmer4Lfe e688500cf5 Add --remove-junk mode: delete + import-exclude bad-metadata entries
Junk entries have no release to blocklist and no file to delete —
only a bad monitored record with a thin/wrong TMDb match. Removes the
record and adds it to Radarr's import exclusion list, same mechanism
radarr_tmdb_removed.sh already uses, so the same bad match can't get
re-added by a future Overseerr request or list sync.
2026-07-17 12:15:55 -04:00
Gmer4Lfe 6f7bb8a6aa Relocate + trigger search for hasFile=false forward-misplacements
Instead of skipping monitored-but-undownloaded titles entirely,
correct their DB pointer (rootFolderPath/path) now so Radarr saves
under the right root whenever it grabs a release, and fire an
immediate MoviesSearch rather than waiting for the next scheduled
one. Junk entries stay excluded — nothing to search for there.
2026-07-17 12:11:30 -04:00
Gmer4Lfe 1777c56efa Refresh shared tracked-data cache after --move writes to avoid a stale-cache window for other scripts 2026-07-17 12:08:10 -04:00
Gmer4Lfe ca6f16bafb Exclude hasFile=false entries from move targets — nothing to physically move 2026-07-17 12:02:57 -04:00
Gmer4Lfe 46ddc55345 Add --move mode to radarr_classification_scan.sh
Acts only on forward misplacements (clear-cut anime/kids classified
content sitting outside its dedicated root) — reverse leaks and junk
entries stay report-only, since those need human judgment or a
different action (removal, not a move). One movie at a time with a
real re-fetch-and-verify after each, matching the race condition found
doing this by hand for Sonarr earlier in the session.
2026-07-17 11:58:28 -04:00
Gmer4Lfe 10d6f372b3 Widen Sonarr reverse-kids-leak to non-US adult certification scales 2026-07-17 11:53:39 -04:00
Gmer4Lfe de57f87b82 Fix reverse_kids_leak losing genre data after object field reduction in jq 2026-07-17 11:51:30 -04:00
Gmer4Lfe 9dbcdc0bd7 Add anime/kids content misclassification detection for Radarr and Sonarr
Overseerr lets users request content into the wrong root folder; these
new report-only scans classify every tracked movie/series (anime, kids,
regular) from metadata alone and flag mismatches against the actual
root folder, in both directions. Rules were validated against real
library data before being adopted — see the header comments in each
script and the master.conf notes above the curated lists.
2026-07-17 11:49:23 -04:00
Gmer4Lfe 6dc5c91f60 Use find -printf instead of per-file stat/basename in transcode_cleanup.sh
Same fix as the arr cleanup scripts today: find -printf gets file size
directly from find's own stat() during the walk (mtime already handled
by -mmin), and the dry-run log line's basename call is replaced with
parameter expansion. Header notes this can matter under real load --
"thousands of HLS segment files" per the existing lsof design principle
this mirrors, even though the ramdisk is empty right now (no active
transcode session to benchmark against directly).
2026-07-17 02:13:07 -04:00
Gmer4Lfe 587fae1539 Replace external basename with parameter expansion in matches_pattern_list
This turned out to be the actual dominant cost left in the cleanup
scripts' classification loop, hidden behind the stat/dirname forks fixed
earlier today -- called once per non-tracked file (most files in a
media library, since every protected sidecar counts). Measured: 47.3s
vs 1.65s for 10,000 calls (~28.6x), identical results confirmed via
spot check before switching. Only used by lidarr_cleanup.sh/
sonarr_cleanup.sh/radarr_cleanup.sh.
2026-07-17 02:02:22 -04:00
Gmer4Lfe d2e071dece Use find -printf instead of per-file stat fork in cleanup scripts
lidarr_cleanup.sh/sonarr_cleanup.sh/radarr_cleanup.sh each forked a
separate stat call per file during classification. find already has to
stat() every entry to know it's -type f, so -printf '%s %T@ %p' gets
size+mtime for free during the walk itself. Measured: 5.77s for all
175,954 files in the Lidarr music root (walk + stat combined) vs 85.98s
for stat alone on a 20K-file subset of the same library -- roughly 130x
faster per file, and collapses two passes into one. Verified path
parsing preserves spaces/parens/unicode exactly via read's trailing-
field capture before switching.
2026-07-17 01:52:30 -04:00