feat: automated nightly scraper + housekeeping
All checks were successful
Build and Deploy / Build & Push (push) Successful in 3m11s

Scraper automation (docker-compose):
- Add scraper service to docker-compose.yml using the same image and
  shared park_data volume; overrides CMD to run scrape-schedule.sh
- scripts/scrape-schedule.sh: runs an initial scrape on container start,
  then sleeps until 3:00 AM (respects TZ env var) and repeats nightly;
  logs timestamps and next-run countdown; non-fatal on scrape errors

Staleness window: 7 days → 72 hours in lib/db.ts so data refreshes
more frequently with the automated schedule in place

Remove favicon: delete app/icon.tsx and public/logo.svg

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 12:47:14 -04:00
parent 20f1058e9e
commit da083c125c
5 changed files with 56 additions and 79 deletions

View File

@@ -1,59 +0,0 @@
import { ImageResponse } from "next/og";
export const size = { width: 32, height: 32 };
export const contentType = "image/png";
export default function Icon() {
return new ImageResponse(
(
<div
style={{
width: 32,
height: 32,
borderRadius: 8,
backgroundColor: "#0c1220",
display: "flex",
position: "relative",
}}
>
{/* Ground line */}
<div
style={{
position: "absolute",
left: 3,
right: 3,
bottom: 7,
height: 2,
backgroundColor: "#f59e0b",
borderRadius: 1,
}}
/>
{/* Lift hill — semicircle bump */}
<div
style={{
position: "absolute",
left: 3,
bottom: 9,
width: 10,
height: 13,
backgroundColor: "#f59e0b",
borderRadius: "50% 50% 0 0",
}}
/>
{/* Vertical loop — circle outline */}
<div
style={{
position: "absolute",
right: 5,
bottom: 7,
width: 12,
height: 12,
border: "2.5px solid #f59e0b",
borderRadius: "50%",
}}
/>
</div>
),
{ width: 32, height: 32 },
);
}

View File

@@ -9,5 +9,15 @@ services:
- NODE_ENV=production - NODE_ENV=production
restart: unless-stopped restart: unless-stopped
scraper:
image: gitea.thewrightserver.net/josh/sixflagssupercalendar:latest
volumes:
- park_data:/app/data
environment:
- NODE_ENV=production
- TZ=America/New_York # set your local timezone so "3am" is 3am your time
command: sh /app/scripts/scrape-schedule.sh
restart: unless-stopped
volumes: volumes:
park_data: park_data:

View File

@@ -167,7 +167,7 @@ export function getMonthCalendar(
return result; return result;
} }
const STALE_AFTER_MS = 7 * 24 * 60 * 60 * 1000; // 1 week const STALE_AFTER_MS = 72 * 60 * 60 * 1000; // 72 hours
/** /**
* Returns true when the scraper should skip this park+month. * Returns true when the scraper should skip this park+month.

View File

@@ -1,19 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 56" fill="none">
<!-- Lift hill + ground + camelback -->
<path
d="M 2 52 L 20 6 L 38 52 L 116 52 Q 134 22 152 52 L 196 52"
stroke="#f59e0b"
stroke-width="3.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<!-- Vertical loop -->
<circle
cx="75"
cy="33"
r="19"
stroke="#f59e0b"
stroke-width="3.5"
fill="none"
/>
</svg>

Before

Width:  |  Height:  |  Size: 434 B

View File

@@ -0,0 +1,45 @@
#!/bin/sh
# Nightly scraper scheduler — runs inside the Docker scraper service.
#
# Behaviour:
# 1. Runs an initial scrape immediately on container start.
# 2. Sleeps until 3:00 AM (container timezone, set via TZ env var).
# 3. Runs the scraper, then sleeps until the next 3:00 AM, forever.
#
# Timezone: set TZ in the scraper service environment to control when
# "3am" is (e.g. TZ=America/New_York). Defaults to UTC if unset.
log() {
echo "[scheduler] $(date '+%Y-%m-%d %H:%M %Z')$*"
}
run_scrape() {
log "Starting scrape"
if npm run scrape; then
log "Scrape completed"
else
log "Scrape failed — will retry at next scheduled time"
fi
}
seconds_until_3am() {
now=$(date +%s)
# Try today's 3am first; if already past, use tomorrow's.
target=$(date -d "today 03:00" +%s)
if [ "$now" -ge "$target" ]; then
target=$(date -d "tomorrow 03:00" +%s)
fi
echo $((target - now))
}
# ── Run immediately on startup ────────────────────────────────────────────────
run_scrape
# ── Nightly loop ──────────────────────────────────────────────────────────────
while true; do
wait=$(seconds_until_3am)
next=$(date -d "now + ${wait} seconds" '+%Y-%m-%d %H:%M %Z')
log "Next scrape in $((wait / 3600))h $((( wait % 3600) / 60))m (${next})"
sleep "$wait"
run_scrape
done