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
This commit is contained in:
@@ -33,10 +33,15 @@
|
||||
# movie file → delete (the arr already refused it as not-an-upgrade)
|
||||
# IMPORTABLE — parse API matches it but the library is missing episodes / the movie
|
||||
# → trigger DownloadedEpisodesScan/DownloadedMoviesScan on the folder and
|
||||
# leave it; whatever imports gets swept as REDUNDANT next week, whatever
|
||||
# leave it; whatever imports gets swept as REDUNDANT next run, whatever
|
||||
# the arr rejects (XEM-blocked, season-span files) stays HELD for a human
|
||||
# HELD — parse API can't match it (series/movie not in the arr) → report only,
|
||||
# deciding whether to add the series or bin the files is a human call
|
||||
# UNMATCHED — parse API can't match it (series/movie not in the arr) → delete. Past the
|
||||
# age gate an entry the arr cannot even name is not going to import: if the
|
||||
# title is in the library and monitored, clearing it lets the arr search a
|
||||
# copy it can actually parse; if it is not in the library, nothing is
|
||||
# tracking it and it is dead weight either way. Guarded — see safeguard 6
|
||||
# HELD — IMPORTABLE entries the arr keeps refusing (XEM-blocked, season-span
|
||||
# files), and everything skipped by a guard → report only, human call
|
||||
#
|
||||
# The queue fetch is a hard gate: if it fails, the whole arr is skipped — with no queue
|
||||
# there is no way to tell tracked from orphaned, and guessing means deleting active imports.
|
||||
@@ -49,8 +54,14 @@
|
||||
# 2. Download dir must exist and live under /mnt/ — refuses to walk anything else
|
||||
# 3. Queue fetch must succeed (see above)
|
||||
# 4. Age gate — nothing under DOWNLOAD_ORPHAN_AGE days is touched
|
||||
# 5. Deletion only for JUNK and parse-verified REDUNDANT — never for HELD/IMPORTABLE
|
||||
# 6. Run total over DOWNLOAD_ORPHAN_MAX_DELETE_GB aborts the delete pass and notifies —
|
||||
# 5. Deletion only for JUNK, parse-verified REDUNDANT, and UNMATCHED — never for
|
||||
# IMPORTABLE or anything a guard has held
|
||||
# 6. UNMATCHED deletes require the arr to report a non-empty library. An empty or
|
||||
# restoring database answers every parse with "no match", which would condemn the
|
||||
# entire download dir; the library is queried directly rather than inferred from the
|
||||
# run's own matches, since a small batch that is legitimately all-unmatched is normal
|
||||
# once daily runs have caught up and would otherwise read as a broken database
|
||||
# 7. Run total over DOWNLOAD_ORPHAN_MAX_DELETE_GB aborts the delete pass and notifies —
|
||||
# a queue fetch that returned partial data would classify live downloads as orphans,
|
||||
# and an abnormally large delete total is the visible symptom of exactly that
|
||||
# (--i-know-what-im-doing overrides, e.g. for a first run against a known backlog)
|
||||
@@ -157,10 +168,12 @@ for arr in sonarr radarr; do
|
||||
queue_endpoint="queue?pageSize=1000&includeUnknownSeriesItems=true"
|
||||
exts_var="SONARR_EXTENSIONS"
|
||||
scan_command="DownloadedEpisodesScan"
|
||||
library_endpoint="series"
|
||||
else
|
||||
queue_endpoint="queue?pageSize=1000&includeUnknownMovieItems=true"
|
||||
exts_var="RADARR_EXTENSIONS"
|
||||
scan_command="DownloadedMoviesScan"
|
||||
library_endpoint="movie"
|
||||
fi
|
||||
|
||||
QUEUE_JSON=$(arr_api "$arr_url" "$arr_key" "v3" "$queue_endpoint" "${arr^}") || {
|
||||
@@ -179,6 +192,8 @@ for arr in sonarr radarr; do
|
||||
DELETE_SIZES=()
|
||||
DELETE_LABELS=()
|
||||
SCAN_PATHS=()
|
||||
UNMATCHED_PATHS=()
|
||||
UNMATCHED_SIZES=()
|
||||
arr_tracked=0; arr_recent=0; arr_held=0; arr_delete_mb=0
|
||||
|
||||
while IFS= read -r entry; do
|
||||
@@ -231,8 +246,8 @@ for arr in sonarr radarr; do
|
||||
fi
|
||||
|
||||
if [[ "$matched" != true ]]; then
|
||||
echo " $ICON_WARN HELD (no match in ${arr^}): $base (${size_mb}M)"
|
||||
arr_held=$((arr_held + 1))
|
||||
UNMATCHED_PATHS+=("$entry")
|
||||
UNMATCHED_SIZES+=("$size_mb")
|
||||
elif (( missing == 0 )); then
|
||||
DELETE_PATHS+=("$entry")
|
||||
DELETE_SIZES+=("$size_mb")
|
||||
@@ -244,6 +259,27 @@ for arr in sonarr radarr; do
|
||||
fi
|
||||
done < <(find "$dl_dir" -mindepth 1 -maxdepth 1 2>/dev/null)
|
||||
|
||||
# An arr with an empty or still-restoring database answers every parse with "no match",
|
||||
# which would turn the whole download dir into UNMATCHED and delete it. Confirm the
|
||||
# library actually holds titles before trusting a no-match to mean what it says. This
|
||||
# has to be asked of the arr directly — inferring health from the run's own matches
|
||||
# fails on a small batch that is legitimately all-unmatched, which is the normal case
|
||||
# once daily runs have caught up.
|
||||
if (( ${#UNMATCHED_PATHS[@]} > 0 )); then
|
||||
library_count=$(arr_api "$arr_url" "$arr_key" "v3" "$library_endpoint" "${arr^}" | jq 'length' 2>/dev/null)
|
||||
if [[ ! "$library_count" =~ ^[0-9]+$ ]] || (( library_count == 0 )); then
|
||||
warn " ${arr^}: library reports ${library_count:-no} titles — cannot trust 'no match', holding ${#UNMATCHED_PATHS[@]} unmatched"
|
||||
arr_held=$((arr_held + ${#UNMATCHED_PATHS[@]}))
|
||||
else
|
||||
for i in "${!UNMATCHED_PATHS[@]}"; do
|
||||
DELETE_PATHS+=("${UNMATCHED_PATHS[$i]}")
|
||||
DELETE_SIZES+=("${UNMATCHED_SIZES[$i]}")
|
||||
DELETE_LABELS+=("UNMATCHED")
|
||||
arr_delete_mb=$((arr_delete_mb + UNMATCHED_SIZES[i]))
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( arr_delete_mb / 1024 > DOWNLOAD_ORPHAN_MAX_DELETE_GB )) && [[ "$I_KNOW" != true ]]; then
|
||||
error "${arr^}: delete total $((arr_delete_mb / 1024))G exceeds cap of ${DOWNLOAD_ORPHAN_MAX_DELETE_GB}G — aborting delete pass"
|
||||
notify "${arr^} download orphan delete total $((arr_delete_mb / 1024))G exceeds ${DOWNLOAD_ORPHAN_MAX_DELETE_GB}G cap on $(hostname) — possible partial queue data, nothing deleted. Re-run with --i-know-what-im-doing if legitimate." \
|
||||
|
||||
Reference in New Issue
Block a user