104 lines
4.5 KiB
Bash
Executable File
104 lines
4.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Route 5 departure watcher — runs in background, posts to Discord when bus departs
|
|
# Usage: bash watch-departure.sh <scheduled_time_UTC> [channel_id]
|
|
# Example: bash watch-departure.sh "2026-02-12T13:30:00Z" 1467247377743347953
|
|
set -eo pipefail
|
|
|
|
SCHED_DEPART="$1"
|
|
CHANNEL="${2:-1467247377743347953}" # Default: DM channel
|
|
VP_URL="https://data.texas.gov/download/cuc7-ywmd/application%2Fjson"
|
|
FIRST_STOP="5854"
|
|
USER_STOP="964"
|
|
TOKEN=$(printenv DISCORD_BOT_TOKEN)
|
|
MAX_POLLS=40 # ~13 minutes max watch time
|
|
POLL_INTERVAL=20 # seconds between polls
|
|
|
|
# Find the trip matching this scheduled departure
|
|
find_trip() {
|
|
local TU=$(curl -sL --max-time 10 "https://data.texas.gov/download/mqtr-wwpy/application%2Fjson" 2>/dev/null)
|
|
echo "$TU" | jq -r --arg sched "$SCHED_DEPART" '.entity[] |
|
|
select(.tripUpdate.trip.routeId == "5" and .tripUpdate.trip.directionId == 0) |
|
|
select([.tripUpdate.stopTimeUpdate[] | select(.stopId == "5854") |
|
|
((.departure.time // .arrival.time) | tonumber)] | .[0] == ($sched | sub("Z$";"") | strptime("%Y-%m-%dT%H:%M:%S") | mktime)) |
|
|
.tripUpdate.trip.tripId' 2>/dev/null | head -1
|
|
}
|
|
|
|
# Convert ISO to epoch
|
|
sched_epoch() {
|
|
date -d "$SCHED_DEPART" +%s 2>/dev/null || date -u -d "${SCHED_DEPART%Z}" +%s 2>/dev/null
|
|
}
|
|
|
|
SCHED_TS=$(sched_epoch)
|
|
SCHED_CST=$(TZ=America/Chicago date -d "@$SCHED_TS" +"%I:%M %p" 2>/dev/null)
|
|
|
|
# Find the trip ID
|
|
TRIP_ID=$(find_trip)
|
|
if [ -z "$TRIP_ID" ]; then
|
|
# Fallback: find closest eastbound trip
|
|
TU=$(curl -sL --max-time 10 "https://data.texas.gov/download/mqtr-wwpy/application%2Fjson" 2>/dev/null)
|
|
TRIP_ID=$(echo "$TU" | jq -r --arg ts "$SCHED_TS" '[.entity[] |
|
|
select(.tripUpdate.trip.routeId == "5" and .tripUpdate.trip.directionId == 0) |
|
|
{tripId: .tripUpdate.trip.tripId, depart: ([.tripUpdate.stopTimeUpdate[] | select(.stopId == "5854") | (.departure.time // .arrival.time)] | .[0] | tonumber)}] |
|
|
sort_by((. .depart - ($ts | tonumber)) | fabs) | .[0].tripId' 2>/dev/null)
|
|
fi
|
|
|
|
if [ -z "$TRIP_ID" ]; then
|
|
# Post error
|
|
curl -s -X POST -H "Authorization: Bot $TOKEN" -H "Content-Type: application/json" \
|
|
-d "{\"content\":\"⚠️ Could not find Route 5 trip for $SCHED_CST departure.\"}" \
|
|
"https://discord.com/api/v10/channels/$CHANNEL/messages" > /dev/null
|
|
exit 1
|
|
fi
|
|
|
|
# Poll until departure
|
|
for i in $(seq 1 $MAX_POLLS); do
|
|
VP=$(curl -sL --max-time 8 "https://data.texas.gov/download/cuc7-ywmd/application%2Fjson" 2>/dev/null)
|
|
|
|
VEHICLE=$(echo "$VP" | jq -c ".entity[] | select(.vehicle.trip.tripId == \"$TRIP_ID\")" 2>/dev/null)
|
|
|
|
if [ -z "$VEHICLE" ]; then
|
|
sleep $POLL_INTERVAL
|
|
continue
|
|
fi
|
|
|
|
STOP_ID=$(echo "$VEHICLE" | jq -r '.vehicle.stopId')
|
|
STATUS=$(echo "$VEHICLE" | jq -r '.vehicle.currentStatus')
|
|
SPEED=$(echo "$VEHICLE" | jq -r '.vehicle.position.speed')
|
|
VEH_ID=$(echo "$VEHICLE" | jq -r '.vehicle.vehicle.label')
|
|
|
|
# Bus has left the first stop
|
|
if [ "$STOP_ID" != "$FIRST_STOP" ] || ([ "$STATUS" = "IN_TRANSIT_TO" ] && [ "$STOP_ID" != "$FIRST_STOP" ]); then
|
|
DEPART_TS=$(date +%s)
|
|
DEPART_CST=$(TZ=America/Chicago date +"%I:%M:%S %p")
|
|
DELAY=$((DEPART_TS - SCHED_TS))
|
|
DELAY_MIN=$((DELAY / 60))
|
|
|
|
# Calculate ETA at user stop (7m26s from first stop)
|
|
ETA_TS=$((DEPART_TS + 446))
|
|
ETA_CST=$(TZ=America/Chicago date -d "@$ETA_TS" +"%I:%M %p" 2>/dev/null)
|
|
|
|
if [ "$DELAY_MIN" -le 0 ]; then
|
|
STATUS_MSG="🟢 On time"
|
|
elif [ "$DELAY_MIN" -le 2 ]; then
|
|
STATUS_MSG="🟡 ~${DELAY_MIN}min late"
|
|
else
|
|
STATUS_MSG="🔴 ${DELAY_MIN}min late"
|
|
fi
|
|
|
|
MSG="🚌 **Route 5 Departed!**\nBus ${VEH_ID} left Anderson/Northcross at ${DEPART_CST}\nScheduled: ${SCHED_CST} | ${STATUS_MSG}\n📍 ETA at Woodrow/Choquette: **${ETA_CST}**"
|
|
|
|
CONTENT=$(printf "$MSG")
|
|
curl -s -X POST -H "Authorization: Bot $TOKEN" -H "Content-Type: application/json" \
|
|
-d "$(jq -n --arg c "$CONTENT" '{content: $c}')" \
|
|
"https://discord.com/api/v10/channels/$CHANNEL/messages" > /dev/null
|
|
exit 0
|
|
fi
|
|
|
|
sleep $POLL_INTERVAL
|
|
done
|
|
|
|
# Timeout — bus never departed (or we missed it)
|
|
curl -s -X POST -H "Authorization: Bot $TOKEN" -H "Content-Type: application/json" \
|
|
-d "{\"content\":\"⚠️ Route 5 watcher timed out — could not confirm $SCHED_CST departure from Anderson/Northcross.\"}" \
|
|
"https://discord.com/api/v10/channels/$CHANNEL/messages" > /dev/null
|