diff --git a/4-seasons.sh b/4-seasons.sh index 4890c83..54a903e 100755 --- a/4-seasons.sh +++ b/4-seasons.sh @@ -11,10 +11,11 @@ set -euo pipefail set -x SCRIPT_DIR="$(dirname "$(realpath "$0")")" +source "$SCRIPT_DIR/sky-cam.conf" # ── Configuration ────────────────────────────────────────────────────────────── -base_dir="/home/motion/drives/local-2tb" -music_base_dir="$base_dir/music/4 Seasons" +base_dir="$BASE_DIR" +music_base_dir="$MUSIC_DIR" [ ! -d "$music_base_dir" ] && music_base_dir="$SCRIPT_DIR/music" # ── Date setup ──────────────────────────────────────────────────────────────── diff --git a/fullday-video.sh b/fullday-video.sh index 955f29f..be9fcf2 100755 --- a/fullday-video.sh +++ b/fullday-video.sh @@ -8,9 +8,10 @@ set -euo pipefail SCRIPT_DIR="$(dirname "$(realpath "$0")")" +source "$SCRIPT_DIR/sky-cam.conf" # ── Configuration ────────────────────────────────────────────────────────────── -base_dir="/home/motion/drives/local-2tb" +base_dir="$BASE_DIR" FULLDAY_FPS=5 # timelapse frame rate — adjust to taste RETENTION_DAYS=10 # full-day videos older than this are deleted diff --git a/montage-mvt.sh b/montage-mvt.sh index 3159c19..8ae114e 100755 --- a/montage-mvt.sh +++ b/montage-mvt.sh @@ -19,10 +19,11 @@ set -euo pipefail SCRIPT_DIR="$(dirname "$(realpath "$0")")" +source "$SCRIPT_DIR/sky-cam.conf" # ── Configuration ────────────────────────────────────────────────────────────── -base_dir="/home/motion/drives/local-2tb" -music_base_dir="$base_dir/music/4 Seasons" +base_dir="$BASE_DIR" +music_base_dir="$MUSIC_DIR" [ ! -d "$music_base_dir" ] && music_base_dir="$SCRIPT_DIR/music" FADE_DUR=2.0 # video + audio fade in/out (seconds) diff --git a/notify.sh b/notify.sh index fad536c..00086ce 100755 --- a/notify.sh +++ b/notify.sh @@ -10,19 +10,18 @@ set -euo pipefail SCRIPT_DIR="$(dirname "$(realpath "$0")")" -CONFIG="$SCRIPT_DIR/notify_config.txt" +CONFIG="$SCRIPT_DIR/sky-cam.conf" TITLE="${1:-Sky-Cam notification}" BODY="${2:-}" # ── Load config ─────────────────────────────────────────────────────────────── if [ ! -f "$CONFIG" ]; then - echo "notify.sh: config not found at $CONFIG — skipping notifications" >&2 + echo "notify.sh: sky-cam.conf not found — skipping notifications" >&2 exit 0 fi -# Source only the known keys; ignore comments and blank lines. -eval "$(grep -E '^[A-Z_]+=.*' "$CONFIG" | grep -v '^#')" +source "$CONFIG" NTFY_ENABLED="${NTFY_ENABLED:-false}" NTFY_URL="${NTFY_URL:-}" @@ -52,23 +51,15 @@ if [ "$EMAIL_ENABLED" = "true" ] && [ -n "$EMAIL_TO" ]; then fi # ── Mattermost text post ────────────────────────────────────────────────────── -# Uses the same mattermost_config.txt as sunrise2mm.py but posts to -# MM_NOTIFY_CHANNEL_ID (can be the same channel or a private admin channel). +# mattermost_url and access_token come from sky-cam.conf (sourced above). if [ "$MM_NOTIFY_ENABLED" = "true" ] && [ -n "$MM_NOTIFY_CHANNEL_ID" ]; then - MM_CONFIG="/home/motion/drives/local-2tb/sunrise-scripts/mattermost_config.txt" - [ ! -f "$MM_CONFIG" ] && MM_CONFIG="$SCRIPT_DIR/mattermost_config.txt" - if [ -f "$MM_CONFIG" ]; then - eval "$(grep -E '^(mattermost_url|access_token)=' "$MM_CONFIG")" - curl -s \ - -H "Authorization: Bearer $access_token" \ - -H "Content-Type: application/json" \ - -d "{\"channel_id\":\"$MM_NOTIFY_CHANNEL_ID\",\"message\":\"**$TITLE**\n$BODY\"}" \ - "${mattermost_url}/api/v4/posts" > /dev/null \ - && echo "notify: mattermost sent" \ - || echo "notify: mattermost failed" >&2 - else - echo "notify: mattermost_config.txt not found — skipping MM notify" >&2 - fi + curl -s \ + -H "Authorization: Bearer $access_token" \ + -H "Content-Type: application/json" \ + -d "{\"channel_id\":\"$MM_NOTIFY_CHANNEL_ID\",\"message\":\"**$TITLE**\n$BODY\"}" \ + "${mattermost_url}/api/v4/posts" > /dev/null \ + && echo "notify: mattermost sent" \ + || echo "notify: mattermost failed" >&2 fi exit 0 diff --git a/notify_config.txt b/notify_config.txt deleted file mode 100644 index c8334d2..0000000 --- a/notify_config.txt +++ /dev/null @@ -1,22 +0,0 @@ -# notify_config.txt — sky-cam notification settings -# Each method is independently toggled. Set to true and fill in the value. - -# ── ntfy (push notifications via ntfy.sh or self-hosted ntfy) ───────────────── -# Self-host: https://docs.ntfy.sh/install/ -# Cloud: sign up at https://ntfy.sh, pick a topic name -NTFY_ENABLED=false -NTFY_URL=https://ntfy.sh/your-topic-here - -# ── Email ───────────────────────────────────────────────────────────────────── -# Requires the 'mail' command (e.g. mailutils or s-nail package). -# For outbound SMTP relay, configure /etc/ssmtp/ssmtp.conf or msmtp. -EMAIL_ENABLED=false -EMAIL_TO=you@example.com -EMAIL_FROM=skycam@localhost - -# ── Mattermost text post ────────────────────────────────────────────────────── -# Posts a plain-text notification (no video attachment) to the given channel. -# Reuses the URL and access_token from mattermost_config.txt. -# MM_NOTIFY_CHANNEL_ID can be the same daily-upload channel or a separate one. -MM_NOTIFY_ENABLED=false -MM_NOTIFY_CHANNEL_ID=your-channel-id-here diff --git a/sky-cam.conf b/sky-cam.conf new file mode 100644 index 0000000..ef170a0 --- /dev/null +++ b/sky-cam.conf @@ -0,0 +1,33 @@ +# sky-cam.conf — single config for all sky-cam scripts and Python helpers. +# +# Bash scripts source this file: +# source "$(dirname "$(realpath "$0")")/sky-cam.conf" +# +# Python reads it with key=value parsing (same format, quotes stripped). +# +# Copy this file to your scripts directory and fill in every value. +# Lines starting with # are comments and are ignored. + +# ── Paths ───────────────────────────────────────────────────────────────────── +BASE_DIR=/home/motion/drives/local-2tb +MUSIC_DIR=/home/motion/drives/local-2tb/music/4 Seasons +TIMEZONE=America/New_York + +# ── Mattermost — daily sunrise upload ──────────────────────────────────────── +mattermost_url=https://your-mattermost-server.example.com +access_token=your-access-token-here +channel_id=your-daily-upload-channel-id-here + +# ── Notifications — movement montage + year-end video complete / job failure ── +# ntfy: https://ntfy.sh (cloud) or self-hosted. Set topic URL below. +NTFY_ENABLED=false +NTFY_URL=https://ntfy.sh/your-topic-here + +# Email: requires the 'mail' command (mailutils / s-nail). +EMAIL_ENABLED=false +EMAIL_TO=you@example.com +EMAIL_FROM=skycam@localhost + +# Mattermost text post (can be same channel as daily upload or a private one). +MM_NOTIFY_ENABLED=false +MM_NOTIFY_CHANNEL_ID=your-notify-channel-id-here diff --git a/sky-cam.crontab b/sky-cam.crontab deleted file mode 100644 index 1973d05..0000000 --- a/sky-cam.crontab +++ /dev/null @@ -1,26 +0,0 @@ -# sky-cam crontab -# -# Install: crontab sky-cam.crontab -# (or append to existing: crontab -l | cat - sky-cam.crontab | crontab -) -# -# Set SCRIPT_DIR to wherever this repo lives on your machine. -# Logs go to /var/log/sky-cam/ — create it first: -# sudo mkdir -p /var/log/sky-cam && sudo chown $USER /var/log/sky-cam - -SCRIPT_DIR=/home/motion/drives/local-2tb/sunrise-scripts -LOGDIR=/var/log/sky-cam - -# ── Daily sunrise video → Mattermost (run after sunrise window ends) ────────── -# sunrise_video.10s.sh processes today's images, so run well after sunrise. -# Adjust the hour to be safely after your latest local sunrise (~09:00 is fine -# for any timezone in the continental US; change to 10:00 if unsure). -0 9 * * * $SCRIPT_DIR/sunrise_video.10s.sh >> $LOGDIR/sunrise.log 2>&1 - -# ── Daily Four Seasons clip (process yesterday's images, 01:00) ─────────────── -# Also triggers montage-mvt.sh automatically on the last day of each movement, -# which in turn triggers year-end-join.sh after the last Autumn movement. -0 1 * * * $SCRIPT_DIR/4-seasons.sh >> $LOGDIR/4-seasons.log 2>&1 - -# ── Full-day timelapse (process yesterday's images, 02:00) ──────────────────── -# Runs after 4-seasons.sh to avoid disk contention. Deletes videos > 10 days. -0 2 * * * $SCRIPT_DIR/fullday-video.sh >> $LOGDIR/fullday.log 2>&1 diff --git a/sunrise2mm.py b/sunrise2mm.py index 484f56c..e6ad9d5 100644 --- a/sunrise2mm.py +++ b/sunrise2mm.py @@ -2,8 +2,11 @@ import requests import os from datetime import datetime -# Configuration file path (update the path to where your mattermost_config.txt is located) -config_file_path = '/home/motion/drives/local-2tb/sunrise-scripts/mattermost_config.txt' +import pathlib + +# Locate sky-cam.conf next to this script (works regardless of cwd). +_here = pathlib.Path(__file__).resolve().parent +config_file_path = str(_here / 'sky-cam.conf') # Function to read configuration from the config file def read_config(config_file_path): diff --git a/systemd/sky-cam-4seasons.service b/systemd/sky-cam-4seasons.service index 80c4d4c..0f0347f 100644 --- a/systemd/sky-cam-4seasons.service +++ b/systemd/sky-cam-4seasons.service @@ -2,6 +2,7 @@ Description=Sky-Cam Four Seasons daily clip (+ montage trigger on last day) After=network-online.target Wants=network-online.target +OnFailure=sky-cam-notify-failure@%n.service [Service] Type=oneshot diff --git a/systemd/sky-cam-fullday.service b/systemd/sky-cam-fullday.service index f043235..bef3263 100644 --- a/systemd/sky-cam-fullday.service +++ b/systemd/sky-cam-fullday.service @@ -1,5 +1,6 @@ [Unit] Description=Sky-Cam full-day timelapse (10-day retention) +OnFailure=sky-cam-notify-failure@%n.service [Service] Type=oneshot diff --git a/systemd/sky-cam-notify-failure@.service b/systemd/sky-cam-notify-failure@.service new file mode 100644 index 0000000..08cd719 --- /dev/null +++ b/systemd/sky-cam-notify-failure@.service @@ -0,0 +1,10 @@ +[Unit] +Description=Sky-Cam failure notification for %i + +[Service] +Type=oneshot +# %i is the name of the failed unit (passed by OnFailure=) +# Edit ExecStart path to match your install location. +ExecStart=/home/motion/drives/local-2tb/sunrise-scripts/notify.sh \ + "sky-cam job failed: %i" \ + "systemd unit %i exited with failure. Check logs: journalctl -u %i" diff --git a/systemd/sky-cam-sunrise.service b/systemd/sky-cam-sunrise.service index 707cfa2..2f58c2d 100644 --- a/systemd/sky-cam-sunrise.service +++ b/systemd/sky-cam-sunrise.service @@ -2,6 +2,7 @@ Description=Sky-Cam daily sunrise video → Mattermost After=network-online.target Wants=network-online.target +OnFailure=sky-cam-notify-failure@%n.service [Service] Type=oneshot diff --git a/year-end-join.sh b/year-end-join.sh index 61920bf..f0ad1ab 100755 --- a/year-end-join.sh +++ b/year-end-join.sh @@ -13,6 +13,7 @@ set -euo pipefail SCRIPT_DIR="$(dirname "$(realpath "$0")")" +source "$SCRIPT_DIR/sky-cam.conf" ASTRO_YEAR="${1:-}" if [ -z "$ASTRO_YEAR" ]; then @@ -20,7 +21,7 @@ if [ -z "$ASTRO_YEAR" ]; then exit 1 fi -base_dir="/home/motion/drives/local-2tb" +base_dir="$BASE_DIR" script_name=$(basename "$SCRIPT_DIR" | cut -d'-' -f1) year_dir="$base_dir/movies/$script_name/$ASTRO_YEAR"