Add resize-temps.sh — re-size backup temp files to correct movement targets
Re-processes *-temp.mp4 files from a backup location using season_info.py to compute the correct target duration per clip (music_duration / DAYS_IN_MVT), producing properly-sized *-final.mp4 files without touching the backup source. Skips finals that already exist. Fixes drift caused by old pipeline sizing clips to the wrong movement structure. https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
This commit is contained in:
Executable
+161
@@ -0,0 +1,161 @@
|
||||
#!/bin/bash
|
||||
# resize-temps.sh — re-size *-temp.mp4 files from a backup location into
|
||||
# correctly-proportioned *-final.mp4 files for use with montage-mvt.sh.
|
||||
#
|
||||
# Reads source temp files from BACKUP_ROOT (never modifies them).
|
||||
# Writes finals to MOVIES_DIR (from sky-cam.conf / .env).
|
||||
#
|
||||
# Usage:
|
||||
# ./resize-temps.sh --cam <camera-name> <backup_root> [--dry-run]
|
||||
#
|
||||
# Example:
|
||||
# ./resize-temps.sh --cam east /home/user/drives/data2/other-pictures/longterm/movies/movies
|
||||
# ./resize-temps.sh --cam north /mnt/backup/movies --dry-run
|
||||
#
|
||||
# The backup_root should contain the old season directories:
|
||||
# <backup_root>/<cam>/Spring/ Winter/ Summer/ Autumn/
|
||||
# with files like: 2025-06-15_Mvt2-temp.mp4
|
||||
#
|
||||
# Output goes to:
|
||||
# MOVIES_DIR/<cam>/<ASTRO_YEAR>/<SEASON>/Mvt<N>/<date>_Mvt<N>-Day<D>of<T>-final.mp4
|
||||
#
|
||||
# Already-existing finals are skipped (never overwritten).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||
source "$SCRIPT_DIR/sky-cam.conf"
|
||||
export TIMEZONE
|
||||
|
||||
# ── Args ──────────────────────────────────────────────────────────────────────
|
||||
CAM=""
|
||||
BACKUP_ROOT=""
|
||||
DRY_RUN=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--cam) CAM="$2"; shift 2 ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
-*) echo "Unknown option: $1"; exit 1 ;;
|
||||
*) BACKUP_ROOT="$1"; shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$CAM" ] || [ -z "$BACKUP_ROOT" ]; then
|
||||
echo "Usage: $0 --cam <camera-name> <backup_root> [--dry-run]"
|
||||
echo " e.g. $0 --cam east /home/user/drives/data2/other-pictures/longterm/movies/movies"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$BACKUP_ROOT/$CAM" ]; then
|
||||
echo "ERROR: $BACKUP_ROOT/$CAM not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
music_base_dir="$MUSIC_DIR"
|
||||
[ ! -d "$music_base_dir" ] && music_base_dir="$SCRIPT_DIR/music"
|
||||
|
||||
echo "Camera: $CAM"
|
||||
echo "Backup root: $BACKUP_ROOT/$CAM"
|
||||
echo "Output root: $MOVIES_DIR/$CAM"
|
||||
echo "Music dir: $music_base_dir"
|
||||
$DRY_RUN && echo "DRY RUN — no files will be written"
|
||||
echo ""
|
||||
|
||||
# ── Find all temp files ───────────────────────────────────────────────────────
|
||||
mapfile -d '' temp_files < <(
|
||||
find "$BACKUP_ROOT/$CAM" -type f -name '*-temp.mp4' -print0 | sort -z
|
||||
)
|
||||
|
||||
if [ "${#temp_files[@]}" -eq 0 ]; then
|
||||
echo "No *-temp.mp4 files found under $BACKUP_ROOT/$CAM"
|
||||
exit 0
|
||||
fi
|
||||
echo "Found ${#temp_files[@]} temp file(s)"
|
||||
echo ""
|
||||
|
||||
skipped=0
|
||||
processed=0
|
||||
errors=0
|
||||
|
||||
for temp_file in "${temp_files[@]}"; do
|
||||
# Extract date from filename: 2025-06-15_Mvt2-temp.mp4 → 2025-06-15
|
||||
filename="$(basename "$temp_file")"
|
||||
date_str="${filename%%_*}"
|
||||
|
||||
# Validate date format
|
||||
if ! [[ "$date_str" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
|
||||
echo "SKIP (bad filename): $temp_file"
|
||||
(( skipped++ )) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get season/movement info for this date
|
||||
_info="$(python3 "$SCRIPT_DIR/season_info.py" "$date_str" 2>/dev/null)" || {
|
||||
echo "SKIP (season_info.py failed for $date_str): $filename"
|
||||
(( skipped++ )) || true
|
||||
continue
|
||||
}
|
||||
eval "$_info"
|
||||
# Provides: SEASON MVT_NUM DAY_OF_MVT DAYS_IN_MVT MVT_START MVT_END
|
||||
# IS_LAST_DAY ASTRO_YEAR
|
||||
|
||||
# Locate music file
|
||||
music_file=$(find "$music_base_dir" -type f -iname "*${SEASON}*" \
|
||||
| grep -iE "Mvt[^0-9]*${MVT_NUM}[^0-9]" | sort | head -n 1)
|
||||
if [ -z "$music_file" ]; then
|
||||
echo "SKIP (no music for $SEASON Mvt$MVT_NUM): $filename"
|
||||
(( skipped++ )) || true
|
||||
continue
|
||||
fi
|
||||
music_duration=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$music_file")
|
||||
target_per_clip=$(echo "scale=6; $music_duration / $DAYS_IN_MVT" | bc)
|
||||
|
||||
# Determine output path
|
||||
out_dir="$MOVIES_DIR/$CAM/$ASTRO_YEAR/$SEASON/Mvt$MVT_NUM"
|
||||
final_file="$out_dir/${date_str}_Mvt${MVT_NUM}-Day${DAY_OF_MVT}of${DAYS_IN_MVT}-final.mp4"
|
||||
|
||||
# Skip if final already exists
|
||||
if [ -f "$final_file" ]; then
|
||||
echo "EXISTS — skip: $(basename "$final_file")"
|
||||
(( skipped++ )) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
raw_dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$temp_file")
|
||||
speed_factor=$(echo "scale=6; $raw_dur / $target_per_clip" | bc)
|
||||
|
||||
echo "Processing: $filename"
|
||||
echo " $SEASON Mvt$MVT_NUM Day$DAY_OF_MVT/$DAYS_IN_MVT Year=$ASTRO_YEAR"
|
||||
echo " raw=${raw_dur}s target=${target_per_clip}s speed=${speed_factor}x"
|
||||
echo " → $(basename "$final_file")"
|
||||
|
||||
if $DRY_RUN; then
|
||||
(( processed++ )) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
mkdir -p "$out_dir"
|
||||
|
||||
if ffmpeg -loglevel warning \
|
||||
-i "$temp_file" \
|
||||
-vf "setpts=PTS/$speed_factor" \
|
||||
-c:v libx264 -pix_fmt yuv420p -preset "$ENCODE_PRESET" -crf "$CRF_SEASONS_FINAL" \
|
||||
-t "$target_per_clip" -an \
|
||||
-y "$final_file"; then
|
||||
actual=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$final_file")
|
||||
echo " Done: ${actual}s"
|
||||
(( processed++ )) || true
|
||||
else
|
||||
rm -f "$final_file"
|
||||
echo " ERROR: ffmpeg failed — no output written"
|
||||
(( errors++ )) || true
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "────────────────────────────────────────"
|
||||
echo "Processed: $processed Skipped: $skipped Errors: $errors"
|
||||
if $DRY_RUN; then
|
||||
echo "(dry run — re-run without --dry-run to write files)"
|
||||
fi
|
||||
Reference in New Issue
Block a user