Add trailer_folder_migration.sh — one-off tool to migrate TV trailers into trailers/ convention
This commit is contained in:
Executable
+199
@@ -0,0 +1,199 @@
|
||||
#!/bin/bash
|
||||
# ==============================================================================================
|
||||
# ============================= Trailer Folder Migration =======================================
|
||||
# ==============================================================================================
|
||||
#
|
||||
# PURPOSE
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# One-off migration for TV show trailers downloaded before Trailarr's "Series
|
||||
# Trailers" profile was corrected. Emby ingests TV trailers sitting at the
|
||||
# series root using the movie-style "<Show> (Year)-trailer.ext" convention as
|
||||
# fake episodes instead of recognizing them as trailers — confirmed via Emby's
|
||||
# server log. The fix is a "trailers/" subfolder (lowercase) under the series
|
||||
# folder containing a plain "trailer.ext" file — same convention Trailarr now
|
||||
# uses going forward (customfilter_id=2, "Series Trailers" profile).
|
||||
#
|
||||
# This script only moves/renames existing misplaced files. It does not touch
|
||||
# Trailarr or Emby — a normal periodic Emby library scan picks up the moved
|
||||
# files on its own.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL MODEL
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Discovery
|
||||
# Scans SONARR_TV_ROOT one level deep for "*-trailer.*" files sitting
|
||||
# directly in a series folder (the movie-style convention).
|
||||
#
|
||||
# Single Trailer Per Show
|
||||
# <Show>/<Show> (Year)-trailer.mkv → <Show>/trailers/trailer.mkv
|
||||
#
|
||||
# Multiple Trailers Per Show
|
||||
# Sorted alphabetically for determinism. First file becomes trailer.ext,
|
||||
# subsequent files become trailer-2.ext, trailer-3.ext, etc. Emby's TV
|
||||
# trailer convention only requires the file to live in trailers/ — exact
|
||||
# filename beyond the first doesn't matter, but distinct names avoid
|
||||
# collisions and keep behavior deterministic on re-run.
|
||||
#
|
||||
# Collision Safety
|
||||
# If the destination filename already exists, the file is skipped and
|
||||
# logged as a conflict rather than overwritten. Lets the script be re-run
|
||||
# safely after a partial run or a manually resolved conflict.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION
|
||||
# ==============================================================================================
|
||||
#
|
||||
# host*.conf
|
||||
#
|
||||
# HOST*_SONARR_TV_ROOT
|
||||
# Host filesystem path to the TV library. Aliased by detect_hosts() →
|
||||
# SONARR_TV_ROOT.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
# ==============================================================================================
|
||||
#
|
||||
# trailer_folder_migration.sh
|
||||
# Move every misplaced trailer file into <show>/trailers/.
|
||||
#
|
||||
# trailer_folder_migration.sh --dry-run
|
||||
# Show what would move, with no filesystem changes.
|
||||
#
|
||||
# trailer_folder_migration.sh --log
|
||||
# Verbose output — per-file source/destination.
|
||||
#
|
||||
# ==============================================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source "$SCRIPT_DIR/../load_config.sh"
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Setup ━━━
|
||||
# ==============================================================================================
|
||||
acquire_lock
|
||||
|
||||
# detect_hosts() sets MY_ID and aliases HOST*_SONARR_TV_ROOT → SONARR_TV_ROOT
|
||||
detect_hosts
|
||||
|
||||
if [[ -z "${SONARR_TV_ROOT:-}" ]]; then
|
||||
error "SONARR_TV_ROOT not set for $MY_ID — check HOST*_SONARR_TV_ROOT in host*.conf"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$SONARR_TV_ROOT" ]]; then
|
||||
error "SONARR_TV_ROOT not found: $SONARR_TV_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
log "TV root: $SONARR_TV_ROOT"
|
||||
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be moved"
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Discover misplaced trailer files, grouped by show ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━ $ICON_CLEAN Trailer Folder Migration — $MY_ID ━━━"
|
||||
|
||||
START=$(date +%s)
|
||||
|
||||
declare -A SHOW_FILES=() # show dir → newline-separated list of trailer file paths
|
||||
while IFS= read -r -d '' f; do
|
||||
show_dir="$(dirname "$f")"
|
||||
SHOW_FILES["$show_dir"]+="$f"$'\n'
|
||||
done < <(find "$SONARR_TV_ROOT" -mindepth 2 -maxdepth 2 -iname "*-trailer.*" -print0)
|
||||
|
||||
TOTAL_SHOWS=${#SHOW_FILES[@]}
|
||||
if [[ "$TOTAL_SHOWS" -eq 0 ]]; then
|
||||
echo "$ICON_DONE No misplaced trailer files found — nothing to migrate"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
warn "$TOTAL_SHOWS show(s) with misplaced trailer file(s)"
|
||||
|
||||
MOVED=0
|
||||
SKIPPED=0
|
||||
FAILED=0
|
||||
FAIL_LIST=()
|
||||
|
||||
for show_dir in "${!SHOW_FILES[@]}"; do
|
||||
mapfile -t files < <(printf '%s' "${SHOW_FILES[$show_dir]}" | sort)
|
||||
trailers_dir="$show_dir/trailers"
|
||||
show_name="$(basename "$show_dir")"
|
||||
|
||||
if [[ "$DRY_RUN" != true ]]; then
|
||||
mkdir -p "$trailers_dir" || {
|
||||
error "$show_name — could not create trailers/ dir"
|
||||
FAILED=$(( FAILED + ${#files[@]} ))
|
||||
FAIL_LIST+=("$show_name")
|
||||
continue
|
||||
}
|
||||
fi
|
||||
|
||||
idx=0
|
||||
for src in "${files[@]}"; do
|
||||
[[ -z "$src" ]] && continue
|
||||
idx=$(( idx + 1 ))
|
||||
ext="${src##*.}"
|
||||
if [[ "$idx" -eq 1 ]]; then
|
||||
dest="$trailers_dir/trailer.$ext"
|
||||
else
|
||||
dest="$trailers_dir/trailer-$idx.$ext"
|
||||
fi
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
log "$show_name — would move: $(basename "$src") → trailers/$(basename "$dest")"
|
||||
MOVED=$(( MOVED + 1 ))
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -e "$dest" ]]; then
|
||||
warn "$show_name — $(basename "$dest") already exists, skipping $(basename "$src")"
|
||||
SKIPPED=$(( SKIPPED + 1 ))
|
||||
continue
|
||||
fi
|
||||
|
||||
if mv "$src" "$dest"; then
|
||||
log "$show_name — $(basename "$src") → trailers/$(basename "$dest")"
|
||||
MOVED=$(( MOVED + 1 ))
|
||||
else
|
||||
error "$show_name — failed to move $(basename "$src")"
|
||||
FAILED=$(( FAILED + 1 ))
|
||||
FAIL_LIST+=("$show_name")
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
END=$(date +%s)
|
||||
|
||||
# ==============================================================================================
|
||||
# ━━━ Summary ━━━
|
||||
# ==============================================================================================
|
||||
echo ""
|
||||
echo "━━━━━ $ICON_SUMMARY TRAILER MIGRATION SUMMARY ━━━━━"
|
||||
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
|
||||
echo "$ICON_CLEAN Shows: $TOTAL_SHOWS"
|
||||
echo "$ICON_TIME Duration: $(format_duration $(( END - START )))"
|
||||
echo ""
|
||||
echo "$ICON_DONE Moved: $MOVED"
|
||||
[[ "$SKIPPED" -gt 0 ]] && echo "$ICON_SKIP Skipped: $SKIPPED (destination already existed)"
|
||||
[[ "$FAILED" -gt 0 ]] && echo "$ICON_ERROR Failed: $FAILED"
|
||||
echo ""
|
||||
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — no changes made"
|
||||
elif [[ "$FAILED" -gt 0 ]]; then
|
||||
echo "$ICON_ERROR Status: SOME MOVES FAILED — ${FAIL_LIST[*]}"
|
||||
notify "Trailer folder migration failed for: ${FAIL_LIST[*]}" \
|
||||
"Trailer Migration" "warning"
|
||||
else
|
||||
echo "$ICON_DONE Status: done — $MOVED file(s) migrated across $TOTAL_SHOWS show(s)"
|
||||
fi
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
[[ "$FAILED" -gt 0 ]] && exit 1
|
||||
exit 0
|
||||
Reference in New Issue
Block a user