#!/bin/bash # sunrise-audio-capture.sh — record exactly SUNRISE_TARGET_SECS of audio # centred on the actual sunrise moment, so daily_sunrise_video.sh can mix in # real ambient sound (birds, rain, wind) at natural speed. # # Triggered at 03:00 by sky-cam-audio-capture.timer; waits internally until # the right moment before recording. Exits immediately if AUDIO_ENABLED≠true. # # Recording window: floor(TARGET/2) seconds before sunrise, # ceil(TARGET/2) seconds after (odd second goes to post). # # Output: BASE_DIR//YYYY-MM-DD/sunrise-audio.m4a # Deleted automatically by daily_sunrise_video.sh after mixing. set -euo pipefail SCRIPT_DIR="$(dirname "$(realpath "$0")")" source "$SCRIPT_DIR/sky-cam.conf" export TZ="$TIMEZONE" CAM="${1:-$SUNRISE_CAM}" if [ "${AUDIO_ENABLED:-false}" != "true" ]; then echo "AUDIO_ENABLED is not true — skipping." exit 0 fi rtsp_var="CAM_RTSP_${CAM}" RTSP_URL="${!rtsp_var:-}" if [ -z "$RTSP_URL" ]; then echo "ERROR: CAM_RTSP_${CAM} not set in sky-cam.conf" exit 1 fi # ── Sunrise time ────────────────────────────────────────────────────────────── sunrise_time=$(python3 "$SCRIPT_DIR/sunrise.py") if [ -z "$sunrise_time" ]; then "$SCRIPT_DIR/notify.sh" "FAILED: audio capture — no sunrise time" \ "sunrise.py returned nothing — check internet/location config" || true exit 1 fi sunrise_time_local=$(TZ="$TIMEZONE" date -d "$sunrise_time" +"%H:%M:%S") echo "Sunrise (local): $sunrise_time_local" # ── Calculate recording window centred on sunrise ───────────────────────────── time_to_seconds() { IFS=':' read -r h m s <<< "$1"; echo $((10#$h*3600 + 10#$m*60 + 10#$s)); } 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)" midnight=$(date -d "today 00:00:00" +%s) now_day_sec=$(( $(date +%s) - midnight )) wait_sec=$(( record_start_sec - now_day_sec )) if [ "$wait_sec" -gt 0 ]; then echo "Waiting ${wait_sec}s until audio window ($(date -d "@$(( midnight + record_start_sec ))" '+%H:%M:%S'))..." sleep "$wait_sec" fi today=$(date +%Y-%m-%d) dir="${AUDIO_DIR:-$BASE_DIR/audio}/sunrise/$CAM/$today" mkdir -p "$dir" output="$dir/sunrise-audio.m4a" echo "Recording ${record_dur_sec}s of audio → $output" if ! ffmpeg -loglevel warning \ -rtsp_transport tcp \ -i "$RTSP_URL" \ -t "$record_dur_sec" \ -vn \ -acodec aac -b:a "${CAPTURE_AUDIO_BITRATE:-96k}" \ -y "$output"; then "$SCRIPT_DIR/notify.sh" "FAILED: audio capture $today" \ "ffmpeg audio recording failed — sunrise video will have no audio" || true exit 1 fi size=$(du -h "$output" | cut -f1) echo "Audio capture complete: $output (${record_dur_sec}s, $size)" # Rolling retention for sunrise audio clips # Guard with [ -d ] so find never exits non-zero under set -euo pipefail, # which would cause the service to report failure even after a clean capture. retain="${SUNRISE_AUDIO_RETENTION_DAYS:-7}" if [ "$retain" -gt 0 ]; then audio_root="${AUDIO_DIR:-$BASE_DIR/audio}/sunrise/$CAM" if [ -d "$audio_root" ]; then deleted=$(find "$audio_root" -name "sunrise-audio.m4a" -mtime +"$retain" -print -delete 2>/dev/null | wc -l) || true [ "$deleted" -gt 0 ] && echo "Retention: deleted $deleted sunrise audio clip(s) older than ${retain}d" || true fi fi exit 0