Wire up Ticketmaster, SeatGeek, Telegram, scoring, Playwright stubs. Deduplicate events with fuzzy venue/name matching. Retry calendar updates on transient failures. Backlog tasks marked complete. Made-with: Cursor
4.3 KiB
Architecture
High-level flow
┌──────────────┐ ┌──────────────┐
│ Ticketmaster │ │ SeatGeek │
│ Provider │ │ Provider │
└──────┬───────┘ └──────┬───────┘
│ │
└────────┬───────────┘
▼
┌───────────────┐
│ Normalize & │
│ Deduplicate │
└───────┬───────┘
▼
┌───────────────┐
│ Impact Score │
└───────┬───────┘
▼
┌───────────────┐
│ Filter by │
│ date window │
└───────┬───────┘
│
┌───────┴───────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Telegram │ │ Airbnb │
│ Alert │ │ Calendar │
│ (primary) │ │ (optional) │
└──────────────┘ └──────────────┘
Module map
src/
├── main.py # CLI entrypoint, orchestration
├── config.py # Pydantic settings from env vars
├── models.py # NormalizedEvent dataclass
├── log.py # Structured logging configuration
├── dedup.py # Deduplication across providers
├── providers/
│ ├── base.py # EventProvider abstract base class
│ ├── ticketmaster.py # Ticketmaster Discovery API
│ └── seatgeek.py # SeatGeek API
├── scoring/
│ └── impact.py # Rule-based impact scoring
├── notifications/
│ └── telegram.py # Telegram bot message sender
└── airbnb/
├── auth.py # Playwright storage state management
└── calendar.py # Calendar navigation and price updates
Key design decisions
1. Provider abstraction
All event providers implement EventProvider.fetch() -> list[NormalizedEvent]. This makes it trivial to add new sources (Eventbrite, PredictHQ, scraping) without touching the orchestration layer.
2. Normalized event model
A single NormalizedEvent dataclass acts as the shared contract between providers, deduplication, scoring, and output formatting. Fields: name, date, venue, source, url, raw metadata.
3. Airbnb automation is isolated and optional
The src/airbnb/ module is completely decoupled from event ingestion. If Playwright breaks (selectors change, login expires), the system degrades gracefully to Telegram-only alerts. The main runner catches all Airbnb errors and logs them without crashing.
4. Storage state for auth
Airbnb authentication uses Playwright's storage_state API. A one-time manual login script saves cookies/localStorage to state.json. Subsequent headless runs load this state. No passwords are stored in code or env vars.
5. Configuration via environment
All secrets and tunables live in env vars (loaded from .env in local dev). No config files to manage, easy to override in Docker/cron.
6. No database
For weekly runs processing dozens of events, in-memory processing is sufficient. If persistence becomes necessary (e.g., tracking price change history), a simple JSON file or SQLite would be the first step.
Error handling strategy
- Each provider's
fetch()is wrapped in try/except; one failing source does not block others. - Telegram send failures are logged but do not block Airbnb updates.
- Airbnb automation failures are logged and reported via Telegram if possible.
- The main runner returns a nonzero exit code if all providers fail.
Future extension points
- New providers: subclass
EventProvider - New notification channels: add modules under
notifications/ - Smarter scoring: replace
scoring/impact.pyinternals - Multi-listing: extend config and loop in
main.py