🐛 Bug Fixes
- Fixture gate no longer vetoes college football — NCAA soccer's mascotless team names were shadowing every other college sport, rejecting 27% of a Saturday CFB slate (#650) — thanks @lpukatch
[1080p]/720p/(4K)tags no longer poison team names — one tagged source went from 0/30 to 21/21 matched (#651)- Pipe metadata (
| 8.29 | ESPN) and apostrophes (Hawai'i) no longer break matching (#652, #653) — thanks @lpukatch {today_tonight}says "tomorrow" / the weekday for games not today instead of "today" on early-created channels (#550)- Stream Priority "Dispatcharr Group" dropdown no longer drops groups (#633) — thanks @lpukatch
- Channel-source group picker now lists Dispatcharr channel groups (#631) — thanks @lpukatch
- Bullpen proxy disables itself after repeated 401s instead of failing every fetch (#548)
✨ New Features
- Pinned Blocks — channel numbering exceptions: pin number ranges by team, league, or sport with lane-based allocation; manual mode retired from the Numbering page (#333)
- Tennis EPG programme matching — binds a linear channel's programme to a tournament + court or player pair from any EPG field (#642)
- Tennis fixture gate — tournament veto and singles/doubles draw-shape validation (#283)
- Optional Bullpen proxy support for the provider layer (#548) — thanks @sethwv (#635)
- Support bundle matching signals —
source_matching_zeroandsource_matching_degradedflag dead or struggling sources on the first line a triager reads (#657) — thanks @lpukatch - Media-server refresh health — refresh outcomes persisted per run, dashboard warning after consecutive failures, bundle signal (#649)
SCHEDULER=offandDRY_RUN=trueenv flags so a dev instance can run beside prod (#554)
⚡ Enhancements
- Channel-source fetch pulls curated channels' streams by id instead of walking the whole Dispatcharr catalog — 7.6s → 0.08s per run on a 118k-stream install (#647)
- Failed matches now persist the near-miss diagnosis (closest candidate, both scores vs threshold) and the exclusion reason (#661) — thanks @lpukatch
- Failure taxonomy: filter and skip outcomes are labelled
filtered:/skipped:instead of "unmatched"; newcandidates_gatedreason for candidates never scored (#662) - One generation = one run row; per-source breakdown moves onto the run, retiring 23k sub-run rows on a typical install (#645)