✨ New Features
- Motorsports support — F1, NASCAR, and IndyCar via ESPN, plus IMSA and WEC via TheSportsDB, with dedicated racing variables and racing-aware matching (#242) — thanks @tomwinterrose
- Per-source matching types — each Source independently toggles Stream Name, Team, and EPG matching, with color-coded Sources badges
- Stream stats caching & stat-based ordering — cache stream statistics, order channels by metric, and expand a channel's streams inline (#244) — thanks @sethwv
- League-aware template sample data with live preview — per-shape sample identities (team / combat / racing) and a live-first preview that surfaces real data gaps instead of masking them (#252, #253) — thanks @sethwv
- Template validation — frontend/backend validation parity with a new
/templates/validateendpoint; flags unknown variables and conditions before they ship - Richer EPG description variables — recaps, headlines, leaders, and storylines pulled from ESPN summaries
- Provider-call telemetry — per-run provider API-call counts surfaced in Generation History
⚡ Enhancements
- ESPN event-status refreshes are coalesced within a generation run for fewer API calls (#254) — thanks @lpukatch
- Custom leagues auto-subscribe on creation, with a "Not subscribed" warning guard (#240)
🐛 Bug Fixes
- Channels for unsubscribed leagues are now cleaned up on the next run (no more wiping all channels)
- Disabled-group cleanup is stream-level, so shared/consolidated channels survive when one contributing source is disabled
- Discovered soccer leagues no longer cache as sport "unknown"
- CDVR M3U→guide refresh is properly sequenced so the guide re-indexes
- Fixed the WBC logo and broken preview league logos
🎨 UI/UX
- Matching-type toggles and Sources badges, with clearer matching copy
- In-app guidance for soccer Teams mode and the Default Team Filter
- Stream-match popovers explaining how and why a stream matched (aliases, patterns, cache age, priority)
🔧 Under the Hood
- Replaced deprecated
datetime.utcnow()with a timezone-aware helper - Layer-separation cleanup and dead-code pruning
- User-guide docs resynced to the v2.7.0 IA overhaul