Add strike system to arr_corruption_scan.sh — require repeat corrupt detections before remediating

This commit is contained in:
Gmer4Lfe
2026-07-18 22:50:19 -04:00
parent e528d23c68
commit 004bde2c62
2 changed files with 56 additions and 2 deletions
+50 -2
View File
@@ -64,7 +64,13 @@
# container almost certainly mounts shares differently)
#
# master.conf
# CORRUPTION_SCAN_STATE_FILE — path to the clean-file skip-cache (default in DATA_DIR)
# CORRUPTION_SCAN_STATE_FILE — path to the clean-file skip-cache (default in DATA_DIR)
# CORRUPTION_SCAN_STRIKES_FILE — path to the consecutive-corrupt-detection counter (default
# in DATA_DIR), keyed by host path
# CORRUPTION_SCAN_STRIKE_LIMIT — consecutive corrupt detections required before --remediate
# acts on a file (default 2) — guards against a one-off
# ffprobe hiccup (mid-write file, NFS blip) triggering an
# unnecessary delete+re-search. Resets on a clean re-probe.
# SONARR_VERSION_MAJOR — reused from sonarr_cleanup.sh for the API version check
#
# ==============================================================================================
@@ -165,6 +171,36 @@ CORRUPTION_SCAN_STATE_FILE="${CORRUPTION_SCAN_STATE_FILE:-$DATA_DIR/corruption_s
mkdir -p "$(dirname "$CORRUPTION_SCAN_STATE_FILE")"
touch "$CORRUPTION_SCAN_STATE_FILE"
CORRUPTION_SCAN_STRIKES_FILE="${CORRUPTION_SCAN_STRIKES_FILE:-$DATA_DIR/corruption_scan_strikes.tsv}"
CORRUPTION_SCAN_STRIKE_LIMIT="${CORRUPTION_SCAN_STRIKE_LIMIT:-2}"
mkdir -p "$(dirname "$CORRUPTION_SCAN_STRIKES_FILE")"
touch "$CORRUPTION_SCAN_STRIKES_FILE"
# Thin wrappers around common.sh's wd_state_get/wd_state_set — same shape as
# stability_watchdog.sh's get_strikes/set_strikes/increment_strikes/reset_strikes, keyed here
# by host path instead of a watchdog check name. Requires repeat corrupt detections across
# separate scan runs before --remediate acts, so a one-off ffprobe hiccup (mid-write file,
# NFS blip) can't trigger an unnecessary delete+re-search on its own.
get_scan_strikes() {
wd_state_get "$1" "$CORRUPTION_SCAN_STRIKES_FILE"
}
set_scan_strikes() {
wd_state_set "$1" "$2" "$CORRUPTION_SCAN_STRIKES_FILE"
}
increment_scan_strikes() {
local current
current=$(get_scan_strikes "$1")
[[ -z "$current" ]] && current=0
(( current++ ))
set_scan_strikes "$1" "$current"
echo "$current"
}
reset_scan_strikes() {
local current
current=$(get_scan_strikes "$1")
[[ -n "$current" && "$current" != "0" ]] && set_scan_strikes "$1" 0
}
if [[ "$SHOW_STATUS" == true ]]; then
echo ""
echo "━━━━━ $ICON_SUMMARY STATUS ━━━━━"
@@ -174,6 +210,7 @@ if [[ "$SHOW_STATUS" == true ]]; then
echo "$ICON_GEAR FFprobe binary: $FFPROBE_BIN"
echo "$ICON_GEAR FFprobe path map: ${#FFPROBE_PATH_MAP[@]} entries"
echo "$ICON_GEAR State file: $CORRUPTION_SCAN_STATE_FILE"
echo "$ICON_GEAR Strike limit: $CORRUPTION_SCAN_STRIKE_LIMIT"
echo "$ICON_GEAR Remediate: $REMEDIATE"
echo "$ICON_GEAR Scan limit: ${SCAN_LIMIT:-unlimited}"
echo "$ICON_GEAR Path filter: ${PATH_FILTER:-none}"
@@ -278,6 +315,7 @@ SCANNED=0
SKIPPED_CACHED=0
SKIPPED_UNMAPPED=0
CORRUPT_COUNT=0
STRIKE_HELD=0
REMEDIATED=0
REMEDIATE_FAILED=0
@@ -318,6 +356,7 @@ while IFS= read -r item; do
fi
if [[ "$result" == "clean" ]]; then
reset_scan_strikes "$host_path"
echo -e "${host_path}\t${stamp}" >> "$FRESH_CLEAN_TMP"
[[ "$ENABLE_LOGGING" == true ]] && echo " $ICON_SUCCESS $host_path"
continue
@@ -326,13 +365,21 @@ while IFS= read -r item; do
# corrupt:<reason>
reason="${result#corrupt:}"
(( CORRUPT_COUNT++ ))
echo " $ICON_ERROR CORRUPT: $host_path"
strikes=$(increment_scan_strikes "$host_path")
echo " $ICON_ERROR CORRUPT: $host_path (strike $strikes/$CORRUPTION_SCAN_STRIKE_LIMIT)"
[[ "$ENABLE_LOGGING" == true ]] && echo " $reason"
if [[ "$REMEDIATE" != true ]]; then
continue
fi
if (( strikes < CORRUPTION_SCAN_STRIKE_LIMIT )); then
warn " $host_path — strike $strikes/$CORRUPTION_SCAN_STRIKE_LIMIT, not yet remediating (needs repeat confirmation)"
(( STRIKE_HELD++ ))
continue
fi
reset_scan_strikes "$host_path"
episode_id=$(echo "$item" | jq -r '.episodeId // empty')
title=$(echo "$item" | jq -r '.sceneName // .relativePath // .path')
@@ -389,6 +436,7 @@ echo "$ICON_SUCCESS Skipped (cached): $SKIPPED_CACHED"
echo "$ICON_WARN Skipped (unmapped): $SKIPPED_UNMAPPED"
echo "$ICON_ERROR Corrupt found: $CORRUPT_COUNT"
if [[ "$REMEDIATE" == true ]]; then
echo "$ICON_WARN Held (strikes): $STRIKE_HELD"
echo "$ICON_SUCCESS Remediated: $REMEDIATED"
echo "$ICON_ERROR Remediation failed: $REMEDIATE_FAILED"
fi
+6
View File
@@ -1185,6 +1185,12 @@
# queued behind other moves already in progress, not just its
# own copy time
CORRUPTION_SCAN_STATE_FILE="${DATA_DIR}/corruption_scan_state.tsv" # clean-file skip-cache
CORRUPTION_SCAN_STRIKES_FILE="${DATA_DIR}/corruption_scan_strikes.tsv" # consecutive corrupt-detection counts, keyed by host path
CORRUPTION_SCAN_STRIKE_LIMIT=2 # consecutive corrupt detections (across separate scan runs)
# required before --remediate deletes+re-searches — guards
# against a one-off ffprobe hiccup (mid-write file, NFS blip)
# triggering an unnecessary delete. Resets to 0 the moment a
# file probes clean again.
SONARR_EXTENSIONS=("mkv" "mp4" "avi" "m4v" "ts" "wmv" "mov")
SONARR_PROTECTED_PATTERNS=(
# Subtitles