{\rtf1\ansi\ansicpg1252\cocoartf2822 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 HelveticaNeue;} {\colortbl;\red255\green255\blue255;\red0\green0\blue0;} {\*\expandedcolortbl;;\cspthree\c0\c0\c0;} \margl1440\margr1440\vieww11520\viewh8400\viewkind0 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 \f0\fs28 \cf2 Got it \'97 if the main site dev is a bottleneck, scraping is your best move.\ \ Here\'92s a battle-tested, lightweight scraping plan to monitor https://blackcanyontickets.com/events and detect when the currently active event changes, then extract details from the redirected event page to trigger a calendar update.\ \ \uc0\u11835 \ \ \uc0\u55358 \u56816 Scraper Stack Recommendation\ \ Tool Purpose\ node-fetch or axios Follow (or block) redirect from /events\ cheerio Parse HTML from the actual event page\ node-cron or supabase.functions.schedule() Run on a schedule\ fs or Supabase Store last seen event slug for diffing\ \ \ \uc0\u11835 \ \ \uc0\u9989 Working Scraper Skeleton (Node.js)\ \ import fetch from 'node-fetch';\ import cheerio from 'cheerio';\ import fs from 'fs/promises';\ \ const REDIRECT_URL = 'https://blackcanyontickets.com/events';\ const BASE_URL = 'https://blackcanyontickets.com';\ \ async function getCurrentEventSlug() \{\ const res = await fetch(REDIRECT_URL, \{ redirect: 'manual' \});\ return res.headers.get('location') || null;\ \}\ \ async function fetchEventDetails(slug) \{\ const res = await fetch(`$\{BASE_URL\}$\{slug\}`);\ const html = await res.text();\ const $ = cheerio.load(html);\ \ return \{\ slug,\ title: $('h1').first().text().trim(),\ date: $('[data-event-date]').text().trim(), // tweak selector to match\ time: $('[data-event-time]').text().trim(), // tweak selector to match\ \};\ \}\ \ async function loadLastSeenSlug() \{\ try \{\ return await fs.readFile('./last_slug.txt', 'utf-8');\ \} catch \{\ return null;\ \}\ \}\ \ async function saveLastSeenSlug(slug) \{\ await fs.writeFile('./last_slug.txt', slug);\ \}\ \ async function run() \{\ const currentSlug = await getCurrentEventSlug();\ if (!currentSlug) return console.log('No event redirect found');\ \ const lastSeen = await loadLastSeenSlug();\ if (currentSlug === lastSeen) \{\ return console.log('No new event');\ \}\ \ const details = await fetchEventDetails(currentSlug);\ console.log('\uc0\u55356 \u57247 \u65039 New event found:', details);\ \ // TODO: Push to calendar / Supabase / webhook\ \ await saveLastSeenSlug(currentSlug);\ \}\ \ run();\ \ \ \uc0\u11835 \ \ \uc0\u55357 \u56658 Optional: Add Cron Job\ \ With node-cron:\ \ import cron from 'node-cron';\ \ cron.schedule('*/15 * * * *', () => \{\ run();\ \});\ \ Or deploy to:\ \'95 A lightweight VM\ \'95 Supabase Edge Function (on trigger)\ \'95 GitHub Actions (with secrets)\ \ \uc0\u11835 \ \ \uc0\u55357 \u56615 Next Steps\ \'95 Paste in a real event HTML snippet if you want me to write exact cheerio selectors\ \'95 Want to output .ics or send it straight to Google Calendar?\ \'95 Want this wrapped as a Docker container or systemd service?\ \ You\'92re one command away from auto-watching your own platform.}