Each pipeline now saves intermediate files permanently before the step most
likely to fail, so a partial failure leaves a recoverable artifact:
- daily_sunrise_video.sh: speed-adjusted video (*-sped.mp4) survives if the
drawtext overlay step fails; deleted automatically on success
- montage-mvt.sh: speed-adjusted video (*-Sped.mp4) survives if the
music-mux + attribution overlay step fails; deleted on success
- 4-seasons.sh / montage-mvt.sh / year-end-join.sh: explicit ffmpeg error
handling with targeted notify.sh calls naming the failed step and the
surviving artifact path
- montage-mvt.sh / 4-seasons.sh / year-end-join.sh: clip-duration-sum vs
music-duration drift check warns when cumulative float error exceeds 2 s
https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
daily_sunrise_video.sh:
- Fixed: was using undefined \$MOVIES_DIR (now \$BASE_DIR/movies)
- Fixed: sunrise_overlay.py was called but never existed — would fail daily
- Fixed: speed-adjust step had no explicit codec (-c:v libx264 missing)
- New: sunrise time overlaid as stacked vertical characters on the right
side using ffmpeg drawtext — no Python/Pillow dependency
- New: upload removed from script; now triggered by systemd OnSuccess=
- Combines speed-adjust and overlay into one ffmpeg pass (was two)
- SUNRISE_OVERLAY_OPACITY from conf controls transparency
install.sh:
- sky-cam-sunrise.service gains OnSuccess=sky-cam-sunrise-upload.service
so upload only runs when video creation succeeds, with separate log
- New sky-cam-sunrise-upload.service runs sunrise2mm.py
sunrise2mm.py: add shebang + chmod +x so systemd ExecStart= calls it directly
sky-cam.conf: add SUNRISE_OVERLAY_OPACITY=0.45
https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ
Adds six CRF vars, AUDIO_BITRATE, and three MONTAGE_* overlay durations.
Values match previous hardcoded defaults so behavior is unchanged.
The same CRF appeared in several scripts but with intentionally different
values per purpose (28 for draft intermediates, 26 for polished output).
Each script's CRF is now its own variable in conf, so changing one never
silently changes another.
https://claude.ai/code/session_01C4jbd3waXG3eKZYbGUjLUQ