generated from me/template-mit
172 lines
5.4 KiB
Bash
Executable File
172 lines
5.4 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# sunset-alarm -- Alert before or after sunset
|
|
# Displays a persistent alert when current time is within
|
|
# (sunset minus specified minutes) of midnight.
|
|
|
|
###############################################################################
|
|
# Defaults
|
|
###############################################################################
|
|
LATLONG=""
|
|
SUNSET_TIME=""
|
|
MINUTES=""
|
|
SUNSET_EPOCH=0
|
|
LAST_DATE=""
|
|
PROMPT="sunset-alarm"
|
|
|
|
###############################################################################
|
|
# Usage
|
|
###############################################################################
|
|
usage() {
|
|
echo "Usage: sunset-alarm (-l LAT:LONG | -t HH24:MI) (-m MINUTES) [-h]" >&2
|
|
exit 1
|
|
}
|
|
|
|
###############################################################################
|
|
# Parse arguments (handles negative values for -m by using "$@")
|
|
###############################################################################
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
-l) LATLONG="$2"; shift 2 ;;
|
|
-t) SUNSET_TIME="$2"; shift 2 ;;
|
|
-m) MINUTES="$2"; shift 2 ;;
|
|
-h) usage ;;
|
|
--) shift; break ;;
|
|
*) echo "Error: unknown argument '$1'" >&2; usage ;;
|
|
esac
|
|
done
|
|
|
|
# Validate inputs
|
|
if [ -z "$MINUTES" ]; then
|
|
echo "Error: -m MINUTES is required." >&2
|
|
usage
|
|
fi
|
|
|
|
if [ -z "$LATLONG" ] && [ -z "$SUNSET_TIME" ]; then
|
|
echo "Error: must specify either -l LAT:LONG or -t HH:MI." >&2
|
|
usage
|
|
fi
|
|
|
|
###############################################################################
|
|
# Internet connectivity check
|
|
###############################################################################
|
|
check_internet() {
|
|
if curl -s --max-time 5 -o /dev/null https://hyperling,com; then
|
|
return 0
|
|
fi
|
|
if curl -s --max-time 5 -o /dev/null https://mullvad.net; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
###############################################################################
|
|
# Get sunset from Open Meteo API
|
|
###############################################################################
|
|
fetch_sunset_time() {
|
|
LAT=$(echo "$LATLONG" | cut -d: -f1)
|
|
LON=$(echo "$LATLONG" | cut -d: -f2)
|
|
|
|
RESPONSE=$(curl -s "https://api.open-meteo.com/v1/forecast?latitude=${LAT}&longitude=${LON}&timezone=auto&daily=sunset&date=today")
|
|
|
|
if [ -z "$RESPONSE" ]; then
|
|
return 1
|
|
fi
|
|
|
|
# Extract sunset timestamp like "2025-06-15T19:32:00"
|
|
SUNSET_RAW=$(echo "$RESPONSE" | grep -o '"sunset":"[^"]*"' | head -1 | sed 's/.*://"//;s/"$//')
|
|
|
|
if [ -z "$SUNSET_RAW" ]; then
|
|
return 1
|
|
fi
|
|
|
|
# Convert to epoch
|
|
SUNSET_EPOCH=$(date -d "$(echo "$SUNSET_RAW" | cut -dT -f1) $(echo "$SUNSET_RAW" | cut -dT -f2)" +%s 2>/dev/null)
|
|
|
|
if [ -z "$SUNSET_EPOCH" ]; then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
###############################################################################
|
|
# Show alert via fallback chain: fyi -> notify-send -> wall
|
|
###############################################################################
|
|
show_alert() {
|
|
TITLE="Sunset Alarm"
|
|
MESSAGE="Sunset is in ${MINUTES} minute(s)."
|
|
|
|
persistent="-t 0 --wait"
|
|
icon="-i weather-clear -u critical"
|
|
|
|
if command -v fyi >/dev/null 2>&1; then
|
|
fyi $icon $persistent "$TITLE" "$MESSAGE"
|
|
elif command -v notify-send >/dev/null 2>&1; then
|
|
notify-send $icon $persistent "$TITLE" "$MESSAGE"
|
|
elif command -v wall >/dev/null 2>&1; then
|
|
echo "${TITLE}: ${MESSAGE}" | wall
|
|
else
|
|
echo "ERROR: No notification tool found." >&2
|
|
echo "Install one of: fyi, notify-send (libnotify-bin), wall (bsd-write)" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
###############################################################################
|
|
# Main loop
|
|
###############################################################################
|
|
while true; do
|
|
TODAY=$(date +%Y-%m-%d)
|
|
CURRENT_TIME=$(date +%s)
|
|
|
|
# Check if we need to fetch new sunset time for a new day
|
|
if [ "$LAST_DATE" != "$TODAY" ]; then
|
|
LAST_DATE="$TODAY"
|
|
|
|
if [ -n "$LATLONG" ]; then
|
|
# Need internet to get sunset time
|
|
if ! check_internet; then
|
|
echo "No internet connection. Retrying in 5 minutes..." >&2
|
|
sleep 300
|
|
continue
|
|
fi
|
|
|
|
fetch_sunset_time || {
|
|
echo "Error fetching sunset time. Retrying in 5 minutes..." >&2
|
|
sleep 300
|
|
continue
|
|
}
|
|
else
|
|
# User provided sunset time directly, convert to epoch
|
|
SUNSET_EPOCH=$(date -d "${TODAY} ${SUNSET_TIME}" +%s 2>/dev/null)
|
|
|
|
if [ -z "$SUNSET_EPOCH" ]; then
|
|
echo "Error: could not parse time '${SUNSET_TIME}'." >&2
|
|
sleep 60
|
|
continue
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Calculate alert window start (sunset minus specified minutes)
|
|
ALERT_WINDOW_START=$(( SUNSET_EPOCH - (MINUTES * 60) ))
|
|
|
|
# Calculate midnight of the current day
|
|
MIDNIGHT=$(date -d "${TODAY} +1 day" +%s)
|
|
|
|
# Alert while current time is within the window (from window start until midnight)
|
|
if [ "$CURRENT_TIME" -ge "$ALERT_WINDOW_START" ] && \
|
|
[ "$CURRENT_TIME" -lt "$MIDNIGHT" ]; then
|
|
show_alert
|
|
sleep 5 # Re-alert every 5 minutes while in alert window
|
|
else
|
|
sleep 60
|
|
fi
|
|
|
|
# Reset when we've passed midnight so we fetch new time tomorrow
|
|
if [ "$CURRENT_TIME" -ge "$MIDNIGHT" ]; then
|
|
LAST_DATE=""
|
|
fi
|
|
done
|