`epgArchiveDays` used `tvg.rec ?? timeshift ?? catchup.days`, but `??` does not
skip an empty string — the common `tvg-rec=""` default stopped the chain and
yielded 0, which the timeline treats as an unbounded catch-up window, so a
channel with a real `timeshift`/`catchup-days` could offer "Watch" on
programmes older than its actual archive. Use the shared `getM3uArchiveDays`
(non-blank + correct precedence), matching the unified live tab. (Codex P2)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Auto-focus no longer forces the view back to today on every ribbon
(re)mount: it skips without clearing `lastFocusKey`, and only commits today
when today actually has a programme. Fixes being trapped on the empty-day
state when navigating to a day that has data (Codex P2).
- Pass `archiveDays` to the timeline from the unified live tab (via the shared
`getM3uArchiveDays`), so M3U catch-up "Watch" is gated to the channel's real
window instead of the unlimited `0` default (Codex P2).
- Never fold the on-air programme into a "N short" group chip, so its
`when: 'now'` highlight (and the auto-focus target) survive when zoomed out
(Greptile P2).
- Chunk the channel candidate lookup (500 keys/query) so the bound-parameter
count stays under SQLite's limit on large playlists — the case-insensitive
raw+lower match binds each key up to 4× (Greptile P2).
Tests: ui-epg 78, electron-backend 433, portal-shared-ui 47; lint + web build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the vertical EPG list/panel with a single horizontal timeline ribbon
(`app-epg-timeline`) shared across all live surfaces — the M3U player, the
unified live tab, and the Xtream and Stalker layouts. It preloads a multi-day
window and supports scroll, zoom, day navigation, short-programme tiers and
per-state empty/error views; the programme-details dialog is restyled to match
and now shows the channel logo.
Timeline / UI
- Auto-focus the currently-airing programme on channel select — instant
(`behavior: 'auto'`), centred, and deduped by programme-set identity so the
30s tick / zoom / re-emits never cause flaky re-jumps.
- Wide-tier cards show a dimmed description preview under the title; title and
preview clip on whole lines (`flex-shrink: 0` + `-webkit-line-clamp`), never
mid-line.
- Dynamic bar subtitle: the now-playing / archive programme title instead of a
static "Timeline" label.
- State-aware toolbar: hide Now + zoom when there is no ribbon, and the date
stepper when the channel has no EPG on any day (hidden, not disabled).
- Empty-state fills and centres within the panel area instead of a fixed
min-height that overflowed the compact inline panel and hid the buttons.
EPG current-programme lookup (electron-backend)
- Timezone-aware "airing now" comparison via SQLite `datetime()` (was a lexical
string compare that broke for offset vs UTC `Z` timestamps).
- Unscoped fallback for resolved candidates whose programmes are tagged with an
out-of-scope source (multi-source imports sharing XMLTV ids), so the sidebar
matches the timeline.
- Match channel candidates by the raw (case-sensitive) key as well as `LOWER()`,
since SQLite `LOWER()`/`COLLATE NOCASE` fold only ASCII — fixes Cyrillic /
Greek channel names showing "No program information available".
- Overlap-based day membership (`hasProgramsForDateKey`) so a film spanning
midnight keeps the ribbon on "today" while it airs.
Refactor
- Extract the duplicated channel-list EPG enrichment (progress + side-car map)
into `channel-list-container/epg-enrichment.util.ts`, shared by the
all-channels / groups / favorites / recent views; also fixes recent's and
favorites' unguarded, NaN-prone progress maths.
Tests: ui-epg 75, components 77, electron-backend 432; lint + web build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(m3u): highlight active archive epg program
* Store the active archive EPG program with the resolved playback URL so the clicked M3U catch-up row stays highlighted during archive playback.
* Show archive playback state and return-to-live controls in the inline player panel.
* Hide duplicate EPG program rows that share the same time slot while keeping the richer provider entry.
Register an "Switch player to Embedded MPV" command in the Cmd+K command
palette so the embedded MPV player can be activated like the other players.
Visibility is gated on an async getEmbeddedMpvSupport() check, mirroring the
Settings dropdown so the command only appears when embedded MPV is usable.
Generalizes the per-command visibility flag from desktopOnly to a `requires`
discriminator ('none' | 'managed-external' | 'embedded-mpv').
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix Stalker route initialization so full portal sessions load auth-capable playlist data before category/content requests. Add regression coverage for full playlist lookup, empty lookup fallback, fast-path explicit portal metadata, and authenticated request routing.
Adds IMDb rating sort and minimum-rating filtering for Xtream VOD/series catalogs, consolidates refinement controls, and guards rating controls away from Live TV.
- save Xtream playlist details through browser-safe metadata persistence in PWA\n- keep PWA Xtream data source cache in sync with current playlist metadata\n- cover dialog close timing, stale cache, and PWA data-source bootstrap regression