From 9ea03d2249be5555b15143ea7a04d40791b18dbd Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Apr 2026 00:46:39 +0000 Subject: [PATCH 1/3] Replace \$EDITOR with nano in README and bootstrap instructions https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ --- README.md | 2 +- bootstrap.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 88df55b..c51888d 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ cd /opt/sky-cam ### 3. Configure ```bash -$EDITOR sky-cam.conf +nano sky-cam.conf ``` `SCRIPT_DIR` and `BASE_DIR` are auto-detected — you only need to fill in settings specific to your setup: diff --git a/bootstrap.sh b/bootstrap.sh index 8bb45ea..f0c3e42 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -35,4 +35,4 @@ echo "" echo " 3. cd $TARGET && ./install.sh" echo " This generates .env.example — copy it to .env and add credentials:" echo " cp $TARGET/.env.example $TARGET/.env" -echo " \$EDITOR $TARGET/.env" +echo " nano $TARGET/.env" From 64cec6b7694c3c1bac4288fb491205920f7411af Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Apr 2026 00:53:58 +0000 Subject: [PATCH 2/3] Rename default camera from 'sunrise' to 'east' for compass consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cameras are now named by direction (east, north, south, west) throughout config defaults, examples, and documentation. The config key SUNRISE_CAM is unchanged — it still means 'which camera faces east and gets the sunrise job'. Only the camera instance name value changes from 'sunrise' to 'east'. sky-cam.conf: CAMERAS=(east), SUNRISE_CAM=east, SCHEDULE_*_east, example comments updated to show all four compass points. README.md: all command examples updated (4-seasons.sh east, journalctl sky-cam-capture-east, etc.) — phenomenon references ('sunrise window', 'sunrise time') left unchanged. bootstrap.sh: example updated to show compass directions. https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ --- README.md | 20 ++++++++++---------- bootstrap.sh | 2 +- sky-cam.conf | 15 +++++++++------ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c51888d..bd03103 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ nano sky-cam.conf | `BASE_DIR` | Root where camera images live — override if storing on a separate drive (`BASE_DIR///.jpg`) | | `MOVIES_DIR` | Where finished videos are written (default: `BASE_DIR/movies`) | | `MUSIC_DIR` | Directory containing the 12 Vivaldi Four Seasons MP3 files | -| `CAMERAS` | Space-separated list of camera names, e.g. `(sunrise north)` | +| `CAMERAS` | Space-separated list of camera names, e.g. `(east north south west)` | | `SUNRISE_CAM` | Which camera faces east and gets the sunrise job | | `LATITUDE` / `LONGITUDE` / `TIMEZONE` | Your location for sunrise calculation | | `CAPTURE_INTERVAL` | Seconds between captured frames (default: 10) | @@ -90,8 +90,8 @@ Re-run `./install.sh` any time `sky-cam.conf` changes (schedules, cameras, etc.) ```bash # Confirm cameras are capturing -systemctl --user status sky-cam-capture-sunrise.service -ls BASE_DIR/sunrise/$(date +%Y-%m-%d)/ # images should appear within CAPTURE_INTERVAL seconds +systemctl --user status sky-cam-capture-east.service +ls BASE_DIR/east/$(date +%Y-%m-%d)/ # images should appear within CAPTURE_INTERVAL seconds # Check all timers are scheduled systemctl --user list-timers 'sky-cam-*' @@ -222,29 +222,29 @@ Attribution data for every file is written to `sunrise-sounds/manifest.json`. **Re-run a daily seasons clip** for yesterday: ```bash -./4-seasons.sh sunrise +./4-seasons.sh east ``` **Rebuild a movement montage** (e.g. to retry audio after a failure): ```bash ./montage-mvt.sh # uses today's movement -./montage-mvt.sh 2025-06-15 sunrise # specific date + camera +./montage-mvt.sh 2025-06-15 east # specific date + camera ``` **Rebuild the year-end video**: ```bash -./year-end-join.sh 2025 sunrise +./year-end-join.sh 2025 east ``` **Check capture status**: ```bash -systemctl --user status sky-cam-capture-sunrise.service -journalctl --user -u sky-cam-capture-sunrise.service -f +systemctl --user status sky-cam-capture-east.service +journalctl --user -u sky-cam-capture-east.service -f ``` **Check logs**: ```bash journalctl --user -u sky-cam-sunrise.service -journalctl --user -u sky-cam-seasons-sunrise.service -journalctl --user -u sky-cam-fullday-sunrise.service +journalctl --user -u sky-cam-seasons-east.service +journalctl --user -u sky-cam-fullday-east.service ``` diff --git a/bootstrap.sh b/bootstrap.sh index f0c3e42..affc2d7 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -28,7 +28,7 @@ echo " 2. Edit $TARGET/sky-cam.conf" echo " — SCRIPT_DIR full path to the directory you'll run scripts from" echo " — BASE_DIR where your camera images live" echo " — MUSIC_DIR path to your Vivaldi Four Seasons audio files" -echo " — CAMERAS list of camera names, e.g. (sunrise)" +echo " — CAMERAS list of camera names, e.g. (east) or (east north south west)" echo " — SUNRISE_CAM which camera faces east (gets the sunrise video job)" echo " — LATITUDE / LONGITUDE / TIMEZONE your location" echo "" diff --git a/sky-cam.conf b/sky-cam.conf index ab7c8e6..09d0ddb 100644 --- a/sky-cam.conf +++ b/sky-cam.conf @@ -180,8 +180,8 @@ TIMEZONE=America/New_York # Each name becomes a subfolder under BASE_DIR (images) and BASE_DIR/movies. # To add a camera: add its name here, add its schedules below, re-run install.sh. # -CAMERAS=(sunrise) # e.g. CAMERAS=(sunrise north west) -SUNRISE_CAM=sunrise # which camera faces east (gets the sunrise video job) +CAMERAS=(east) # e.g. CAMERAS=(east north south west) +SUNRISE_CAM=east # which camera faces east (gets the sunrise video job) # ── Schedules ───────────────────────────────────────────────────────────────── # All times are HH:MM:SS (24-hour local time). @@ -207,15 +207,18 @@ SUNRISE_CAM=sunrise # which camera faces east (gets the sunrise v # SCHEDULE_SUNRISE=03:00:00 -SCHEDULE_SEASONS_sunrise=01:00:00 -SCHEDULE_FULLDAY_sunrise=02:00:00 +SCHEDULE_SEASONS_east=01:00:00 +SCHEDULE_FULLDAY_east=02:00:00 # Uncomment and fill in for each camera you add to CAMERAS above: #SCHEDULE_SEASONS_north=01:30:00 #SCHEDULE_FULLDAY_north=02:30:00 # -#SCHEDULE_SEASONS_west=02:00:00 -#SCHEDULE_FULLDAY_west=03:00:00 +#SCHEDULE_SEASONS_south=02:00:00 +#SCHEDULE_FULLDAY_south=03:00:00 +# +#SCHEDULE_SEASONS_west=02:30:00 +#SCHEDULE_FULLDAY_west=03:30:00 # ── Sunrise video tuning ────────────────────────────────────────────────────── # Capture window around sunrise: From 8b9ad74c5847634a80abd51c7c390c026db491f9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 20 Apr 2026 01:01:25 +0000 Subject: [PATCH 3/3] Fix six bugs found in final audit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit montage-mvt.sh, year-end-join.sh: CAM_NAME fallback referenced undefined \$CAM_NAME — crashes under set -euo pipefail on manual runs without args. Fixed to fall back to \$SUNRISE_CAM (same fix applied earlier to other scripts). notify.sh: Mattermost notification guard only checked MM_NOTIFY_CHANNEL_ID, not mattermost_url or access_token. If those are unset, curl would send a malformed request silently. Added guards for all three required values. install.sh: seasons/fullday service units had literal \n in After=/Wants= lines because bash does not interpret \n in heredoc variable expansions. Changed to \$'...' syntax so actual newlines are written, making valid systemd unit files. Also: audio capture timer now uses \$SCHEDULE_SUNRISE instead of hardcoded 03:00, keeping it in sync if the user changes the schedule. sunrise-audio-capture.sh: record_start_sec could theoretically go negative (sunrise very early + large SUNRISE_TARGET_SECS). Added floor-at-zero guard. daily_sunrise_video.sh: added comment explaining why audio_offset is always 0. README.md: fix CAM_RTSP_sunrise example to CAM_RTSP_east. https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ --- README.md | 2 +- daily_sunrise_video.sh | 2 +- install.sh | 7 ++++--- montage-mvt.sh | 2 +- notify.sh | 2 +- sunrise-audio-capture.sh | 1 + year-end-join.sh | 2 +- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bd03103..70ba407 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ $EDITOR .env ```bash # RTSP stream URL — one per camera (variable name matches camera name) -CAM_RTSP_sunrise=rtsp://admin:password@192.168.1.100:554/stream1 +CAM_RTSP_east=rtsp://admin:password@192.168.1.100:554/stream1 # Mattermost upload mattermost_url=https://your-mattermost.example.com diff --git a/daily_sunrise_video.sh b/daily_sunrise_video.sh index a338ebf..d5f15a9 100644 --- a/daily_sunrise_video.sh +++ b/daily_sunrise_video.sh @@ -168,7 +168,7 @@ fade_out=$(echo "scale=1; $SUNRISE_TARGET_SECS - 0.5" | bc) # ── Pick audio source ───────────────────────────────────────────────────────── audio_src="" -audio_offset="0" +audio_offset="0" # cam audio is pre-centred on sunrise; library files are trimmed to fit cam_audio="$image_dir/sunrise-audio.m4a" if [ "${AUDIO_ENABLED:-false}" = "true" ]; then diff --git a/install.sh b/install.sh index b343297..a43ec26 100755 --- a/install.sh +++ b/install.sh @@ -144,14 +144,15 @@ EOF done # ── Sunrise audio capture ───────────────────────────────────────────────────── -# Triggered at 03:00; waits internally until the right time before recording. +# Uses the same schedule as the sunrise video — both start early and wait +# internally for the right moment, so they don't interfere. if [ "${AUDIO_ENABLED:-false}" = "true" ]; then write_service "sky-cam-audio-capture" \ "$SUNRISE_CAM: sunrise audio capture" \ "sunrise-audio-capture.sh" write_timer "sky-cam-audio-capture" \ "$SUNRISE_CAM: sunrise audio capture" \ - "03:00:00" + "$SCHEDULE_SUNRISE" timers+=("sky-cam-audio-capture") fi @@ -166,7 +167,7 @@ for cam in "${CAMERAS[@]}"; do write_service "sky-cam-seasons-${cam}" \ "${cam}: Four Seasons daily clip" \ "4-seasons.sh ${cam}" \ - "After=network-online.target\nWants=network-online.target\n" + $'After=network-online.target\nWants=network-online.target\n' write_timer "sky-cam-seasons-${cam}" "${cam}: Four Seasons daily clip" \ "${!sched_seasons_var}" timers+=("sky-cam-seasons-${cam}") diff --git a/montage-mvt.sh b/montage-mvt.sh index 9fc08a1..49b7d7c 100755 --- a/montage-mvt.sh +++ b/montage-mvt.sh @@ -24,7 +24,7 @@ export TIMEZONE # make it visible to season_info.py subprocess # Args: [date] [camera-name] # Camera name: second argument overrides conf (passed through from 4-seasons.sh). -CAM_NAME="${2:-$CAM_NAME}" +CAM_NAME="${2:-$SUNRISE_CAM}" # ── Configuration ────────────────────────────────────────────────────────────── base_dir="$BASE_DIR" diff --git a/notify.sh b/notify.sh index 00086ce..8f580f9 100755 --- a/notify.sh +++ b/notify.sh @@ -52,7 +52,7 @@ fi # ── Mattermost text post ────────────────────────────────────────────────────── # mattermost_url and access_token come from sky-cam.conf (sourced above). -if [ "$MM_NOTIFY_ENABLED" = "true" ] && [ -n "$MM_NOTIFY_CHANNEL_ID" ]; then +if [ "$MM_NOTIFY_ENABLED" = "true" ] && [ -n "$MM_NOTIFY_CHANNEL_ID" ] && [ -n "${mattermost_url:-}" ] && [ -n "${access_token:-}" ]; then curl -s \ -H "Authorization: Bearer $access_token" \ -H "Content-Type: application/json" \ diff --git a/sunrise-audio-capture.sh b/sunrise-audio-capture.sh index 7cc3068..6dfff83 100755 --- a/sunrise-audio-capture.sh +++ b/sunrise-audio-capture.sh @@ -49,6 +49,7 @@ sunrise_sec=$(time_to_seconds "$sunrise_time_local") half_pre=$(( SUNRISE_TARGET_SECS / 2 )) # floor — pre-sunrise portion half_post=$(( SUNRISE_TARGET_SECS - half_pre )) # ceil — post-sunrise gets odd second record_start_sec=$(( sunrise_sec - half_pre )) +[ "$record_start_sec" -lt 0 ] && record_start_sec=0 record_dur_sec=$SUNRISE_TARGET_SECS echo "Audio window: ${half_pre}s before → ${half_post}s after sunrise (${record_dur_sec}s total)" diff --git a/year-end-join.sh b/year-end-join.sh index 178fb59..d8430f5 100755 --- a/year-end-join.sh +++ b/year-end-join.sh @@ -21,7 +21,7 @@ if [ -z "$ASTRO_YEAR" ]; then exit 1 fi # Camera name: second argument overrides conf (passed through from montage-mvt.sh). -CAM_NAME="${2:-$CAM_NAME}" +CAM_NAME="${2:-$SUNRISE_CAM}" year_dir="$MOVIES_DIR/$CAM_NAME/$ASTRO_YEAR"