kyros:每 6 小时刷新的旧金山湾区活动 iCalendar 订阅源
SiddanthEmani/kyros
kyros 是一个每 6 小时刷新的 iCalendar 活动订阅源,聚合 Luma、Ticketmaster 和 Funcheap 三个来源,覆盖湾区 50 英里内的 EDM、演唱会、免费活动和 AI 讲座,输出 events.ics 及 edm/music/free/ai 四个分类 feed,一个 URL 即可在任意日历应用中订阅。
An iCalendar feed of the best events in the SF Bay Area — EDM, concerts, free things to do, and AI talks — refreshed every 6 hours. San Jose first, the rest of the Bay right behind it. One URL — subscribe from any calendar app.
Subscribe
Add to Google Calendar — one tap on Android or desktop. Google Calendar (app or web) opens straight to the "Subscribe" prompt, already filled in.
Or add a raw feed URL manually. Everything lives under
https://raw.githubusercontent.com/SiddanthEmani/kyros/main/:
| feed | what's in it |
|---|---|
events.ics |
everything, tagged [EDM] / [Live] / [AI] / [Free] / [Bay] |
feeds/edm.ics |
electronic — club nights and DJ shows |
feeds/music.ics |
all live music: concerts + EDM |
feeds/free.ics |
free events only |
feeds/ai.ics |
AI talks, demos, hackathons (the original kyros feed) |
- Apple Calendar
File → New Calendar Subscription→ paste URL - Google Calendar / Android use the one-tap link above, or on
desktop:
Other calendars → + → From URL→ paste URL - Outlook / Fantastical / anything else Add subscription by URL
kyros (κῦρος): authority, weight, signal over noise.
How it works
Luma ┐
TM ├─► classify ─► geo filter ─► dedup ─► rank ─► cap ─► 5 feeds
Fun. ┘ 5 buckets 50mi of SJ merge SJ first per cat every 6h
- Fetch — three sources, each isolated so a dead site can't take down a
refresh:
- Luma — AI talks, demos and hackathons. Scrapes the server-rendered discover HTML and paginates the JSON discover API, falling back through CORS relays when the runner IP is blocked.
- Ticketmaster — concerts and ticketed shows within 50 miles of downtown San Jose (SAP Center, Shoreline, The Ritz, Fox Oakland, Chase Center). Needs a free API key; skips itself without one.
- Funcheap — free and cheap events, region by region, South Bay first.
- Classify — each event lands in one or more of
ai,edm,concert,free,community. Anything that matches nothing is dropped, which is what keeps "Networking Drinks" out of the feed. - Geo — resolved to a Bay city and region by coordinates when a source gives them, else by city and venue names. Outside 50 miles of San Jose is dropped.
- Dedup — the same show arrives from more than one source. Matches merge, so one event keeps Ticketmaster's price and another source's genre tags.
- Rank & cap — per-category scoring plus a San Jose / South Bay boost, so SJ wins the caps while a strong SF show still makes it. Caps are per category, then a combined cap over the union.
- Write — the combined
events.icsplus the four category feeds.
If a refresh collapses (blocked IP, changed markup), the run fails loudly and keeps the existing feeds rather than publishing an empty calendar.
The Ticketmaster key (optional)
Concert coverage is much better with one. Grab a free key at
developer.ticketmaster.com (5,000
calls/day; a refresh uses ~10) and add it as a repository secret named
TICKETMASTER_API_KEY. Without it, that source logs no key, skipping and
everything else still builds.
Running it locally
pip install -r requirements-dev.txt python run.py # build the feeds python run.py --explain # ...and log the ranked keep-list per category python run.py --dry-run --explain # fetch and rank, write nothing python run.py --offline --explain # run the whole pipeline off committed fixtures python -m pytest -q # offline parser + pipeline tests
Two flags exist for CI: --report PATH appends a markdown run report
(per-source counts, drop breakdown, top picks) — the PR check points it at
$GITHUB_STEP_SUMMARY — and --require-events N exits non-zero when fewer
than N events survive, which is how a silently-dead parser gets caught.
--ics-path puts the combined feed anywhere; the category feeds follow it
into the same directory, so a scratch run stays out of the repo:
python run.py --offline --ics-path /tmp/kyros/events.ics
Configuration (config.json)
| key | default | meaning |
|---|---|---|
lookahead_days |
30 |
drop events past this horizon |
local_tz |
"America/Los_Angeles" |
IANA tz for every schedule check |
center |
SJ, radius_miles: 50 |
what counts as "around the area" |
region_boost |
south-bay 3.0, peninsula 1.5, sf/east-bay 0.5 |
the San Jose priority dial; San Jose proper gets +1.0 on top |
free_bonus |
1.0 |
score bonus for free events |
sources |
all true |
turn an individual source off |
cities / luma_categories |
SJ, SF, Oakland, Palo Alto / ["ai"] |
Luma discover scope |
ticketmaster_classifications |
["music"] |
Discovery classifications to query |
categories.<name>.cap |
8–15 | top-N per category |
categories.<name>.min_weekday_hour_local |
16–17 |
weekday events must start at/after this hour; weekends always pass |
combined_cap |
60 |
cap on the combined feed |
prefix_titles |
true |
[EDM]-style tags in the combined feed |
min_events_floor |
5 |
below this, keep the old feeds and fail the run |
Old flat configs still work: min_weekday_hour_local and
max_events_per_run are read and mapped onto the new shape.
Files
run.py # CLI entry point
kyros/
config.py http.py model.py # config, fetching, the Event record
geo.py # Bay city registry, radius, SJ boost
classify.py rank.py # categories and per-category scoring
dedup.py ics.py # cross-source merge, feed writing
pipeline.py report.py # fetch -> filter -> rank -> write, run report
sources/ # luma, ticketmaster, funcheap
tests/ # offline, fixture-driven
scripts/fetch_fixtures.py # refresh fixtures when a site changes
config.json # user-editable
.github/workflows/
refresh.yml # 6-hourly schedule, commits the feeds
pr-check.yml # every PR commit: tests + a live dry run
events.ics feeds/*.ics # output (committed by CI)
Why this exists
It started as one calendar I could open on Sunday night and see every meaningful AI talk in the Bay for the coming weeks. The same filtering turns out to be exactly what the rest of a week needs — which warehouse party is worth the drive, which show at The Ritz is on sale, what's free downtown this weekend — without scrolling five sites that each cover a third of it.
License
MIT — fork it, run it for your city, ship your own feed.
来源:GitHub · github.com