Removes dependency on MotionEye or any NVR software. Everything is now
CLI/ffmpeg configured entirely from sky-cam.conf.
capture.sh
Long-running systemd service (one per camera) that pulls frames from the
camera's RTSP stream at CAPTURE_INTERVAL seconds, writing HH-MM-SS.jpg
into BASE_DIR/<cam>/YYYY-MM-DD/. Restarts at midnight for the new date
directory; auto-reconnects on camera disconnect.
sunrise-audio-capture.sh
One-shot service triggered at 03:00. Waits until (sunrise minus
SUNRISE_PRE_MIN minus AUDIO_PRE_BUFFER_MIN), then records the RTSP audio
stream for the full sunrise window. Output deleted after mixing.
daily_sunrise_video.sh
Step 3 now mixes in sunrise-audio.m4a when AUDIO_ENABLED=true and the
file exists. Audio is centred on actual sunrise time at natural speed
while the video plays as the sped-up timelapse. Uses filter_complex
when audio is present (can't combine -vf with -filter_complex).
install.sh
Generates sky-cam-capture-<cam>.service for each camera with CAM_RTSP_<cam>
set, and sky-cam-audio-capture.{service,timer} when AUDIO_ENABLED=true.
sky-cam.conf
New settings: CAM_RTSP_<cam>, CAPTURE_INTERVAL, AUDIO_ENABLED,
AUDIO_PRE_BUFFER_MIN, CAPTURE_AUDIO_BITRATE.
https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
81 lines
2.9 KiB
Bash
Executable File
81 lines
2.9 KiB
Bash
Executable File
#!/bin/bash
|
||
# sunrise-audio-capture.sh — record the camera's RTSP audio stream during the
|
||
# sunrise window so daily_sunrise_video.sh can mix in natural ambient sound
|
||
# (birds, rain, wind) at real speed while the video plays as a timelapse.
|
||
#
|
||
# Triggered daily at 03:00 by sky-cam-audio-capture.timer.
|
||
# Waits internally until (sunrise − SUNRISE_PRE_MIN − AUDIO_PRE_BUFFER_MIN),
|
||
# then records for the full window. Exits immediately if AUDIO_ENABLED≠true.
|
||
#
|
||
# Output: BASE_DIR/SUNRISE_CAM/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 wait and record duration ───────────────────────────────────────
|
||
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")
|
||
buffer_sec=$(( ${AUDIO_PRE_BUFFER_MIN:-2} * 60 ))
|
||
record_start_sec=$(( sunrise_sec - SUNRISE_PRE_MIN * 60 - buffer_sec ))
|
||
record_dur_sec=$(( (SUNRISE_PRE_MIN + SUNRISE_POST_MIN) * 60 + buffer_sec ))
|
||
|
||
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="$BASE_DIR/$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)"
|