🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
3.2 KiB
{\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.}