Auto-detect SCRIPT_DIR/BASE_DIR; sunrise waits for capture window; optional overlay

sky-cam.conf:
- SCRIPT_DIR auto-detects from its own location via BASH_SOURCE — no manual
  path entry needed after bootstrap; override still works via environment.
- BASE_DIR defaults to \$SCRIPT_DIR/data; MOVIES_DIR defaults to \$BASE_DIR/movies.
  Override either to point at a drive/mount as before.
- SCHEDULE_SUNRISE changed to 03:00 — the script now waits internally until
  the capture window closes before touching images, so the schedule just needs
  to be early enough, not timed exactly to sunrise.
- Schedule section rewritten to explain what each job does and what day's data
  it processes (SEASONS/FULLDAY always process yesterday).
- SUNRISE_PRE_MIN/POST_MIN comments explain the window and its relationship to
  SUNRISE_TARGET_SECS.
- SUNRISE_OVERLAY_ENABLED=true added; set false to skip the timestamp entirely.

daily_sunrise_video.sh:
- After calculating the capture window, sleep until end_sec+30s if we fired
  before the window finished — guarantees all images are present.
- DT (drawtext filter) is only built when SUNRISE_OVERLAY_ENABLED=true.
- Step 3b skips ffmpeg entirely when overlay is disabled, moving work_video
  directly to final_video (faster, no re-encode).

https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
This commit is contained in:
Claude
2026-04-20 00:18:43 +00:00
parent a1cf1304e4
commit be714affc0
2 changed files with 96 additions and 47 deletions
+56 -32
View File
@@ -48,6 +48,17 @@ start_sec=$((sunrise_sec - SUNRISE_PRE_MIN * 60))
end_sec=$((sunrise_sec + SUNRISE_POST_MIN * 60))
echo "Window: $((start_sec/3600)):$(printf '%02d' $(((start_sec%3600)/60)))$((end_sec/3600)):$(printf '%02d' $(((end_sec%3600)/60)))"
# ── Wait for capture window to finish ────────────────────────────────────────
# The timer fires early (default 03:00); we sleep internally so images from
# the full window are available before we start encoding.
midnight=$(date -d "today 00:00:00" +%s)
now_day_sec=$(( $(date +%s) - midnight ))
if [ "$now_day_sec" -lt "$end_sec" ]; then
wait_sec=$(( end_sec - now_day_sec + 30 ))
echo "Waiting ${wait_sec}s for capture window to finish (ends $(date -d "@$(( midnight + end_sec ))" '+%H:%M:%S'))..."
sleep "$wait_sec"
fi
# ── Collect images in window ──────────────────────────────────────────────────
if [ ! -d "$image_dir" ]; then
"$SCRIPT_DIR/notify.sh" "FAILED: sunrise $current_date" \
@@ -126,21 +137,20 @@ 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.
# ── Build overlay filter (skipped if SUNRISE_OVERLAY_ENABLED=false) ──────────
SR_TIME=$(echo "$sunrise_time_local" | cut -d'-' -f1,2 | tr '-' ':')
# Build "H\nH\n:\nM\nM" for vertical stacking in drawtext
SR_VERT=$(echo "$SR_TIME" | awk 'BEGIN{FS=""}{for(i=1;i<=NF;i++){printf "%s",$i; if(i<NF)printf "\\n"}}')
DT="drawtext"
[ -n "$FONT" ] && DT="${DT}=fontfile='${FONT}'" || DT="${DT}"
DT="${DT}:text='${SR_VERT}'"
DT="${DT}:fontcolor=white@${SUNRISE_OVERLAY_OPACITY}"
DT="${DT}:fontsize=h/22"
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"
DT=""
if [ "${SUNRISE_OVERLAY_ENABLED:-true}" = "true" ]; then
SR_VERT=$(echo "$SR_TIME" | awk 'BEGIN{FS=""}{for(i=1;i<=NF;i++){printf "%s",$i; if(i<NF)printf "\\n"}}')
DT="drawtext"
[ -n "$FONT" ] && DT="${DT}=fontfile='${FONT}'" || DT="${DT}"
DT="${DT}:text='${SR_VERT}'"
DT="${DT}:fontcolor=white@${SUNRISE_OVERLAY_OPACITY}"
DT="${DT}:fontsize=h/22"
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"
fi
# ── Step 3: Audio mix + overlay — each independently optional/fallible ────────
# Step 3a: mixes audio into a temp copy of the sped video (video stream is
@@ -203,29 +213,43 @@ if [ -n "$audio_src" ]; then
fi
fi
# ── Step 3b: burn overlay ─────────────────────────────────────────────────────
echo "Step 3b/3: overlay → $final_video"
# ── Step 3b: burn overlay (or promote work_video directly if disabled) ────────
if $has_audio; then audio_out_flags=(-c:a copy); else audio_out_flags=(-an); fi
if ffmpeg -loglevel warning \
-i "$work_video" \
-vf "${DT}" \
-c:v libx264 -pix_fmt yuv420p -crf "$CRF_SUNRISE" \
"${audio_out_flags[@]}" \
-y "$final_video"; then
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" "$temp_audio"; temp_audio=""
[ -f "$cam_audio" ] && rm -f "$cam_audio"
"$SCRIPT_DIR/notify.sh" "Sunrise ready: $current_date" \
"$(basename "$final_video")${actual_dur}s, sunrise at ${SR_TIME}" || true
step3b_ok=false
if [ -n "$DT" ]; then
echo "Step 3b/3: overlay → $final_video"
if ffmpeg -loglevel warning \
-i "$work_video" \
-vf "${DT}" \
-c:v libx264 -pix_fmt yuv420p -crf "$CRF_SUNRISE" \
"${audio_out_flags[@]}" \
-y "$final_video"; then
step3b_ok=true
else
if $has_audio; then promote_label="audio-mixed"; else promote_label="speed-only"; fi
mv "$work_video" "$final_video"
[ "$work_video" != "$sped_video" ] && rm -f "$sped_video"
temp_audio=""
[ -f "$cam_audio" ] && rm -f "$cam_audio"
echo "Overlay failed — promoting ${promote_label} video as upload target"
"$SCRIPT_DIR/notify.sh" "WARNING: sunrise overlay failed $current_date" \
"Overlay failed — uploading ${promote_label} video (no timestamp)" || true
step3b_ok=true # degraded but recoverable — upload still fires
fi
else
if $has_audio; then promote_label="audio-mixed"; else promote_label="speed-only"; fi
echo "Step 3b/3: overlay disabled — promoting as final"
mv "$work_video" "$final_video"
[ "$work_video" != "$sped_video" ] && rm -f "$sped_video"
temp_audio=""
step3b_ok=true
fi
if $step3b_ok; then
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" "$temp_audio" 2>/dev/null || true; temp_audio=""
[ -f "$cam_audio" ] && rm -f "$cam_audio"
echo "Overlay failed — promoting ${promote_label} video as upload target"
"$SCRIPT_DIR/notify.sh" "WARNING: sunrise overlay failed $current_date" \
"Overlay failed — uploading ${promote_label} video (no timestamp)" || true
"$SCRIPT_DIR/notify.sh" "Sunrise ready: $current_date" \
"$(basename "$final_video")${actual_dur}s, sunrise at ${SR_TIME}" || true
fi