Merge pull request #48 from outis1one/clDemoe/seasonal-sunrise-montage-nn268

ClDemoe/seasonal sunrise montage nn268
This commit is contained in:
Outis
2026-04-23 08:03:12 -04:00
committed by GitHub
4 changed files with 51 additions and 28 deletions
+19 -20
View File
@@ -95,34 +95,33 @@ trap cleanup EXIT
mapfile -t all_images < <(find "$image_dir" -type f -name "*.jpg" | sort)
# Validate each frame: skip empty files, corrupt JPEGs, and optionally grey/uniform frames.
# SEASONS_GREY_STDDEV_MIN=0 (default) disables the grey filter.
# Set to e.g. 5 in sky-cam.conf to drop uniform grey frames (bad-signal captures).
# Validate each frame: skip empty files and optionally uniform-colour bad-signal frames.
# SEASONS_GREY_STDDEV_MIN=0 (default) disables the content check entirely.
# When enabled, large files (> SEASONS_LARGE_FRAME_BYTES, default 1 MB) are trusted
# as good without running the expensive ImageMagick check — only sub-1MB frames
# are inspected. This keeps the filter fast even on days with 40k+ images.
GREY_MIN="${SEASONS_GREY_STDDEV_MIN:-0}"
GREY_DARK_FLOOR="${SEASONS_GREY_DARK_FLOOR:-30}" # frames darker than this are never skipped
GREY_DARK_FLOOR="${SEASONS_GREY_DARK_FLOOR:-30}"
LARGE_BYTES="${SEASONS_LARGE_FRAME_BYTES:-1048576}" # files above this skip content check
images=(); bad=0; grey=0
for img in "${all_images[@]}"; do
# Empty or unreadable
# Skip empty or unreadable files (0-byte writes from camera reconnects)
if [ ! -r "$img" ] || [ ! -s "$img" ]; then
echo "WARNING: skipping empty/missing frame: $(basename "$img")"
((bad++)) || true; continue
fi
# Corrupt JPEG — ffprobe can't identify any video stream
if ! ffprobe -v quiet -select_streams v:0 \
-show_entries stream=codec_name -of csv=p=0 "$img" 2>/dev/null \
| grep -q .; then
echo "WARNING: skipping corrupt frame: $(basename "$img")"
((bad++)) || true; continue
fi
# Optional: skip uniform-grey bad-signal frames.
# A frame is bad-signal if it is BOTH uniform (low stddev) AND not dark.
# Night frames are dark so they pass even with low stddev.
# Optional: skip uniform-colour bad-signal frames (green, grey, etc.).
# Only runs ImageMagick on files below SEASONS_LARGE_FRAME_BYTES — large files
# are always good and skip the check entirely.
if [ "$GREY_MIN" != "0" ] && command -v convert &>/dev/null; then
read -r stddev mean < <(convert "$img" -colorspace Gray \
-format "%[fx:int(standard_deviation*255)] %[fx:int(mean*255)]" \
info: 2>/dev/null || echo "255 128")
if [ "${stddev:-255}" -lt "$GREY_MIN" ] && [ "${mean:-0}" -gt "$GREY_DARK_FLOOR" ]; then
((grey++)) || true; continue
fsize=$(stat -c%s "$img" 2>/dev/null || echo 0)
if [ "$fsize" -lt "$LARGE_BYTES" ]; then
read -r stddev mean < <(convert "$img" -colorspace Gray \
-format "%[fx:int(standard_deviation*255)] %[fx:int(mean*255)]" \
info: 2>/dev/null || echo "255 128")
if [ "${stddev:-255}" -lt "$GREY_MIN" ] && [ "${mean:-0}" -gt "$GREY_DARK_FLOOR" ]; then
((grey++)) || true; continue
fi
fi
fi
images+=("$img")
+17
View File
@@ -234,6 +234,23 @@ Attribution data for every file is written to `sunrise-sounds/manifest.json`.
./4-seasons.sh east
```
**Re-run a daily seasons clip** for a specific past date:
```bash
./4-seasons.sh east 2026-04-19
```
**Backfill multiple past dates** (useful after a camera outage or a fresh install with existing images):
```bash
for d in 2026-04-15 2026-04-16 2026-04-17 2026-04-18 2026-04-19; do
./4-seasons.sh east "$d"
done
```
Replace the date list with whatever range you need. Each run produces one `*-final.mp4` in the movement's output directory. Once all days for a movement are present you can build the montage manually:
```bash
./montage-mvt.sh east 2026-04-19 # date of the last day of that movement
```
**Rebuild a movement montage** (e.g. to retry audio after a failure):
```bash
./montage-mvt.sh east # uses today's date
+5 -3
View File
@@ -356,10 +356,10 @@ if $step3b_ok; then
-name "*-daily-sunrise-test.mp4" \
-mtime +"$demo_retain" -print -delete 2>/dev/null | wc -l)
[ "$deleted_demo" -gt 0 ] && \
echo "Demo retention: deleted $deleted_demo test file(s) older than ${demo_retain} days"
echo "Demo retention: deleted $deleted_demo test file(s) older than ${demo_retain} days" || true
fi
else
[ -f "${cam_audio:-}" ] && rm -f "${cam_audio:-}"
[ -f "${cam_audio:-}" ] && rm -f "${cam_audio:-}" || true
"$SCRIPT_DIR/notify.sh" "Sunrise ready: $current_date" \
"$(basename "$final_video")${actual_dur}s, sunrise at ${SR_TIME} | $final_video" || true
@@ -370,7 +370,9 @@ if $step3b_ok; then
-path "*/sunrise-only/*-daily-sunrise.mp4" \
-mtime +"$retain" -print -delete 2>/dev/null | wc -l)
[ "$deleted_old" -gt 0 ] && \
echo "Retention: deleted $deleted_old sunrise video(s) older than ${retain} days"
echo "Retention: deleted $deleted_old sunrise video(s) older than ${retain} days" || true
fi
fi
fi
exit 0
+10 -5
View File
@@ -256,18 +256,23 @@ ENCODE_PRESET=slow # ffmpeg preset for all encodes (slow/medium/fast)
AUDIO_BITRATE=192k # montage-mvt.sh — music track on movement montages
# ── Frame validation (4-seasons.sh) ──────────────────────────────────────────
# Corrupt or empty frames (e.g. first frame after a camera reconnect) are always
# skipped automatically via ffprobe. No config needed.
# Empty (0-byte) frames are always skipped. No config needed for that.
#
# SEASONS_GREY_STDDEV_MIN / SEASONS_GREY_DARK_FLOOR — optional bad-signal filter.
# Catches uniform-colour frames caused by a bad RTSP signal: solid green, grey, etc.
# These are valid JPEGs but contain no real image content.
# Uncomment both lines to enable. A frame is dropped only when BOTH are true:
# 1. pixel standard deviation (0255) < SEASONS_GREY_STDDEV_MIN (frame is uniform)
# 2. mean brightness (0255) > SEASONS_GREY_DARK_FLOOR (frame is not dark)
# This keeps genuine night frames (dark + low variation) while dropping
# solid-grey bad-signal frames (mid-bright + no variation).
# Night frames are dark so they always pass even if stddev is low.
# Requires ImageMagick (convert). Start with these values and tune from there:
#SEASONS_GREY_STDDEV_MIN=5 # skip if stdev < 5 (very uniform)
#SEASONS_GREY_STDDEV_MIN=5 # skip if stdev < 5 (very uniform colour)
#SEASONS_GREY_DARK_FLOOR=30 # …but only if mean brightness > 30 (not a night frame)
#
# Performance: ImageMagick is only called on files below SEASONS_LARGE_FRAME_BYTES.
# Files above that threshold are always good and skip the check entirely.
# Default 1 MB — adjust if your camera produces larger bad-signal frames.
#SEASONS_LARGE_FRAME_BYTES=1048576
# ── Montage attribution overlay ───────────────────────────────────────────────
# A translucent bar across the top of each movement montage, naming the