Add per-step resilience and notifications across all video pipeline scripts
Each pipeline now saves intermediate files permanently before the step most likely to fail, so a partial failure leaves a recoverable artifact: - daily_sunrise_video.sh: speed-adjusted video (*-sped.mp4) survives if the drawtext overlay step fails; deleted automatically on success - montage-mvt.sh: speed-adjusted video (*-Sped.mp4) survives if the music-mux + attribution overlay step fails; deleted on success - 4-seasons.sh / montage-mvt.sh / year-end-join.sh: explicit ffmpeg error handling with targeted notify.sh calls naming the failed step and the surviving artifact path - montage-mvt.sh / 4-seasons.sh / year-end-join.sh: clip-duration-sum vs music-duration drift check warns when cumulative float error exceeds 2 s https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
This commit is contained in:
+54
-10
@@ -4,6 +4,12 @@
|
||||
# side, and write the final video. Upload is handled by a separate systemd
|
||||
# service (sky-cam-sunrise-upload) triggered via OnSuccess= so the two jobs
|
||||
# have independent log entries and failure states.
|
||||
#
|
||||
# Resilience: the speed-adjusted video is saved permanently before the overlay
|
||||
# step. If overlay fails, the sped video survives at:
|
||||
# <output_dir>/<date>-daily-sunrise-sped.mp4
|
||||
# Re-run this script once the issue is resolved; the sped file is deleted
|
||||
# automatically when the overlay step succeeds.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -22,6 +28,8 @@ mkdir -p "$output_dir"
|
||||
# ── Sunrise time ──────────────────────────────────────────────────────────────
|
||||
sunrise_time=$(python3 "$SCRIPT_DIR/sunrise.py")
|
||||
if [[ -z "$sunrise_time" ]]; then
|
||||
"$SCRIPT_DIR/notify.sh" "FAILED: sunrise $current_date" \
|
||||
"Could not retrieve sunrise time from sunrise.py" || true
|
||||
echo "Error: Failed to retrieve sunrise time."
|
||||
exit 1
|
||||
fi
|
||||
@@ -40,11 +48,14 @@ echo "Window: $((start_sec/3600)):$(printf '%02d' $(((start_sec%3600)/60))) →
|
||||
|
||||
# ── Collect images in window ──────────────────────────────────────────────────
|
||||
if [ ! -d "$image_dir" ]; then
|
||||
"$SCRIPT_DIR/notify.sh" "FAILED: sunrise $current_date" \
|
||||
"Image directory not found: $image_dir" || true
|
||||
echo "Error: image directory not found: $image_dir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
temp_list=$(mktemp --suffix=.txt)
|
||||
raw_video=""
|
||||
trap 'rm -f "$temp_list" "$raw_video" 2>/dev/null || true' EXIT
|
||||
|
||||
find "$image_dir" -type f -name "*.jpg" | sort | while read -r img; do
|
||||
@@ -56,6 +67,8 @@ done > "$temp_list"
|
||||
|
||||
num_images=$(wc -l < "$temp_list")
|
||||
if [[ $num_images -lt 1 ]]; then
|
||||
"$SCRIPT_DIR/notify.sh" "FAILED: sunrise $current_date" \
|
||||
"No images found in sunrise window" || true
|
||||
echo "No images found in sunrise window."
|
||||
exit 1
|
||||
fi
|
||||
@@ -78,17 +91,39 @@ fi
|
||||
|
||||
# ── Step 1: Raw video from images ─────────────────────────────────────────────
|
||||
raw_video=$(mktemp --suffix=.mp4)
|
||||
echo "Step 1/2: encoding raw video..."
|
||||
ffmpeg -loglevel warning \
|
||||
echo "Step 1/3: encoding raw video..."
|
||||
if ! ffmpeg -loglevel warning \
|
||||
-f concat -safe 0 -i "$temp_list" \
|
||||
-c:v libx264 -pix_fmt yuv420p -crf "$CRF_SUNRISE" -vsync 2 -an \
|
||||
-y "$raw_video"
|
||||
-y "$raw_video"; then
|
||||
"$SCRIPT_DIR/notify.sh" "FAILED: sunrise step 1/3 (encode) $current_date" \
|
||||
"ffmpeg raw encode from images failed — check: journalctl -u sky-cam-sunrise.service" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
raw_dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$raw_video")
|
||||
speed_factor=$(echo "scale=3; $raw_dur / $SUNRISE_TARGET_SECS" | bc)
|
||||
echo "Raw: ${raw_dur}s speed factor: ${speed_factor}x"
|
||||
|
||||
# ── Step 2: Speed-adjust + sunrise time overlay ───────────────────────────────
|
||||
# ── Step 2: Speed-adjust — saved permanently so overlay failure is recoverable ─
|
||||
# Deleted automatically if step 3 succeeds.
|
||||
sped_video="$output_dir/$current_date-daily-sunrise-sped.mp4"
|
||||
echo "Step 2/3: speed-adjust → $sped_video"
|
||||
if ! ffmpeg -loglevel warning \
|
||||
-i "$raw_video" \
|
||||
-vf "setpts=PTS/${speed_factor}" \
|
||||
-c:v libx264 -pix_fmt yuv420p -crf "$CRF_SUNRISE" -an \
|
||||
-y "$sped_video"; then
|
||||
rm -f "$sped_video"
|
||||
"$SCRIPT_DIR/notify.sh" "FAILED: sunrise step 2/3 (speed) $current_date" \
|
||||
"speed-adjust failed — no video saved" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sped_dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$sped_video")
|
||||
echo "Speed-adjusted: ${sped_dur}s (saved — overlay still pending)"
|
||||
|
||||
# ── Build overlay filter ──────────────────────────────────────────────────────
|
||||
# Time displayed as stacked characters down the right side (e.g. 0/7/:/2/3),
|
||||
# semi-transparent with a soft drop shadow so it reads on any background.
|
||||
SR_TIME=$(echo "$sunrise_time_local" | cut -d'-' -f1,2 | tr '-' ':')
|
||||
@@ -104,14 +139,23 @@ DT="${DT}:line_spacing=4"
|
||||
DT="${DT}:x=w-tw-18:y=(h-th)/2"
|
||||
DT="${DT}:shadowcolor=black@0.55:shadowx=1:shadowy=1"
|
||||
|
||||
# ── Step 3: Overlay — sunrise time burned in ──────────────────────────────────
|
||||
# If this fails, $sped_video survives at its permanent path for manual recovery.
|
||||
final_video="$output_dir/$current_date-daily-sunrise.mp4"
|
||||
echo "Step 2/2: speed-adjust + overlay → $final_video"
|
||||
|
||||
ffmpeg -loglevel warning \
|
||||
-i "$raw_video" \
|
||||
-vf "setpts=PTS/${speed_factor},${DT}" \
|
||||
echo "Step 3/3: overlay → $final_video"
|
||||
if ! ffmpeg -loglevel warning \
|
||||
-i "$sped_video" \
|
||||
-vf "${DT}" \
|
||||
-c:v libx264 -pix_fmt yuv420p -crf "$CRF_SUNRISE" -an \
|
||||
-y "$final_video"
|
||||
-y "$final_video"; then
|
||||
"$SCRIPT_DIR/notify.sh" "FAILED: sunrise overlay $current_date" \
|
||||
"Overlay failed — speed-only video saved: $(basename "$sped_video")" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
actual_dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$final_video")
|
||||
echo "Done: $final_video (${actual_dur}s, sunrise at ${SR_TIME})"
|
||||
|
||||
rm -f "$sped_video"
|
||||
"$SCRIPT_DIR/notify.sh" "Sunrise ready: $current_date" \
|
||||
"$(basename "$final_video") — ${actual_dur}s, sunrise at ${SR_TIME}" || true
|
||||
|
||||
Reference in New Issue
Block a user