Files
sky-cam/install.sh
T
Claude 7486916f9f Sunrise time overlay; systemd upload separation; bug fixes
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
2026-04-19 16:35:33 +00:00

164 lines
5.6 KiB
Bash
Executable File

#!/bin/bash
# install.sh — generate and install sky-cam systemd units from sky-cam.conf.
#
# Usage:
# ./install.sh # installs to ~/.config/systemd/user (no root needed)
# ./install.sh --system # installs to /etc/systemd/system (needs sudo)
#
# Run this once after editing sky-cam.conf, and again whenever sky-cam.conf
# changes (e.g. SCRIPT_DIR moves, cameras added, schedules changed).
# No other file needs editing.
set -euo pipefail
HERE="$(dirname "$(realpath "$0")")"
source "$HERE/sky-cam.conf"
# ── Install target ────────────────────────────────────────────────────────────
SYSTEM_MODE=false
[ "${1:-}" = "--system" ] && SYSTEM_MODE=true
if $SYSTEM_MODE; then
UNIT_DIR="/etc/systemd/system"
SC="sudo systemctl"
else
UNIT_DIR="$HOME/.config/systemd/user"
SC="systemctl --user"
fi
mkdir -p "$UNIT_DIR"
echo "Installing systemd units to $UNIT_DIR ..."
# ── Helper: write a oneshot service unit ─────────────────────────────────────
write_service() {
local unit="$1" description="$2" script="$3" extra="${4:-}"
cat > "$UNIT_DIR/${unit}.service" <<EOF
[Unit]
Description=Sky-Cam — $description
${extra}OnFailure=sky-cam-notify-failure@%n.service
[Service]
Type=oneshot
ExecStart=$SCRIPT_DIR/$script
StandardOutput=journal
StandardError=journal
EOF
echo " wrote ${unit}.service"
}
# ── Helper: write a timer unit ───────────────────────────────────────────────
write_timer() {
local unit="$1" description="$2" calendar="$3"
cat > "$UNIT_DIR/${unit}.timer" <<EOF
[Unit]
Description=Sky-Cam — $description
[Timer]
OnCalendar=*-*-* $calendar
Persistent=true
[Install]
WantedBy=timers.target
EOF
echo " wrote ${unit}.timer"
}
# ── Failure notification template ────────────────────────────────────────────
cat > "$UNIT_DIR/sky-cam-notify-failure@.service" <<EOF
[Unit]
Description=Sky-Cam notify on failure for %i
[Service]
Type=oneshot
ExecStart=$SCRIPT_DIR/notify.sh "sky-cam job failed: %i" "systemd unit %i failed — check: journalctl -u %i"
EOF
echo " wrote sky-cam-notify-failure@.service"
# ── Sunrise video — SUNRISE_CAM only ─────────────────────────────────────────
# OnSuccess= triggers the upload service only when video creation succeeds.
cat > "$UNIT_DIR/sky-cam-sunrise.service" <<EOF
[Unit]
Description=Sky-Cam — $SUNRISE_CAM: daily sunrise video
After=network-online.target
Wants=network-online.target
OnFailure=sky-cam-notify-failure@%n.service
OnSuccess=sky-cam-sunrise-upload.service
[Service]
Type=oneshot
ExecStart=$SCRIPT_DIR/daily_sunrise_video.sh
StandardOutput=journal
StandardError=journal
EOF
echo " wrote sky-cam-sunrise.service"
cat > "$UNIT_DIR/sky-cam-sunrise-upload.service" <<EOF
[Unit]
Description=Sky-Cam — $SUNRISE_CAM: upload daily sunrise to Mattermost
After=network-online.target
Wants=network-online.target
OnFailure=sky-cam-notify-failure@%n.service
[Service]
Type=oneshot
ExecStart=$SCRIPT_DIR/sunrise2mm.py
StandardOutput=journal
StandardError=journal
EOF
echo " wrote sky-cam-sunrise-upload.service"
write_timer "sky-cam-sunrise" "$SUNRISE_CAM: daily sunrise video" "$SCHEDULE_SUNRISE"
timers=(sky-cam-sunrise)
# ── Per-camera Four Seasons and full-day jobs ─────────────────────────────────
# Reads CAMERAS, SCHEDULE_SEASONS_<cam>, SCHEDULE_FULLDAY_<cam> from sky-cam.conf.
# Scripts receive the camera name as $1 so they know which camera to process.
for cam in "${CAMERAS[@]}"; do
sched_seasons_var="SCHEDULE_SEASONS_${cam}"
sched_fullday_var="SCHEDULE_FULLDAY_${cam}"
if [ -n "${!sched_seasons_var:-}" ]; then
write_service "sky-cam-seasons-${cam}" \
"${cam}: Four Seasons daily clip" \
"4-seasons.sh ${cam}" \
"After=network-online.target\nWants=network-online.target\n"
write_timer "sky-cam-seasons-${cam}" "${cam}: Four Seasons daily clip" \
"${!sched_seasons_var}"
timers+=("sky-cam-seasons-${cam}")
else
echo " WARNING: SCHEDULE_SEASONS_${cam} not set — skipping seasons timer for ${cam}"
fi
if [ -n "${!sched_fullday_var:-}" ]; then
write_service "sky-cam-fullday-${cam}" \
"${cam}: full-day timelapse" \
"fullday-video.sh ${cam}"
write_timer "sky-cam-fullday-${cam}" "${cam}: full-day timelapse" \
"${!sched_fullday_var}"
timers+=("sky-cam-fullday-${cam}")
else
echo " WARNING: SCHEDULE_FULLDAY_${cam} not set — skipping fullday timer for ${cam}"
fi
done
# ── Reload and enable ─────────────────────────────────────────────────────────
echo ""
$SC daemon-reload
for timer in "${timers[@]}"; do
$SC enable --now "${timer}.timer" \
&& echo " enabled + started ${timer}.timer" \
|| echo " WARNING: could not enable ${timer}.timer"
done
echo ""
echo "Done. Check status with:"
if $SYSTEM_MODE; then
echo " sudo systemctl list-timers 'sky-cam-*'"
echo " sudo journalctl -u sky-cam-seasons-${CAMERAS[0]}.service -f"
else
echo " systemctl --user list-timers 'sky-cam-*'"
echo " journalctl --user -u sky-cam-seasons-${CAMERAS[0]}.service -f"
fi