Fix bugs found in post-refactor audit
- verify-mvt.sh: remove dead first _info= line (used MVT_START before defined); fix JPEG size loop to accumulate bytes correctly and display human-readable total; show size in delete confirmation - montage-mvt.sh: grep -c uses || echo 0 instead of || true to be unambiguous about the no-match value under set -e - capture.sh, capture-watchdog.sh: require camera name arg, remove silent SUNRISE_CAM fallback - migrate-seasons.sh: require --cam arg, error if missing - README.md, sky-cam.conf: remove stale fullday-video.sh references; README pipeline diagram updated to show verify-mvt.sh https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
This commit is contained in:
@@ -58,7 +58,6 @@ nano sky-cam.conf
|
|||||||
| `CAPTURE_INTERVAL` | Seconds between captured frames (default: 10) |
|
| `CAPTURE_INTERVAL` | Seconds between captured frames (default: 10) |
|
||||||
| `SCHEDULE_SUNRISE` | When to start the sunrise job — default `03:00`, script waits internally until the capture window closes |
|
| `SCHEDULE_SUNRISE` | When to start the sunrise job — default `03:00`, script waits internally until the capture window closes |
|
||||||
| `SCHEDULE_SEASONS_<cam>` | When to run the Four Seasons daily clip — processes **yesterday's** images; runs after midnight |
|
| `SCHEDULE_SEASONS_<cam>` | When to run the Four Seasons daily clip — processes **yesterday's** images; runs after midnight |
|
||||||
| `SCHEDULE_FULLDAY_<cam>` | When to run the full-day timelapse — also processes yesterday; schedule after SEASONS |
|
|
||||||
|
|
||||||
### 4. Set up credentials
|
### 4. Set up credentials
|
||||||
|
|
||||||
@@ -137,10 +136,9 @@ Camera JPEGs + audio
|
|||||||
│ Step 2: speed-adjust to exactly match music → saved permanently
|
│ Step 2: speed-adjust to exactly match music → saved permanently
|
||||||
│ Step 3: mix music + fades + attribution overlay → Montage.mp4
|
│ Step 3: mix music + fades + attribution overlay → Montage.mp4
|
||||||
│ Last movement of Autumn → triggers year-end-join.sh
|
│ Last movement of Autumn → triggers year-end-join.sh
|
||||||
│
|
│ On completion → notify with verify-mvt.sh command
|
||||||
└─ fullday-video.sh <cam> (runs at SCHEDULE_FULLDAY_<cam>, processes yesterday)
|
└─ verify-mvt.sh <year> <season> <mvt> <cam> (run manually after notification)
|
||||||
Encode all of yesterday's JPEGs at FULLDAY_FPS
|
Review montage, approve to delete source JPEG folders
|
||||||
Delete videos older than RETENTION_DAYS
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Resilience
|
### Resilience
|
||||||
@@ -251,5 +249,4 @@ journalctl --user -u sky-cam-watchdog-east.service -f
|
|||||||
```bash
|
```bash
|
||||||
journalctl --user -u sky-cam-sunrise.service
|
journalctl --user -u sky-cam-sunrise.service
|
||||||
journalctl --user -u sky-cam-seasons-east.service
|
journalctl --user -u sky-cam-seasons-east.service
|
||||||
journalctl --user -u sky-cam-fullday-east.service
|
|
||||||
```
|
```
|
||||||
|
|||||||
+5
-1
@@ -12,7 +12,11 @@ SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
|||||||
source "$SCRIPT_DIR/sky-cam.conf"
|
source "$SCRIPT_DIR/sky-cam.conf"
|
||||||
export TZ="$TIMEZONE"
|
export TZ="$TIMEZONE"
|
||||||
|
|
||||||
CAM="${1:-$SUNRISE_CAM}"
|
CAM="${1:-}"
|
||||||
|
if [ -z "$CAM" ]; then
|
||||||
|
echo "Usage: $0 <camera-name>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
STALE_SECS="${CAPTURE_STALE_SECS:-30}"
|
STALE_SECS="${CAPTURE_STALE_SECS:-30}"
|
||||||
CHECK_INTERVAL=$(( STALE_SECS / 3 ))
|
CHECK_INTERVAL=$(( STALE_SECS / 3 ))
|
||||||
[ "$CHECK_INTERVAL" -lt 5 ] && CHECK_INTERVAL=5
|
[ "$CHECK_INTERVAL" -lt 5 ] && CHECK_INTERVAL=5
|
||||||
|
|||||||
+5
-1
@@ -17,7 +17,11 @@ SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
|||||||
source "$SCRIPT_DIR/sky-cam.conf"
|
source "$SCRIPT_DIR/sky-cam.conf"
|
||||||
export TZ="$TIMEZONE"
|
export TZ="$TIMEZONE"
|
||||||
|
|
||||||
CAM="${1:-$SUNRISE_CAM}"
|
CAM="${1:-}"
|
||||||
|
if [ -z "$CAM" ]; then
|
||||||
|
echo "Usage: $0 <camera-name>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
rtsp_var="CAM_RTSP_${CAM}"
|
rtsp_var="CAM_RTSP_${CAM}"
|
||||||
RTSP_URL="${!rtsp_var:-}"
|
RTSP_URL="${!rtsp_var:-}"
|
||||||
|
|||||||
+5
-1
@@ -41,7 +41,11 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
[ -z "$CAM" ] && CAM="$SUNRISE_CAM"
|
if [ -z "$CAM" ]; then
|
||||||
|
echo "Usage: $0 --cam <camera-name> [--dry-run] [OLD_ROOT]"
|
||||||
|
echo " e.g. $0 --cam east ~/drives/local-2tb/movies/sunrise"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
NEW_ROOT="$MOVIES_DIR/$CAM/2025"
|
NEW_ROOT="$MOVIES_DIR/$CAM/2025"
|
||||||
|
|
||||||
echo "Old archive : $OLD_ROOT"
|
echo "Old archive : $OLD_ROOT"
|
||||||
|
|||||||
+2
-2
@@ -207,8 +207,8 @@ if ffmpeg -loglevel warning \
|
|||||||
actual_dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$output_file")
|
actual_dur=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$output_file")
|
||||||
dur_delta=$(echo "scale=1; $actual_dur - $music_duration" | bc | sed 's/^-//')
|
dur_delta=$(echo "scale=1; $actual_dur - $music_duration" | bc | sed 's/^-//')
|
||||||
stream_types=$(ffprobe -v error -show_entries stream=codec_type -of csv=p=0 "$output_file" 2>/dev/null)
|
stream_types=$(ffprobe -v error -show_entries stream=codec_type -of csv=p=0 "$output_file" 2>/dev/null)
|
||||||
has_video=$(echo "$stream_types" | grep -c "video" || true)
|
has_video=$(echo "$stream_types" | grep -c "video" || echo 0)
|
||||||
has_audio=$(echo "$stream_types" | grep -c "audio" || true)
|
has_audio=$(echo "$stream_types" | grep -c "audio" || echo 0)
|
||||||
checks="duration=${actual_dur}s (drift ${dur_delta}s)"
|
checks="duration=${actual_dur}s (drift ${dur_delta}s)"
|
||||||
[ "$has_video" -gt 0 ] && checks="$checks video=ok" || checks="$checks video=MISSING"
|
[ "$has_video" -gt 0 ] && checks="$checks video=ok" || checks="$checks video=MISSING"
|
||||||
[ "$has_audio" -gt 0 ] && checks="$checks audio=ok" || checks="$checks audio=MISSING"
|
[ "$has_audio" -gt 0 ] && checks="$checks audio=ok" || checks="$checks audio=MISSING"
|
||||||
|
|||||||
+2
-3
@@ -21,9 +21,8 @@
|
|||||||
#
|
#
|
||||||
# systemctl --user daemon-reload
|
# systemctl --user daemon-reload
|
||||||
# systemctl --user enable --now sky-cam-sunrise.timer
|
# systemctl --user enable --now sky-cam-sunrise.timer
|
||||||
# systemctl --user enable --now sky-cam-seasons-sunrise.timer
|
# # one sky-cam-seasons-<cam>.timer per camera, e.g.:
|
||||||
# systemctl --user enable --now sky-cam-fullday-sunrise.timer
|
# systemctl --user enable --now sky-cam-seasons-east.timer
|
||||||
# # one sky-cam-seasons-<cam>.timer and sky-cam-fullday-<cam>.timer per camera
|
|
||||||
#
|
#
|
||||||
# Check status:
|
# Check status:
|
||||||
# systemctl --user list-timers 'sky-cam-*'
|
# systemctl --user list-timers 'sky-cam-*'
|
||||||
|
|||||||
+8
-21
@@ -40,13 +40,7 @@ if [ -z "$montage_file" ] || [ ! -f "$montage_file" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Get movement date range from season_info ──────────────────────────────────
|
# ── Get movement date range from season_info ──────────────────────────────────
|
||||||
_info="$(python3 "$SCRIPT_DIR/season_info.py" "$MVT_START" 2>/dev/null)" 2>/dev/null || true
|
# Extract date from montage filename (format: YYYY-MM-DD_Season_MvtN-Montage.mp4)
|
||||||
|
|
||||||
# Use the sped file's date prefix to find a representative date in the movement
|
|
||||||
sped_file=$(find "$MOVIES_DIR/$CAM_NAME/$ASTRO_YEAR/$SEASON/Mvt${MVT_NUM}" \
|
|
||||||
-maxdepth 1 -name "*-Sped.mp4" 2>/dev/null | head -n 1 || true)
|
|
||||||
|
|
||||||
# Get MVT_START from the montage filename (format: YYYY-MM-DD_Season_MvtN-Montage.mp4)
|
|
||||||
mvt_start_date=$(basename "$montage_file" | cut -d_ -f1)
|
mvt_start_date=$(basename "$montage_file" | cut -d_ -f1)
|
||||||
_info="$(python3 "$SCRIPT_DIR/season_info.py" "$mvt_start_date")"
|
_info="$(python3 "$SCRIPT_DIR/season_info.py" "$mvt_start_date")"
|
||||||
eval "$_info"
|
eval "$_info"
|
||||||
@@ -89,30 +83,23 @@ printf " File size : %s\n" "$file_size"
|
|||||||
printf " Daily clips : %d / %d days\n" "$final_count" "$DAYS_IN_MVT"
|
printf " Daily clips : %d / %d days\n" "$final_count" "$DAYS_IN_MVT"
|
||||||
printf " Music : %s\n" "$(basename "${music_file:-NOT FOUND}")"
|
printf " Music : %s\n" "$(basename "${music_file:-NOT FOUND}")"
|
||||||
|
|
||||||
# Count JPEG folders available for deletion
|
# Count JPEG folders and sum their sizes
|
||||||
jpeg_count=0
|
jpeg_count=0
|
||||||
jpeg_size=0
|
jpeg_bytes=0
|
||||||
d="$MVT_START"
|
d="$MVT_START"
|
||||||
while [[ "$d" < "$MVT_END" || "$d" == "$MVT_END" ]]; do
|
while [[ "$d" < "$MVT_END" || "$d" == "$MVT_END" ]]; do
|
||||||
dir="$BASE_DIR/$CAM_NAME/$d"
|
dir="$BASE_DIR/$CAM_NAME/$d"
|
||||||
if [ -d "$dir" ]; then
|
if [ -d "$dir" ]; then
|
||||||
jpeg_count=$(( jpeg_count + 1 ))
|
jpeg_count=$(( jpeg_count + 1 ))
|
||||||
|
jpeg_bytes=$(( jpeg_bytes + $(du -sb "$dir" 2>/dev/null | cut -f1 || echo 0) ))
|
||||||
fi
|
fi
|
||||||
d=$(date -d "$d + 1 day" +%Y-%m-%d)
|
d=$(date -d "$d + 1 day" +%Y-%m-%d)
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$jpeg_count" -gt 0 ]; then
|
if [ "$jpeg_count" -gt 0 ]; then
|
||||||
jpeg_size=$(du -sh "$BASE_DIR/$CAM_NAME" --exclude="*" 2>/dev/null || true)
|
jpeg_size=$(numfmt --to=iec-i --suffix=B "$jpeg_bytes" 2>/dev/null || echo "${jpeg_bytes}B")
|
||||||
# Sum only the movement date folders
|
printf " JPEG folders : %d date folders, %s (%s → %s)\n" \
|
||||||
total_jpeg_bytes=0
|
"$jpeg_count" "$jpeg_size" "$MVT_START" "$MVT_END"
|
||||||
d="$MVT_START"
|
|
||||||
while [[ "$d" < "$MVT_END" || "$d" == "$MVT_END" ]]; do
|
|
||||||
dir="$BASE_DIR/$CAM_NAME/$d"
|
|
||||||
[ -d "$dir" ] && total_jpeg_bytes=$(du -sb "$dir" 2>/dev/null | cut -f1 || echo 0) || true
|
|
||||||
d=$(date -d "$d + 1 day" +%Y-%m-%d)
|
|
||||||
done
|
|
||||||
printf " JPEG folders : %d date folders (%s → %s)\n" \
|
|
||||||
"$jpeg_count" "$MVT_START" "$MVT_END"
|
|
||||||
else
|
else
|
||||||
printf " JPEG folders : none found (already deleted)\n"
|
printf " JPEG folders : none found (already deleted)\n"
|
||||||
fi
|
fi
|
||||||
@@ -148,7 +135,7 @@ while true; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
echo " Will delete $jpeg_count JPEG date folders ($MVT_START → $MVT_END) for camera [$CAM_NAME]."
|
echo " Will delete $jpeg_count JPEG date folders ($MVT_START → $MVT_END) for camera [$CAM_NAME] — ${jpeg_size}."
|
||||||
echo " The montage video and daily clips are kept."
|
echo " The montage video and daily clips are kept."
|
||||||
read -rp " Confirm? [yes/no]: " confirm
|
read -rp " Confirm? [yes/no]: " confirm
|
||||||
if [ "$confirm" = "yes" ]; then
|
if [ "$confirm" = "yes" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user