From 6f7bb8a6aa2aa4b7234965746ec61381099d9715 Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Fri, 17 Jul 2026 12:11:30 -0400 Subject: [PATCH] Relocate + trigger search for hasFile=false forward-misplacements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Arrs_Stack/radarr_classification_scan.sh | 67 ++++++++++++++++++------ 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/Arrs_Stack/radarr_classification_scan.sh b/Arrs_Stack/radarr_classification_scan.sh index 8d4d0b7..4d68f26 100755 --- a/Arrs_Stack/radarr_classification_scan.sh +++ b/Arrs_Stack/radarr_classification_scan.sh @@ -268,12 +268,14 @@ if [[ "$MOVE_MODE" == true ]]; then build_arr_path_map "RADARR" - # hasFile==false entries have nothing to physically move (some monitored titles simply - # were never downloaded — confirmed live: "Biohazard 4: Incubate" had hasFile=false even - # in the cache from before this run started, not something this script broke). Moving - # Radarr's DB pointer for those is harmless but pointless — skip them here; they still - # show up correctly in the report above as a classification finding. - MOVE_TARGETS=$(echo "$RESULTS" | jq -c '[.[] | select((.forward_anime_miss or .forward_kids_miss) and (.is_junk | not) and .hasFile)]') + # hasFile==false entries (monitored but never downloaded) have nothing to physically + # move — confirmed live: "Biohazard 4: Incubate" had hasFile=false even in the cache from + # before any of this ran, not something this script broke. There's still real value in + # fixing them, though: correct the DB pointer now (so Radarr saves to the right root + # whenever it does find a release) and kick off an immediate search rather than waiting + # for the next scheduled one. Junk entries are still excluded entirely — nothing to + # search for there, they need removal instead. + 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 @@ -281,15 +283,17 @@ if [[ "$MOVE_MODE" == true ]]; then exit 0 fi - warn "About to move $MOVE_COUNT movies — one at a time, verifying after each" + warn "About to process $MOVE_COUNT movies — one at a time, verifying after each" MOVED=0 + RELOCATED_SEARCH=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') + had_file=$(echo "$item" | jq -r '.hasFile') if [[ "$is_anime_flag" == "true" ]]; then target_root="$RADARR_ANIME_ROOT" else @@ -317,7 +321,14 @@ if [[ "$MOVE_MODE" == true ]]; then fi new_path="${target_root}/${folder_name}" - info " → $title: $old_path → $new_path" + + if [[ "$had_file" == "true" ]]; then + info " → $title: $old_path → $new_path (moving file)" + move_qs="?moveFiles=true" + else + info " → $title: $old_path → $new_path (no file — relocating + search)" + move_qs="" + fi updated_movie=$(echo "$full_movie" | jq --arg root "$target_root" --arg path "$new_path" \ '.rootFolderPath = $root | .path = $path') @@ -327,7 +338,7 @@ if [[ "$MOVE_MODE" == true ]]; then -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) + "${RADARR_URL}/api/v3/movie/${id}${move_qs}" 2>/dev/null) if [[ "$http_code" != "200" && "$http_code" != "202" ]]; then error " ✗ $title — API returned HTTP $http_code — stopping (review before re-running)" @@ -342,21 +353,42 @@ if [[ "$MOVE_MODE" == true ]]; then 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" + if [[ "$verify_root" != "$target_root" ]]; then + error " ✗ $title — verification failed (root: $verify_root) — stopping" (( FAILED++ )) break fi + + if [[ "$had_file" == "true" ]]; then + if [[ "$verify_hasfile" == "true" ]]; then + echo " $ICON_SUCCESS $title — moved and verified" + (( MOVED++ )) + else + error " ✗ $title — verification failed (root updated but hasFile now false) — stopping" + (( FAILED++ )) + break + fi + else + search_code=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \ + --max-time 30 \ + -H "X-Api-Key: $RADARR_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"MoviesSearch\",\"movieIds\":[${id}]}" \ + "${RADARR_URL}/api/v3/command" 2>/dev/null) + if [[ "$search_code" == "200" || "$search_code" == "201" ]]; then + echo " $ICON_SUCCESS $title — relocated, search triggered" + else + warn " $title — relocated but search trigger returned HTTP $search_code (will pick up on next scheduled search)" + fi + (( RELOCATED_SEARCH++ )) + fi done < <(echo "$MOVE_TARGETS" | jq -c '.[]') # arr_get_tracked_data() is cache-first — every write above changed rootFolderPath, so the # shared cache is now stale until the next scheduled arr_cache_prefill run (up to 30min). # Every other script reading this cache (cleanup, discovery, etc.) would see wrong data # until then — refresh it now with one more live fetch rather than leave that window open. - if [[ "$MOVED" -gt 0 ]]; then + if [[ "$(( MOVED + RELOCATED_SEARCH ))" -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" @@ -364,8 +396,9 @@ if [[ "$MOVE_MODE" == true ]]; then echo "" echo "━━━━━ $ICON_SUMMARY MOVE SUMMARY ━━━━━" - echo "$ICON_SUCCESS Moved: $MOVED" - echo "$ICON_ERROR Failed: $FAILED" + echo "$ICON_SUCCESS Moved (file relocated): $MOVED" + echo "$ICON_SUCCESS Relocated + search triggered: $RELOCATED_SEARCH" + echo "$ICON_ERROR Failed: $FAILED" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" fi