Merge pull request #6 from outis1one/claude/seasonal-sunrise-montage-nn268
Claude/seasonal sunrise montage nn268
This commit is contained in:
@@ -12,6 +12,7 @@ set -x
|
|||||||
|
|
||||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||||
source "$SCRIPT_DIR/sky-cam.conf"
|
source "$SCRIPT_DIR/sky-cam.conf"
|
||||||
|
export TIMEZONE # make it visible to season_info.py subprocess
|
||||||
|
|
||||||
# ── Configuration ──────────────────────────────────────────────────────────────
|
# ── Configuration ──────────────────────────────────────────────────────────────
|
||||||
base_dir="$BASE_DIR"
|
base_dir="$BASE_DIR"
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ fi
|
|||||||
# Output the sunrise time in UTC
|
# Output the sunrise time in UTC
|
||||||
echo "Sunrise time (UTC): $sunrise_time"
|
echo "Sunrise time (UTC): $sunrise_time"
|
||||||
|
|
||||||
# Set the time zone to Eastern US time (America/New_York)
|
# Export timezone so date and subprocesses use the configured local time.
|
||||||
export TZ="America/New_York"
|
export TZ="$TIMEZONE"
|
||||||
|
|
||||||
# Convert sunrise time from UTC to Eastern Time (ET)
|
# Convert sunrise time from UTC to local time.
|
||||||
sunrise_time_et=$(TZ="America/New_York" date -d "$sunrise_time" +"%H-%M-%S")
|
sunrise_time_et=$(TZ="$TIMEZONE" date -d "$sunrise_time" +"%H-%M-%S")
|
||||||
|
|
||||||
# Output the converted sunrise time in Eastern Time
|
# Output the converted sunrise time in Eastern Time
|
||||||
echo "Sunrise time (Eastern Time): $sunrise_time_et"
|
echo "Sunrise time (Eastern Time): $sunrise_time_et"
|
||||||
@@ -46,9 +46,9 @@ time_to_seconds() {
|
|||||||
# Convert sunrise time (in Eastern Time) to seconds since midnight
|
# Convert sunrise time (in Eastern Time) to seconds since midnight
|
||||||
sunrise_seconds=$(time_to_seconds "$sunrise_time_et")
|
sunrise_seconds=$(time_to_seconds "$sunrise_time_et")
|
||||||
|
|
||||||
# Calculate the start and end times (60 minutes before sunrise and 15 minutes after sunrise)
|
# Calculate the capture window around sunrise.
|
||||||
start_seconds=$((sunrise_seconds - 70 * 60)) # 60 minutes before sunrise
|
start_seconds=$((sunrise_seconds - SUNRISE_PRE_MIN * 60))
|
||||||
end_seconds=$((sunrise_seconds + 10 * 60)) # 20 minutes after sunrise
|
end_seconds=$((sunrise_seconds + SUNRISE_POST_MIN * 60))
|
||||||
|
|
||||||
# Output the start and end times in seconds for debugging
|
# Output the start and end times in seconds for debugging
|
||||||
echo "Start seconds: $start_seconds"
|
echo "Start seconds: $start_seconds"
|
||||||
@@ -110,18 +110,16 @@ echo "Initial video duration: $video_duration"
|
|||||||
IFS=':' read -r hours minutes seconds <<< $(echo $video_duration | cut -d '.' -f1) # Extract time
|
IFS=':' read -r hours minutes seconds <<< $(echo $video_duration | cut -d '.' -f1) # Extract time
|
||||||
total_seconds=$(($hours * 3600 + $minutes * 60 + $seconds)) # Convert to total seconds
|
total_seconds=$(($hours * 3600 + $minutes * 60 + $seconds)) # Convert to total seconds
|
||||||
|
|
||||||
# Target video duration: 10 seconds
|
target_duration=$SUNRISE_TARGET_SECS
|
||||||
target_duration=8
|
|
||||||
|
|
||||||
# Calculate the speed-up factor to make the video fit into the target duration of 10 seconds
|
|
||||||
speed_up_factor=$(echo "scale=3; $total_seconds / $target_duration" | bc)
|
speed_up_factor=$(echo "scale=3; $total_seconds / $target_duration" | bc)
|
||||||
echo "Calculated speed-up factor: $speed_up_factor"
|
echo "Calculated speed-up factor: $speed_up_factor"
|
||||||
|
|
||||||
# Output filename for the second movie (speed-adjusted)
|
# Output filename for the second movie (speed-adjusted)
|
||||||
final_video="$output_dir/$current_date-sunrise-10s.mp4"
|
final_video="$output_dir/$current_date-daily-sunrise.mp4"
|
||||||
|
|
||||||
# Apply the speed adjustment using the setpts filter
|
# Apply the speed adjustment using the setpts filter
|
||||||
echo "Adjusting video speed to target duration of 10 seconds..."
|
echo "Adjusting video speed to ${SUNRISE_TARGET_SECS}s..."
|
||||||
ffmpeg -i "$first_movie" -filter:v "setpts=PTS/$speed_up_factor" -y "$final_video"
|
ffmpeg -i "$first_movie" -filter:v "setpts=PTS/$speed_up_factor" -y "$final_video"
|
||||||
|
|
||||||
# Check the duration of the adjusted video
|
# Check the duration of the adjusted video
|
||||||
+1
-2
@@ -12,8 +12,7 @@ source "$SCRIPT_DIR/sky-cam.conf"
|
|||||||
|
|
||||||
# ── Configuration ──────────────────────────────────────────────────────────────
|
# ── Configuration ──────────────────────────────────────────────────────────────
|
||||||
base_dir="$BASE_DIR"
|
base_dir="$BASE_DIR"
|
||||||
FULLDAY_FPS=5 # timelapse frame rate — adjust to taste
|
# FULLDAY_FPS and RETENTION_DAYS come from sky-cam.conf
|
||||||
RETENTION_DAYS=10 # full-day videos older than this are deleted
|
|
||||||
|
|
||||||
# ── Date / paths ──────────────────────────────────────────────────────────────
|
# ── Date / paths ──────────────────────────────────────────────────────────────
|
||||||
yesterday=$(date --date="yesterday" +%Y-%m-%d)
|
yesterday=$(date --date="yesterday" +%Y-%m-%d)
|
||||||
|
|||||||
+1
-1
@@ -77,7 +77,7 @@ echo " wrote sky-cam-notify-failure@.service"
|
|||||||
# Sunrise video → Mattermost (run after sunrise window ends)
|
# Sunrise video → Mattermost (run after sunrise window ends)
|
||||||
write_service "sky-cam-sunrise" \
|
write_service "sky-cam-sunrise" \
|
||||||
"daily sunrise video → Mattermost" \
|
"daily sunrise video → Mattermost" \
|
||||||
"sunrise_video.10s.sh" \
|
"daily_sunrise_video.sh" \
|
||||||
"After=network-online.target\nWants=network-online.target\n"
|
"After=network-online.target\nWants=network-online.target\n"
|
||||||
write_timer "sky-cam-sunrise" "daily sunrise video" "*-*-* 09:00:00"
|
write_timer "sky-cam-sunrise" "daily sunrise video" "*-*-* 09:00:00"
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
|
||||||
source "$SCRIPT_DIR/sky-cam.conf"
|
source "$SCRIPT_DIR/sky-cam.conf"
|
||||||
|
export TIMEZONE # make it visible to season_info.py subprocess
|
||||||
|
|
||||||
# ── Configuration ──────────────────────────────────────────────────────────────
|
# ── Configuration ──────────────────────────────────────────────────────────────
|
||||||
base_dir="$BASE_DIR"
|
base_dir="$BASE_DIR"
|
||||||
|
|||||||
+81
-2
@@ -37,7 +37,7 @@
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# You run / schedule:
|
# You run / schedule:
|
||||||
# sunrise_video.10s.sh — daily at 09:00 (via systemd)
|
# daily_sunrise_video.sh — daily at 09:00 (via systemd)
|
||||||
# grabs today's sunrise images, makes a 10-second
|
# grabs today's sunrise images, makes a 10-second
|
||||||
# video, uploads it to Mattermost
|
# video, uploads it to Mattermost
|
||||||
#
|
#
|
||||||
@@ -72,8 +72,76 @@
|
|||||||
# Helpers (called by the scripts above, not run directly):
|
# Helpers (called by the scripts above, not run directly):
|
||||||
# notify.sh — sends notifications via ntfy / email / Mattermost
|
# notify.sh — sends notifications via ntfy / email / Mattermost
|
||||||
# season_info.py — outputs astronomical season/movement/year for a date
|
# season_info.py — outputs astronomical season/movement/year for a date
|
||||||
# sunrise.py — outputs today's sunrise time (used by sunrise_video)
|
# sunrise.py — outputs today's sunrise time (used by daily_sunrise_video)
|
||||||
# sunrise2mm.py — uploads the sunrise video to Mattermost
|
# sunrise2mm.py — uploads the sunrise video to Mattermost
|
||||||
|
# sunrise_overlay.py — burns a timestamp overlay onto the sunrise video
|
||||||
|
#
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# FILE DEPENDENCIES — who calls whom, and what to update if you rename a file
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# sky-cam.conf (this file)
|
||||||
|
# ← sourced by every .sh script; read by sunrise.py, sunrise2mm.py
|
||||||
|
# → if renamed: update the 'source' line at the top of ALL scripts
|
||||||
|
# (don't rename it — just edit it in place)
|
||||||
|
#
|
||||||
|
# install.sh
|
||||||
|
# ← run manually; reads this conf
|
||||||
|
# → if renamed: update the note at the top of this conf file only
|
||||||
|
# generates → systemd unit files (sky-cam-*.service / .timer)
|
||||||
|
# and sky-cam-notify-failure@.service
|
||||||
|
#
|
||||||
|
# daily_sunrise_video.sh
|
||||||
|
# ← called by systemd sky-cam-sunrise.timer (09:00)
|
||||||
|
# → if renamed: update install.sh (write_service call, line ~80)
|
||||||
|
# then re-run install.sh to regenerate the unit
|
||||||
|
# calls → sunrise.py, sunrise_overlay.py, sunrise2mm.py
|
||||||
|
#
|
||||||
|
# 4-seasons.sh
|
||||||
|
# ← called by systemd sky-cam-4seasons.timer (01:00)
|
||||||
|
# → if renamed: update install.sh (write_service call, line ~86)
|
||||||
|
# then re-run install.sh
|
||||||
|
# calls → season_info.py, montage-mvt.sh
|
||||||
|
#
|
||||||
|
# fullday-video.sh
|
||||||
|
# ← called by systemd sky-cam-fullday.timer (02:00)
|
||||||
|
# → if renamed: update install.sh (write_service call, line ~93)
|
||||||
|
# then re-run install.sh
|
||||||
|
#
|
||||||
|
# montage-mvt.sh
|
||||||
|
# ← called by 4-seasons.sh on the last day of each movement
|
||||||
|
# → if renamed: update 4-seasons.sh (the exec line near the bottom)
|
||||||
|
# calls → season_info.py, notify.sh, year-end-join.sh
|
||||||
|
#
|
||||||
|
# year-end-join.sh
|
||||||
|
# ← called by montage-mvt.sh at end of Autumn Mvt 3
|
||||||
|
# → if renamed: update montage-mvt.sh (the exec line at the bottom)
|
||||||
|
# calls → notify.sh
|
||||||
|
#
|
||||||
|
# notify.sh
|
||||||
|
# ← called by montage-mvt.sh, year-end-join.sh
|
||||||
|
# also referenced in install.sh for the OnFailure= failure template
|
||||||
|
# → if renamed: update montage-mvt.sh, year-end-join.sh, install.sh
|
||||||
|
#
|
||||||
|
# season_info.py
|
||||||
|
# ← called by 4-seasons.sh and montage-mvt.sh
|
||||||
|
# → if renamed: update 4-seasons.sh and montage-mvt.sh (the eval lines)
|
||||||
|
#
|
||||||
|
# sunrise.py
|
||||||
|
# ← called by daily_sunrise_video.sh
|
||||||
|
# → if renamed: update daily_sunrise_video.sh
|
||||||
|
#
|
||||||
|
# sunrise_overlay.py
|
||||||
|
# ← called by daily_sunrise_video.sh
|
||||||
|
# → if renamed: update daily_sunrise_video.sh
|
||||||
|
#
|
||||||
|
# sunrise2mm.py
|
||||||
|
# ← called by daily_sunrise_video.sh
|
||||||
|
# → if renamed: update daily_sunrise_video.sh
|
||||||
|
#
|
||||||
|
# stitch-cameras.py
|
||||||
|
# ← run manually only; no script calls it
|
||||||
|
# → safe to rename with no other changes needed
|
||||||
#
|
#
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
@@ -96,6 +164,17 @@ LATITUDE=38.123456
|
|||||||
LONGITUDE=-97.654321
|
LONGITUDE=-97.654321
|
||||||
TIMEZONE=America/New_York
|
TIMEZONE=America/New_York
|
||||||
|
|
||||||
|
# ── Sunrise video tuning ──────────────────────────────────────────────────────
|
||||||
|
# How many minutes before/after sunrise to include in the daily clip.
|
||||||
|
SUNRISE_PRE_MIN=70
|
||||||
|
SUNRISE_POST_MIN=10
|
||||||
|
# Target duration (seconds) for the speed-adjusted sunrise video.
|
||||||
|
SUNRISE_TARGET_SECS=10
|
||||||
|
|
||||||
|
# ── Full-day timelapse tuning ─────────────────────────────────────────────────
|
||||||
|
FULLDAY_FPS=5 # frame rate of the timelapse video
|
||||||
|
RETENTION_DAYS=10 # delete full-day videos older than this many days
|
||||||
|
|
||||||
# ── Mattermost — daily sunrise upload ─────────────────────────────────────────
|
# ── Mattermost — daily sunrise upload ─────────────────────────────────────────
|
||||||
mattermost_url=https://your-mattermost-server.example.com
|
mattermost_url=https://your-mattermost-server.example.com
|
||||||
access_token=your-access-token-here
|
access_token=your-access-token-here
|
||||||
|
|||||||
+1
-2
@@ -53,8 +53,7 @@ if not os.path.isdir(output_dir):
|
|||||||
print(f"Error: The directory {output_dir} does not exist. The video may not have been created yet.")
|
print(f"Error: The directory {output_dir} does not exist. The video may not have been created yet.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# Find the sunrise video file for today (e.g., 2024-11-05-sunrise-10s.mp4)
|
final_video_file = os.path.join(output_dir, f"{today_date_str}-daily-sunrise.mp4")
|
||||||
final_video_file = os.path.join(output_dir, f"{today_date_str}-sunrise-10s.mp4")
|
|
||||||
|
|
||||||
# Debugging: print the full path of the video file to make sure it's correct
|
# Debugging: print the full path of the video file to make sure it's correct
|
||||||
print(f"Looking for video file: {final_video_file}")
|
print(f"Looking for video file: {final_video_file}")
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ OnFailure=sky-cam-notify-failure@%n.service
|
|||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
# ── Edit this path ────────────────────────────────────────────────────────────
|
# ── Edit this path ────────────────────────────────────────────────────────────
|
||||||
ExecStart=/home/motion/drives/local-2tb/sunrise-scripts/sunrise_video.10s.sh
|
ExecStart=/home/motion/drives/local-2tb/sunrise-scripts/daily_sunrise_video.sh
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
StandardError=journal
|
StandardError=journal
|
||||||
|
|||||||
Reference in New Issue
Block a user