Relocate + trigger search for hasFile=false forward-misplacements
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.
This commit is contained in:
@@ -268,12 +268,14 @@ if [[ "$MOVE_MODE" == true ]]; then
|
|||||||
|
|
||||||
build_arr_path_map "RADARR"
|
build_arr_path_map "RADARR"
|
||||||
|
|
||||||
# hasFile==false entries have nothing to physically move (some monitored titles simply
|
# hasFile==false entries (monitored but never downloaded) have nothing to physically
|
||||||
# were never downloaded — confirmed live: "Biohazard 4: Incubate" had hasFile=false even
|
# move — confirmed live: "Biohazard 4: Incubate" had hasFile=false even in the cache from
|
||||||
# in the cache from before this run started, not something this script broke). Moving
|
# before any of this ran, not something this script broke. There's still real value in
|
||||||
# Radarr's DB pointer for those is harmless but pointless — skip them here; they still
|
# fixing them, though: correct the DB pointer now (so Radarr saves to the right root
|
||||||
# show up correctly in the report above as a classification finding.
|
# whenever it does find a release) and kick off an immediate search rather than waiting
|
||||||
MOVE_TARGETS=$(echo "$RESULTS" | jq -c '[.[] | select((.forward_anime_miss or .forward_kids_miss) and (.is_junk | not) and .hasFile)]')
|
# 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')
|
MOVE_COUNT=$(echo "$MOVE_TARGETS" | jq 'length')
|
||||||
|
|
||||||
if [[ "$MOVE_COUNT" -eq 0 ]]; then
|
if [[ "$MOVE_COUNT" -eq 0 ]]; then
|
||||||
@@ -281,15 +283,17 @@ if [[ "$MOVE_MODE" == true ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
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
|
MOVED=0
|
||||||
|
RELOCATED_SEARCH=0
|
||||||
FAILED=0
|
FAILED=0
|
||||||
|
|
||||||
while IFS= read -r item; do
|
while IFS= read -r item; do
|
||||||
id=$(echo "$item" | jq -r '.id')
|
id=$(echo "$item" | jq -r '.id')
|
||||||
title=$(echo "$item" | jq -r '.title')
|
title=$(echo "$item" | jq -r '.title')
|
||||||
is_anime_flag=$(echo "$item" | jq -r '.is_anime')
|
is_anime_flag=$(echo "$item" | jq -r '.is_anime')
|
||||||
|
had_file=$(echo "$item" | jq -r '.hasFile')
|
||||||
if [[ "$is_anime_flag" == "true" ]]; then
|
if [[ "$is_anime_flag" == "true" ]]; then
|
||||||
target_root="$RADARR_ANIME_ROOT"
|
target_root="$RADARR_ANIME_ROOT"
|
||||||
else
|
else
|
||||||
@@ -317,7 +321,14 @@ if [[ "$MOVE_MODE" == true ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
new_path="${target_root}/${folder_name}"
|
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" \
|
updated_movie=$(echo "$full_movie" | jq --arg root "$target_root" --arg path "$new_path" \
|
||||||
'.rootFolderPath = $root | .path = $path')
|
'.rootFolderPath = $root | .path = $path')
|
||||||
@@ -327,7 +338,7 @@ if [[ "$MOVE_MODE" == true ]]; then
|
|||||||
-H "X-Api-Key: $RADARR_API_KEY" \
|
-H "X-Api-Key: $RADARR_API_KEY" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "$updated_movie" \
|
-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
|
if [[ "$http_code" != "200" && "$http_code" != "202" ]]; then
|
||||||
error " ✗ $title — API returned HTTP $http_code — stopping (review before re-running)"
|
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_root=$(echo "$verify_movie" | jq -r '.rootFolderPath')
|
||||||
verify_hasfile=$(echo "$verify_movie" | jq -r '.hasFile')
|
verify_hasfile=$(echo "$verify_movie" | jq -r '.hasFile')
|
||||||
|
|
||||||
if [[ "$verify_root" == "$target_root" ]] && [[ "$verify_hasfile" == "true" ]]; then
|
if [[ "$verify_root" != "$target_root" ]]; then
|
||||||
echo " $ICON_SUCCESS $title — moved and verified"
|
error " ✗ $title — verification failed (root: $verify_root) — stopping"
|
||||||
(( MOVED++ ))
|
|
||||||
else
|
|
||||||
error " ✗ $title — verification failed (root: $verify_root, hasFile: $verify_hasfile) — stopping"
|
|
||||||
(( FAILED++ ))
|
(( FAILED++ ))
|
||||||
break
|
break
|
||||||
fi
|
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 '.[]')
|
done < <(echo "$MOVE_TARGETS" | jq -c '.[]')
|
||||||
|
|
||||||
# arr_get_tracked_data() is cache-first — every write above changed rootFolderPath, so the
|
# 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).
|
# 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
|
# 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.
|
# 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..."
|
info "Refreshing shared tracked-data cache..."
|
||||||
fresh_movies=$(arr_api "$RADARR_URL" "$RADARR_API_KEY" "v3" "movie" "Radarr")
|
fresh_movies=$(arr_api "$RADARR_URL" "$RADARR_API_KEY" "v3" "movie" "Radarr")
|
||||||
[[ -n "$fresh_movies" ]] && arr_cache_write "radarr" "$fresh_movies"
|
[[ -n "$fresh_movies" ]] && arr_cache_write "radarr" "$fresh_movies"
|
||||||
@@ -364,8 +396,9 @@ if [[ "$MOVE_MODE" == true ]]; then
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "━━━━━ $ICON_SUMMARY MOVE SUMMARY ━━━━━"
|
echo "━━━━━ $ICON_SUMMARY MOVE SUMMARY ━━━━━"
|
||||||
echo "$ICON_SUCCESS Moved: $MOVED"
|
echo "$ICON_SUCCESS Moved (file relocated): $MOVED"
|
||||||
echo "$ICON_ERROR Failed: $FAILED"
|
echo "$ICON_SUCCESS Relocated + search triggered: $RELOCATED_SEARCH"
|
||||||
|
echo "$ICON_ERROR Failed: $FAILED"
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user