refactor: hardcode API IDs and coaster lists, remove Playwright discovery
Embed Six Flags API IDs directly in the park registry and snapshot coaster lists from park-meta.json into a TypeScript module. This eliminates the Playwright-based discovery script, RCDB scraper, and runtime dependency on park-meta.json — preparing for the backend API transition. - Add apiId field to Park type and all 24 park entries - Create lib/coaster-data.ts with hardcoded coaster lists - Update page components to use park.apiId and new getCoasterSet() - Remove scripts/discover.ts, lib/scrapers/rcdb.ts, lib/park-meta.ts - Remove data/park-meta.json from shared volume - Remove playwright devDependency and discover npm script - Simplify scripts/scrape.ts (no RCDB, no discovery checks) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+6
-10
@@ -1,11 +1,11 @@
|
||||
import { HomePageClient } from "@/components/HomePageClient";
|
||||
import { PARKS } from "@/lib/parks";
|
||||
import { openDb, getDateRange, getApiId } from "@/lib/db";
|
||||
import { openDb, getDateRange } from "@/lib/db";
|
||||
import { getTodayLocal, isWithinOperatingWindow, getOperatingStatus } from "@/lib/env";
|
||||
import { fetchLiveRides } from "@/lib/scrapers/queuetimes";
|
||||
import { fetchToday } from "@/lib/scrapers/sixflags";
|
||||
import { QUEUE_TIMES_IDS } from "@/lib/queue-times-map";
|
||||
import { readParkMeta, getCoasterSet } from "@/lib/park-meta";
|
||||
import { getCoasterSet, hasCoasterData } from "@/lib/coaster-data";
|
||||
import type { DayData } from "@/lib/db";
|
||||
|
||||
interface PageProps {
|
||||
@@ -58,9 +58,7 @@ export default async function HomePage({ searchParams }: PageProps) {
|
||||
if (weekDates.includes(today)) {
|
||||
const todayResults = await Promise.all(
|
||||
PARKS.map(async (p) => {
|
||||
const apiId = getApiId(db, p.id);
|
||||
if (!apiId) return null;
|
||||
const live = await fetchToday(apiId, 300); // 5-min ISR cache
|
||||
const live = await fetchToday(p.apiId, 300); // 5-min ISR cache
|
||||
return live ? { parkId: p.id, live } : null;
|
||||
})
|
||||
);
|
||||
@@ -83,9 +81,7 @@ export default async function HomePage({ searchParams }: PageProps) {
|
||||
0
|
||||
);
|
||||
|
||||
// Always fetch both ride and coaster counts — the client decides which to display.
|
||||
const parkMeta = readParkMeta();
|
||||
const hasCoasterData = PARKS.some((p) => (parkMeta[p.id]?.coasters.length ?? 0) > 0);
|
||||
const coasterDataAvailable = hasCoasterData();
|
||||
|
||||
let rideCounts: Record<string, number> = {};
|
||||
let coasterCounts: Record<string, number> = {};
|
||||
@@ -112,7 +108,7 @@ export default async function HomePage({ searchParams }: PageProps) {
|
||||
const trackedParks = openTodayParks.filter((p) => QUEUE_TIMES_IDS[p.id]);
|
||||
const results = await Promise.all(
|
||||
trackedParks.map(async (p) => {
|
||||
const coasterSet = getCoasterSet(p.id, parkMeta);
|
||||
const coasterSet = getCoasterSet(p.id);
|
||||
const result = await fetchLiveRides(QUEUE_TIMES_IDS[p.id], coasterSet, 300);
|
||||
const rideCount = result ? result.rides.filter((r) => r.isOpen).length : null;
|
||||
const coasterCount = result ? result.rides.filter((r) => r.isOpen && r.isCoaster).length : 0;
|
||||
@@ -143,7 +139,7 @@ export default async function HomePage({ searchParams }: PageProps) {
|
||||
openParkIds={openParkIds}
|
||||
closingParkIds={closingParkIds}
|
||||
weatherDelayParkIds={weatherDelayParkIds}
|
||||
hasCoasterData={hasCoasterData}
|
||||
hasCoasterData={coasterDataAvailable}
|
||||
scrapedCount={scrapedCount}
|
||||
/>
|
||||
);
|
||||
|
||||
+6
-27
@@ -2,12 +2,12 @@ import Link from "next/link";
|
||||
import { BackToCalendarLink } from "@/components/BackToCalendarLink";
|
||||
import { notFound } from "next/navigation";
|
||||
import { PARK_MAP } from "@/lib/parks";
|
||||
import { openDb, getParkMonthData, getApiId } from "@/lib/db";
|
||||
import { openDb, getParkMonthData } from "@/lib/db";
|
||||
import { scrapeRidesForDay } from "@/lib/scrapers/sixflags";
|
||||
import { fetchLiveRides } from "@/lib/scrapers/queuetimes";
|
||||
import { fetchToday } from "@/lib/scrapers/sixflags";
|
||||
import { QUEUE_TIMES_IDS } from "@/lib/queue-times-map";
|
||||
import { readParkMeta, getCoasterSet } from "@/lib/park-meta";
|
||||
import { getCoasterSet } from "@/lib/coaster-data";
|
||||
import { ParkMonthCalendar } from "@/components/ParkMonthCalendar";
|
||||
import { LiveRidePanel } from "@/components/LiveRidePanel";
|
||||
import type { RideStatus, RidesFetchResult } from "@/lib/scrapers/sixflags";
|
||||
@@ -42,13 +42,9 @@ export default async function ParkPage({ params, searchParams }: PageProps) {
|
||||
|
||||
const db = openDb();
|
||||
const monthData = getParkMonthData(db, id, year, month);
|
||||
const apiId = getApiId(db, id);
|
||||
db.close();
|
||||
|
||||
// Prefer live today data from the Six Flags API (5-min ISR cache) so that
|
||||
// weather delays and hour changes surface immediately rather than showing
|
||||
// stale DB values. Fall back to DB if the API call fails.
|
||||
const liveToday = apiId !== null ? await fetchToday(apiId, 300).catch(() => null) : null;
|
||||
const liveToday = await fetchToday(park.apiId, 300).catch(() => null);
|
||||
const todayData = liveToday
|
||||
? { isOpen: liveToday.isOpen, hoursLabel: liveToday.hoursLabel ?? null, specialType: liveToday.specialType ?? null }
|
||||
: monthData[today];
|
||||
@@ -56,8 +52,7 @@ export default async function ParkPage({ params, searchParams }: PageProps) {
|
||||
|
||||
// ── Ride data: try live Queue-Times first, fall back to schedule ──────────
|
||||
const queueTimesId = QUEUE_TIMES_IDS[id];
|
||||
const parkMeta = readParkMeta();
|
||||
const coasterSet = getCoasterSet(id, parkMeta);
|
||||
const coasterSet = getCoasterSet(id);
|
||||
|
||||
let liveRides: LiveRidesResult | null = null;
|
||||
let ridesResult: RidesFetchResult | null = null;
|
||||
@@ -87,9 +82,8 @@ export default async function ParkPage({ params, searchParams }: PageProps) {
|
||||
liveRides.rides.length > 0 &&
|
||||
liveRides.rides.every((r) => !r.isOpen);
|
||||
|
||||
// Only hit the schedule API as a fallback when Queue-Times live data is unavailable.
|
||||
if (!liveRides && apiId !== null) {
|
||||
ridesResult = await scrapeRidesForDay(apiId, today);
|
||||
if (!liveRides) {
|
||||
ridesResult = await scrapeRidesForDay(park.apiId, today);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -175,7 +169,6 @@ export default async function ParkPage({ params, searchParams }: PageProps) {
|
||||
<RideList
|
||||
ridesResult={ridesResult}
|
||||
parkOpenToday={!!parkOpenToday}
|
||||
apiIdMissing={apiId === null && !queueTimesId}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
@@ -256,24 +249,10 @@ function LiveBadge() {
|
||||
function RideList({
|
||||
ridesResult,
|
||||
parkOpenToday,
|
||||
apiIdMissing,
|
||||
}: {
|
||||
ridesResult: RidesFetchResult | null;
|
||||
parkOpenToday: boolean;
|
||||
apiIdMissing: boolean;
|
||||
}) {
|
||||
if (apiIdMissing) {
|
||||
return (
|
||||
<Callout>
|
||||
Park API ID not discovered yet. Run{" "}
|
||||
<code style={{ background: "var(--color-surface-2)", padding: "1px 5px", borderRadius: 3, fontSize: "0.8em" }}>
|
||||
npm run discover
|
||||
</code>{" "}
|
||||
to enable ride data.
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
||||
if (!parkOpenToday) {
|
||||
return <Callout>Park is closed today — no ride schedule available.</Callout>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user