From be714affc0a1fd18df38320076e3a43ed98f7600 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Apr 2026 00:18:43 +0000 Subject: [PATCH] Auto-detect SCRIPT_DIR/BASE_DIR; sunrise waits for capture window; optional overlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- daily_sunrise_video.sh | 88 +++++++++++++++++++++++++++--------------- sky-cam.conf | 55 +++++++++++++++++++------- 2 files changed, 96 insertions(+), 47 deletions(-) diff --git a/daily_sunrise_video.sh b/daily_sunrise_video.sh index a259fc1..7f418c8 100644 --- a/daily_sunrise_video.sh +++ b/daily_sunrise_video.sh @@ -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/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 diff --git a/sky-cam.conf b/sky-cam.conf index fe6a7b6..8a746c7 100644 --- a/sky-cam.conf +++ b/sky-cam.conf @@ -147,12 +147,17 @@ # ============================================================================= # ── Install location ────────────────────────────────────────────────────────── -# Full path to the directory containing this file and all the scripts. -SCRIPT_DIR=/home/motion/drives/local-2tb/sunrise-scripts +# Auto-detected from where this file lives — override only if you move the +# scripts to a different location after install. +SCRIPT_DIR="${SCRIPT_DIR:-$(dirname "$(realpath "${BASH_SOURCE[0]}")")}" # ── Storage ─────────────────────────────────────────────────────────────────── -BASE_DIR=/home/motion/drives/local-2tb -MOVIES_DIR=$BASE_DIR/movies # override if videos live on a different drive +# BASE_DIR: root folder where camera images are stored. +# Structure created automatically: BASE_DIR//YYYY-MM-DD/HH-MM-SS.jpg +# Defaults to a 'data' subfolder next to the scripts; override to point at +# an external drive or network mount (recommended for production). +BASE_DIR="${BASE_DIR:-$SCRIPT_DIR/data}" +MOVIES_DIR="${MOVIES_DIR:-$BASE_DIR/movies}" # override if videos live on a different drive MUSIC_DIR=/home/motion/drives/local-2tb/music/4 Seasons # ── Location & timezone ─────────────────────────────────────────────────────── @@ -179,14 +184,28 @@ CAMERAS=(sunrise) # e.g. CAMERAS=(sunrise north west) SUNRISE_CAM=sunrise # which camera faces east (gets the sunrise video job) # ── Schedules ───────────────────────────────────────────────────────────────── -# SCHEDULE_SUNRISE when to run daily_sunrise_video.sh (SUNRISE_CAM only) -# SCHEDULE_SEASONS_ when to run 4-seasons.sh for each camera -# SCHEDULE_FULLDAY_ when to run fullday-video.sh for each camera -# -# Times are HH:MM:SS (24-hour). Space cameras at least 30 min apart. +# All times are HH:MM:SS (24-hour local time). # install.sh reads these and generates one systemd timer per camera per job. # -SCHEDULE_SUNRISE=09:00:00 +# SCHEDULE_SUNRISE +# When to START the sunrise video job. The script wakes up, calculates +# today's sunrise time, then WAITS internally until the capture window is +# fully finished before touching any images. Set this early enough to +# cover your earliest possible sunrise minus SUNRISE_PRE_MIN — 03:00 works +# year-round for most locations. The video is ready a few minutes after the +# capture window closes, not at this start time. +# +# SCHEDULE_SEASONS_ (one per camera in CAMERAS) +# When to run the Four Seasons daily clip job. Processes YESTERDAY'S images +# (not today's) — always runs after midnight. On the last day of a season +# movement this automatically triggers the movement montage build. +# Space multiple cameras at least 30 min apart to avoid disk contention. +# +# SCHEDULE_FULLDAY_ (one per camera in CAMERAS) +# When to run the full-day timelapse job. Also processes YESTERDAY'S images. +# Space after SCHEDULE_SEASONS to avoid overlap. +# +SCHEDULE_SUNRISE=03:00:00 SCHEDULE_SEASONS_sunrise=01:00:00 SCHEDULE_FULLDAY_sunrise=02:00:00 @@ -199,12 +218,18 @@ SCHEDULE_FULLDAY_sunrise=02:00:00 #SCHEDULE_FULLDAY_west=03:00:00 # ── Sunrise video tuning ────────────────────────────────────────────────────── -# How many minutes before/after sunrise to include in the daily clip. -SUNRISE_PRE_MIN=70 -SUNRISE_POST_MIN=10 -# Target duration (seconds) for the speed-adjusted sunrise video. +# Capture window around sunrise: +# Images from (sunrise - SUNRISE_PRE_MIN) to (sunrise + SUNRISE_POST_MIN) +# are included in the clip. Larger windows give more context; they are all +# speed-adjusted to fit SUNRISE_TARGET_SECS regardless of window size. +SUNRISE_PRE_MIN=70 # minutes before sunrise to start capturing +SUNRISE_POST_MIN=10 # minutes after sunrise to stop capturing +# Target length of the final sunrise video (seconds). SUNRISE_TARGET_SECS=10 -# Opacity of the sunrise-time overlay (0.0 = invisible, 1.0 = fully opaque). +# Burn the local sunrise time vertically on the right side of the video. +# Set false to skip the overlay entirely (cleaner look, faster encoding). +SUNRISE_OVERLAY_ENABLED=true +# Opacity of the sunrise-time text (0.0 = invisible, 1.0 = fully opaque). SUNRISE_OVERLAY_OPACITY=0.45 # ── Full-day timelapse tuning ─────────────────────────────────────────────────