Files
sky-cam/sunrise-audio-capture.sh
T
Claude 7c5a703222 Fix sky-cam-audio-capture.service spurious failure on no-op retention
The retention block ended with `[ test ] && echo`, which under `set -e`
returns exit 1 when `deleted` is 0 — the normal case on most days. As
the script's last command, that bash exit propagated to systemd, which
marked the unit failed and fired the OnFailure ntfy even though the
audio file was written successfully.

Add `|| true` and an explicit `exit 0` so a no-op retention pass is
treated as success.
2026-04-29 18:33:03 +00:00

97 lines
3.6 KiB
Bash
Executable File

#!/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/<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 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
retain="${SUNRISE_AUDIO_RETENTION_DAYS:-7}"
if [ "$retain" -gt 0 ]; then
audio_root="${AUDIO_DIR:-$BASE_DIR/audio}/sunrise/$CAM"
deleted=$(find "$audio_root" -name "sunrise-audio.m4a" -mtime +"$retain" -print -delete 2>/dev/null | wc -l)
[ "$deleted" -gt 0 ] && echo "Retention: deleted $deleted sunrise audio clip(s) older than ${retain}d" || true
fi
exit 0