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.
This commit is contained in:
Gmer4Lfe
2026-07-17 12:15:55 -04:00
parent 6f7bb8a6aa
commit e688500cf5
+91 -5
View File
@@ -90,9 +90,17 @@
# RUNTIME MODES # RUNTIME MODES
# ============================================================================================== # ==============================================================================================
# #
# radarr_classification_scan.sh — normal run, prints report # radarr_classification_scan.sh — normal run, prints report
# radarr_classification_scan.sh --log — verbose (per-movie TRACKED-style logging) # radarr_classification_scan.sh --log — verbose (per-movie TRACKED-style logging)
# radarr_classification_scan.sh --status — show config and exit # radarr_classification_scan.sh --status — show config and exit
# radarr_classification_scan.sh --remove-junk — delete + import-exclude bad-metadata entries
# radarr_classification_scan.sh --move — relocate forward misplacements (moves the
# file if one exists; for hasFile=false
# entries, just corrects rootFolderPath/path
# and triggers an immediate MoviesSearch)
#
# --remove-junk and --move can be combined in one run — junk is cleared first, then the
# move pass runs against the remaining (now junk-free) classification.
# #
# ============================================================================================== # ==============================================================================================
@@ -100,11 +108,13 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../load_config.sh" source "$SCRIPT_DIR/../load_config.sh"
# --move is a script-local flag, not one parse_args recognizes — check the raw args before # --move / --remove-junk are script-local flags, not ones parse_args recognizes — check the
# they get filtered into PARSED_ARGS. # raw args before they get filtered into PARSED_ARGS.
MOVE_MODE=false MOVE_MODE=false
REMOVE_JUNK_MODE=false
for _arg in "$@"; do for _arg in "$@"; do
[[ "$_arg" == "--move" ]] && MOVE_MODE=true [[ "$_arg" == "--move" ]] && MOVE_MODE=true
[[ "$_arg" == "--remove-junk" ]] && REMOVE_JUNK_MODE=true
done done
unset _arg unset _arg
@@ -145,6 +155,7 @@ if [[ "$SHOW_STATUS" == true ]]; then
echo "$ICON_GEAR Kids studios: ${#RADARR_KIDS_STUDIOS[@]} curated" echo "$ICON_GEAR Kids studios: ${#RADARR_KIDS_STUDIOS[@]} curated"
echo "$ICON_GEAR Junk min votes: ${RADARR_JUNK_MIN_VOTES:-15}" echo "$ICON_GEAR Junk min votes: ${RADARR_JUNK_MIN_VOTES:-15}"
echo "$ICON_GEAR Move mode: $MOVE_MODE" echo "$ICON_GEAR Move mode: $MOVE_MODE"
echo "$ICON_GEAR Remove-junk: $REMOVE_JUNK_MODE"
echo "━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━"
exit 0 exit 0
fi fi
@@ -246,6 +257,81 @@ echo "$ICON_PROTECTED Bad metadata (junk): $JUNK_COUNT (hasFile=false, no imdb
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
[[ "$ENABLE_LOGGING" != true ]] && echo " (run with --log for the per-title list)" [[ "$ENABLE_LOGGING" != true ]] && echo " (run with --log for the per-title list)"
# ==============================================================================================
# ━━━ Remove-Junk Mode ━━━
# ==============================================================================================
# Junk entries are bad/thin TMDb matches with hasFile=false — there's no release to blocklist
# (nothing was ever grabbed) and no file to delete, only a bad monitored record. The fix is
# removing the record and adding it to Radarr's import exclusion list (same mechanism
# radarr_tmdb_removed.sh already uses via RADARR_DROPPED_ADD_EXCLUSION) so the same bad TMDb
# match can't get re-added by a future Overseerr request or list sync.
if [[ "$REMOVE_JUNK_MODE" == true ]]; then
echo ""
echo "━━━ $ICON_TRASH Remove-Junk Mode ━━━"
acquire_lock "wait"
trap "_release_all_locks" EXIT
JUNK_TARGETS=$(echo "$RESULTS" | jq -c '[.[] | select(.is_junk)]')
JUNK_TARGET_COUNT=$(echo "$JUNK_TARGETS" | jq 'length')
if [[ "$JUNK_TARGET_COUNT" -eq 0 ]]; then
info "No junk entries to remove"
else
warn "About to remove $JUNK_TARGET_COUNT junk entries — one at a time, verifying after each"
JUNK_REMOVED=0
JUNK_FAILED=0
while IFS= read -r item; do
id=$(echo "$item" | jq -r '.id')
title=$(echo "$item" | jq -r '.title')
http_code=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
--max-time 15 \
-H "X-Api-Key: $RADARR_API_KEY" \
"${RADARR_URL}/api/v3/movie/${id}?deleteFiles=false&addImportExclusion=true" 2>/dev/null)
if [[ "$http_code" != "200" && "$http_code" != "202" ]]; then
error "$title — API returned HTTP $http_code — stopping (review before re-running)"
(( JUNK_FAILED++ ))
break
fi
sleep 1
# Verify — the movie should now be gone entirely (404).
verify_code=$(curl -sf -o /dev/null -w "%{http_code}" \
-H "X-Api-Key: $RADARR_API_KEY" \
"${RADARR_URL}/api/v3/movie/${id}" 2>/dev/null)
if [[ "$verify_code" == "404" ]]; then
echo " $ICON_SUCCESS $title — removed and excluded"
(( JUNK_REMOVED++ ))
else
error "$title — verification failed (still returns HTTP $verify_code) — stopping"
(( JUNK_FAILED++ ))
break
fi
done < <(echo "$JUNK_TARGETS" | jq -c '.[]')
if [[ "$JUNK_REMOVED" -gt 0 ]]; then
info "Refreshing shared tracked-data cache..."
fresh_movies=$(arr_api "$RADARR_URL" "$RADARR_API_KEY" "v3" "movie" "Radarr")
[[ -n "$fresh_movies" ]] && arr_cache_write "radarr" "$fresh_movies"
fi
echo ""
echo "━━━━━ $ICON_SUMMARY REMOVE-JUNK SUMMARY ━━━━━"
echo "$ICON_SUCCESS Removed: $JUNK_REMOVED"
echo "$ICON_ERROR Failed: $JUNK_FAILED"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
fi
_release_all_locks
trap - EXIT
fi
# ============================================================================================== # ==============================================================================================
# ━━━ Move Mode ━━━ # ━━━ Move Mode ━━━
# ============================================================================================== # ==============================================================================================