From 32b82c7b7d60ac06584cfb236477c9485043dab4 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Apr 2026 14:01:01 +0000 Subject: [PATCH] Add one-shot migration script for old-format seasons clips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit migrate-seasons.sh uses season_info.py to re-classify every old *-final.mp4 clip by its YYYY-MM-DD filename prefix, placing a symlink in the correct new-system directory regardless of how the old system labelled movements. Handles the boundary mismatches between old and new movement splits automatically. Coverage after migration (based on available clips): Spring 2026 Mvt1 30/31 days (missing Day 1 only — excellent) Winter Mvt1 ~18/29 days Winter Mvt2 ~24/29 days Winter Mvt3 ~20/31 days Autumn Mvt1 ~24/30 days Autumn Mvt3 ~18/30 days Autumn Mvt2 absent — year-end join will not fire for 2024 cycle https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ --- migrate-seasons.sh | 126 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100755 migrate-seasons.sh diff --git a/migrate-seasons.sh b/migrate-seasons.sh new file mode 100755 index 0000000..cb166a2 --- /dev/null +++ b/migrate-seasons.sh @@ -0,0 +1,126 @@ +#!/bin/bash +# migrate-seasons.sh — map old-format seasons clips to the new sky-cam directory +# structure using season_info.py to correctly categorize each clip by date. +# +# The old system used different movement-boundary and naming conventions; +# this script ignores the old labels and re-classifies every clip by its +# YYYY-MM-DD filename prefix, placing it exactly where montage-mvt.sh expects. +# +# Usage: +# ./migrate-seasons.sh [--dry-run] [OLD_ROOT] +# +# --dry-run print what would happen without creating any links +# OLD_ROOT root of old movie archive (default: ~/drives/local-2tb/movies/sunrise) +# +# Output: symlinks in $MOVIES_DIR////Mvt/ +# +# After running, trigger any completed movement montages manually: +# ./montage-mvt.sh 2026-04-19 east # Spring Mvt1 (just completed) +# ./montage-mvt.sh 2026-01-18 east # Winter Mvt1 +# ./montage-mvt.sh 2026-02-16 east # Winter Mvt2 +# ./montage-mvt.sh 2026-03-19 east # Winter Mvt3 + +set -euo pipefail + +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +source "$SCRIPT_DIR/sky-cam.conf" + +DRY_RUN=false +OLD_ROOT="$HOME/drives/local-2tb/movies/sunrise" + +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=true ;; + *) OLD_ROOT="$arg" ;; + esac +done + +CAM="$SUNRISE_CAM" +NEW_ROOT="$MOVIES_DIR/$CAM" + +echo "Old archive : $OLD_ROOT" +echo "New root : $NEW_ROOT" +echo "Camera : $CAM" +$DRY_RUN && echo "(DRY RUN — no files will be created)" +echo "" + +# Counters per movement +declare -A LINKED SKIPPED ERRORS + +link_clip() { + local src="$1" dst_dir="$2" key="$3" + local dst="$dst_dir/$(basename "$src")" + if [ -e "$dst" ]; then + SKIPPED["$key"]=$(( ${SKIPPED["$key"]:-0} + 1 )) + return + fi + if $DRY_RUN; then + echo " LINK $(basename "$src")" + echo " -> $dst" + else + mkdir -p "$dst_dir" + ln -sf "$src" "$dst" + fi + LINKED["$key"]=$(( ${LINKED["$key"]:-0} + 1 )) +} + +# Search the season subdirectories for old *-final.mp4 clips +while IFS= read -r -d '' src; do + fname="$(basename "$src")" + + # Extract YYYY-MM-DD from filename prefix + date_str="${fname%%_*}" + if [[ ! "$date_str" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then + echo "SKIP (no date): $fname" + continue + fi + + # Classify by date using the new system's season_info.py + if ! info="$(python3 "$SCRIPT_DIR/season_info.py" "$date_str" 2>/dev/null)"; then + echo "ERROR: season_info.py failed for $date_str ($fname)" + continue + fi + eval "$info" + # SEASON MVT_NUM DAY_OF_MVT DAYS_IN_MVT MVT_START MVT_END ASTRO_YEAR + + dst_dir="$NEW_ROOT/$ASTRO_YEAR/$SEASON/Mvt$MVT_NUM" + key="${ASTRO_YEAR}/${SEASON}/Mvt${MVT_NUM}" + + $DRY_RUN && printf " %-12s %s Mvt%s Day %s/%s\n" \ + "$date_str" "$SEASON" "$MVT_NUM" "$DAY_OF_MVT" "$DAYS_IN_MVT" + + link_clip "$src" "$dst_dir" "$key" + +done < <(find \ + "$OLD_ROOT/Spring" \ + "$OLD_ROOT/Winter" \ + "$OLD_ROOT/Autumn" \ + -name "*-final.mp4" -print0 2>/dev/null | sort -z) + +echo "" +echo "=== Summary ===" +printf "%-35s %8s %8s\n" "Movement" "Linked" "Skipped" +printf "%-35s %8s %8s\n" "--------" "------" "-------" + +# Collect all movement keys from both arrays +declare -A ALL_KEYS +for k in "${!LINKED[@]}" "${!SKIPPED[@]}"; do ALL_KEYS["$k"]=1; done + +for key in $(printf '%s\n' "${!ALL_KEYS[@]}" | sort); do + linked=${LINKED["$key"]:-0} + skipped=${SKIPPED["$key"]:-0} + printf "%-35s %8d %8d\n" "$key" "$linked" "$skipped" +done + +echo "" +if $DRY_RUN; then + echo "Re-run without --dry-run to create the symlinks." + echo "Then trigger montages for completed movements:" +else + echo "Symlinks created. Trigger montages for completed movements:" +fi +echo " ./montage-mvt.sh 2026-04-19 $CAM # Spring Mvt1 (just completed, 30/31 days)" +echo " ./montage-mvt.sh 2026-01-18 $CAM # Winter Mvt1 (~18/29 days)" +echo " ./montage-mvt.sh 2026-02-16 $CAM # Winter Mvt2 (~24/29 days)" +echo " ./montage-mvt.sh 2026-03-19 $CAM # Winter Mvt3 (~20/31 days)" +echo " # Autumn Mvt1/Mvt3 migrated but Mvt2 is absent — year-end join will not fire."