Files
SixFlagsSuperCalendar/README.md
josh 9700d0bd9a
All checks were successful
Build and Deploy / Build & Push (push) Successful in 2m54s
feat: RCDB-backed roller coaster filter with fuzzy name matching
- Add lib/park-meta.ts to manage data/park-meta.json (rcdb_id + coaster lists)
- Add lib/scrapers/rcdb.ts to scrape operating coaster names from RCDB park pages
- discover.ts now seeds park-meta.json with skeleton entries for all parks
- scrape.ts now refreshes RCDB coaster lists (30-day staleness) for parks with rcdb_id set
- fetchLiveRides() accepts a coasterNames Set; isCoaster uses normalize() on both sides
  to handle trademark symbols, 'THE ' prefixes, and punctuation differences between
  Queue-Times and RCDB names — applies correctly to both land rides and top-level rides
- Commit park-meta.json so it ships in the Docker image (fresh volumes get it automatically)
- Update .gitignore / .dockerignore to exclude only *.db files, not all of data/
- Dockerfile copies park-meta.json into image before VOLUME declaration
- README: document coaster filter setup and correct staleness window (72h not 7d)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 13:49:49 -04:00

124 lines
4.6 KiB
Markdown

# Thoosie Calendar
A week-by-week calendar showing operating hours for all Six Flags Entertainment Group theme parks — including the former Cedar Fair parks. Data is scraped from the Six Flags internal API and stored locally in SQLite. Click any park to see its full month calendar and live ride status with current wait times.
## Parks
24 theme parks across the US, Canada, and Mexico, grouped by region:
| Region | Parks |
|--------|-------|
| **Northeast** | Great Adventure (NJ), New England (MA), Great Escape (NY), Darien Lake (NY), Dorney Park (PA), Canada's Wonderland (ON) |
| **Southeast** | Over Georgia, Carowinds (NC), Kings Dominion (VA) |
| **Midwest** | Great America (IL), St. Louis (MO), Cedar Point (OH), Kings Island (OH), Valleyfair (MN), Worlds of Fun (MO), Michigan's Adventure (MI) |
| **Texas & South** | Over Texas, Fiesta Texas (TX), Frontier City (OK) |
| **West & International** | Magic Mountain (CA), Discovery Kingdom (CA), Knott's Berry Farm (CA), California's Great America (CA), Mexico |
## Tech Stack
- **Next.js 15** — App Router, Server Components, standalone output
- **Tailwind CSS v4** — `@theme {}` CSS variables, no config file
- **SQLite** via `better-sqlite3` — persisted in `/app/data/parks.db`
- **Playwright** — one-time headless browser run to discover each park's internal API ID
- **Six Flags CloudFront API** — `https://d18car1k0ff81h.cloudfront.net/operating-hours/park/{id}?date=YYYYMM`
- **Queue-Times.com API** — live ride open/closed status and wait times, updated every 5 minutes
## Ride Status
The park detail page shows ride open/closed status using a two-tier approach:
1. **Live data (Queue-Times.com)** — when a park is operating, ride status and wait times are fetched from the [Queue-Times.com API](https://queue-times.com/en-US/pages/api) and cached for 5 minutes. All 24 parks are mapped. Displays a **Live** badge with per-ride wait times.
2. **Schedule fallback (Six Flags API)** — the Six Flags operating-hours API drops the current day from its response once a park opens. When Queue-Times data is unavailable, the app falls back to the nearest upcoming date from the Six Flags schedule API as an approximation.
### Roller Coaster Filter
When live data is shown, a **Coasters only** toggle appears if roller coaster data has been populated for that park. Coaster lists are sourced from [RCDB](https://rcdb.com) and stored in `data/park-meta.json`. To populate them:
1. Open `data/park-meta.json` and set `rcdb_id` for each park to the numeric RCDB park ID (visible in the URL: `https://rcdb.com/4529.htm``4529`).
2. Run `npm run scrape` — coaster lists are fetched from RCDB and stored in the JSON file. They refresh automatically every 30 days on subsequent scrapes.
---
## Local Development
**Prerequisites:** Node.js 22+, npm
```bash
npm install
npx playwright install chromium
```
### Seed the database
Run once to discover each park's internal API ID (opens a headless browser per park):
```bash
npm run discover
```
Scrape operating hours for the full year:
```bash
npm run scrape
```
Force a full re-scrape (ignores the 7-day staleness window):
```bash
npm run scrape:force
```
### Debug a specific park + date
Inspect raw API data and parsed output for any park and date:
```bash
npm run debug -- --park kingsisland --date 2026-06-15
```
Output is printed to the terminal and saved to `debug/{parkId}_{date}.txt`.
### Run the dev server
```bash
npm run dev
```
Open [http://localhost:3000](http://localhost:3000). Navigate weeks with the `←` / `→` buttons, or pass `?week=YYYY-MM-DD` directly. Click any park name to open its detail page.
---
## Deployment
The app uses Next.js standalone output. The SQLite database is stored in a Docker volume at `/app/data`.
```bash
docker compose up -d
```
### Seed the database inside the container
The production image includes Playwright and Chromium, so discovery and scraping run directly against the container's volume:
```bash
docker compose exec web npm run discover
docker compose exec web npm run scrape
```
Or as a one-off against the named volume:
```bash
docker run --rm -v sixflagssupercalendar_park_data:/app/data \
gitea.thewrightserver.net/josh/sixflagssupercalendar:latest \
npm run scrape
```
---
## Data Refresh
The scraper skips any park + month already scraped within the last 72 hours. The nightly Docker scraper service handles this automatically. Parks or months not yet in the database show a `—` placeholder; parks with no open days in the displayed week are hidden from the calendar automatically.
Roller coaster lists (from RCDB) are refreshed every 30 days on each `npm run scrape` run, for parks with a configured `rcdb_id`.