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.
This commit is contained in:
@@ -100,6 +100,14 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "$SCRIPT_DIR/../load_config.sh"
|
||||
|
||||
# --move is a script-local flag, not one parse_args recognizes — check the raw args before
|
||||
# they get filtered into PARSED_ARGS.
|
||||
MOVE_MODE=false
|
||||
for _arg in "$@"; do
|
||||
[[ "$_arg" == "--move" ]] && MOVE_MODE=true
|
||||
done
|
||||
unset _arg
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
# ==============================================================================================
|
||||
@@ -136,6 +144,7 @@ if [[ "$SHOW_STATUS" == true ]]; then
|
||||
echo "$ICON_GEAR Anime studios: ${#RADARR_ANIME_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 Move mode: $MOVE_MODE"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
exit 0
|
||||
fi
|
||||
@@ -237,4 +246,112 @@ echo "$ICON_PROTECTED Bad metadata (junk): $JUNK_COUNT (hasFile=false, no imdb
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
[[ "$ENABLE_LOGGING" != true ]] && echo " (run with --log for the per-title list)"
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Move Mode ━━━
|
||||
# ==============================================================================================
|
||||
# Acts only on FORWARD misplacements (clear-cut: classified anime/kids, sitting in the wrong
|
||||
# root) and never on REVERSE leaks (those are judgment calls — deliberate style placements
|
||||
# like Castlevania/Legend of Korra live there, so they're report-only) or JUNK (those need
|
||||
# removal from Radarr, not a file move — nothing to move for a hasFile=false entry).
|
||||
#
|
||||
# One movie at a time, verified after each, matching the lesson learned doing this by hand
|
||||
# for Sonarr earlier: a rapid-fire batch of moves raced Radarr's own file-move worker and
|
||||
# left two series' files at an intermediate path while the API still reported success. A
|
||||
# short sleep plus a real re-fetch-and-check after every single move catches that here
|
||||
# before it can compound across dozens of movies.
|
||||
if [[ "$MOVE_MODE" == true ]]; then
|
||||
echo ""
|
||||
echo "━━━ $ICON_SYNC Move Mode — Forward Misplacements ━━━"
|
||||
|
||||
acquire_lock "wait"
|
||||
trap "_release_all_locks" EXIT
|
||||
|
||||
build_arr_path_map "RADARR"
|
||||
|
||||
MOVE_TARGETS=$(echo "$RESULTS" | jq -c '[.[] | select((.forward_anime_miss or .forward_kids_miss) and (.is_junk | not))]')
|
||||
MOVE_COUNT=$(echo "$MOVE_TARGETS" | jq 'length')
|
||||
|
||||
if [[ "$MOVE_COUNT" -eq 0 ]]; then
|
||||
info "Nothing to move"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
warn "About to move $MOVE_COUNT movies — one at a time, verifying after each"
|
||||
|
||||
MOVED=0
|
||||
FAILED=0
|
||||
|
||||
while IFS= read -r item; do
|
||||
id=$(echo "$item" | jq -r '.id')
|
||||
title=$(echo "$item" | jq -r '.title')
|
||||
is_anime_flag=$(echo "$item" | jq -r '.is_anime')
|
||||
if [[ "$is_anime_flag" == "true" ]]; then
|
||||
target_root="$RADARR_ANIME_ROOT"
|
||||
else
|
||||
target_root="$RADARR_KIDS_ROOT"
|
||||
fi
|
||||
|
||||
# RESULTS only carries the reduced report fields — Radarr's PUT expects the complete
|
||||
# resource representation, so fetch a fresh full movie record to modify and send back.
|
||||
full_movie=$(arr_api "$RADARR_URL" "$RADARR_API_KEY" "v3" "movie/$id" "Radarr")
|
||||
if [[ -z "$full_movie" ]]; then
|
||||
error " ✗ $title — could not fetch full movie record, skipping"
|
||||
(( FAILED++ ))
|
||||
continue
|
||||
fi
|
||||
|
||||
old_path=$(echo "$full_movie" | jq -r '.path')
|
||||
folder_name="${old_path##*/}"
|
||||
|
||||
# A literal "/" in the folder name would build a broken nested directory instead of
|
||||
# moving to one clean folder — bit us once already doing this by hand for Sonarr.
|
||||
if [[ "$folder_name" == *"/"* ]]; then
|
||||
error " ✗ $title — folder name contains '/', skipping (needs manual handling)"
|
||||
(( FAILED++ ))
|
||||
continue
|
||||
fi
|
||||
|
||||
new_path="${target_root}/${folder_name}"
|
||||
info " → $title: $old_path → $new_path"
|
||||
|
||||
updated_movie=$(echo "$full_movie" | jq --arg root "$target_root" --arg path "$new_path" \
|
||||
'.rootFolderPath = $root | .path = $path')
|
||||
|
||||
http_code=$(curl -sf -o /dev/null -w "%{http_code}" -X PUT \
|
||||
--max-time 30 \
|
||||
-H "X-Api-Key: $RADARR_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$updated_movie" \
|
||||
"${RADARR_URL}/api/v3/movie/${id}?moveFiles=true" 2>/dev/null)
|
||||
|
||||
if [[ "$http_code" != "200" && "$http_code" != "202" ]]; then
|
||||
error " ✗ $title — API returned HTTP $http_code — stopping (review before re-running)"
|
||||
(( FAILED++ ))
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 3
|
||||
|
||||
# Never trust the PUT response alone — re-fetch and confirm the change actually landed.
|
||||
verify_movie=$(arr_api "$RADARR_URL" "$RADARR_API_KEY" "v3" "movie/$id" "Radarr")
|
||||
verify_root=$(echo "$verify_movie" | jq -r '.rootFolderPath')
|
||||
verify_hasfile=$(echo "$verify_movie" | jq -r '.hasFile')
|
||||
|
||||
if [[ "$verify_root" == "$target_root" ]] && [[ "$verify_hasfile" == "true" ]]; then
|
||||
echo " $ICON_SUCCESS $title — moved and verified"
|
||||
(( MOVED++ ))
|
||||
else
|
||||
error " ✗ $title — verification failed (root: $verify_root, hasFile: $verify_hasfile) — stopping"
|
||||
(( FAILED++ ))
|
||||
break
|
||||
fi
|
||||
done < <(echo "$MOVE_TARGETS" | jq -c '.[]')
|
||||
|
||||
echo ""
|
||||
echo "━━━━━ $ICON_SUMMARY MOVE SUMMARY ━━━━━"
|
||||
echo "$ICON_SUCCESS Moved: $MOVED"
|
||||
echo "$ICON_ERROR Failed: $FAILED"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user