feat(playback): draw catch-up programmes as seek-bar segments (#1750)

This commit is contained in:
4gray authored and GitHub committed 2026-09-29 19:34:38 +02:00
1 parent 4e17fbed4e
commit f38c6f86d1
35 files changed
+1206 -15

No files matched your search

+33 -7
View File
@@ -359,13 +359,39 @@ collapses instead of pushing its neighbours. The optional `timelineSegments` inp
them; `normalizeTimelineSegments` (`controls-timeline-segments.ts`) clamps
to the duration, orders, drops empty and reversed entries, cuts overlaps at
the previous end and fills every gap with an untitled segment so the row
always covers `[0, duration]`. Without segments — every host today — the
row is one untitled segment, which is the plain bar. `ControlsTimeline`
owns the normalized list and the per-segment fill for the current scrub or
playback value; the hover label becomes `Chapter 2 · 12:40` over a titled
segment. Producers (EPG programmes for catch-up and timeshift playback,
mpv's chapter list) are separate follow-ups; the rendering, model and rules
are in place for them.
always covers `[0, duration]`. Without segments — live playback, VOD and
series — the row is one untitled segment, which is the plain bar.
`ControlsTimeline` owns the normalized list and the per-segment fill for the
current scrub or playback value; the hover label becomes `Chapter 2 · 12:40`
over a titled segment. mpv's chapter list is not a producer yet.
**Catch-up producer.** Archive playback of a live channel passes the EPG
programmes overlapping its archive window.
`buildCatchupTimelineSegments(programmes, activeProgramme, windowEnd?)`
(`catchup-timeline-segments.ts`) clips every programme to the window and
makes it relative to the window start, which is the activated programme's
start. Xtream timeshift URLs request exactly `[start, stop]` of that
programme, so the window ends at its stop. M3U catch-up URLs run from `utc`
to `lutc`, the moment the URL was resolved, so M3U hosts pass
`getM3uCatchupWindowEndSeconds(url)` (`@iptvnator/shared/m3u-utils`) and every
programme up to then is drawn. Programme and window times follow the EPG view
rule (unix timestamp, else the ISO string), so the display offset cancels.
The activated programme always owns its own span, with its own title: a
list from another date may lack it, and an overlapping or revised guide
entry must not relabel the archive being played, so other programmes only
fill the window after it. Live playback returns `null`. Stalker has no
archive playback, so it has no producer.
Plumbing mirrors `mediaTitle`: each live host derives
`catchupTimelineSegments` → `WebPlayerViewComponent.timelineSegments` → the
four engine hosts → `app-player-controls`. The hosts are the Xtream live
layout (`controlledEpgPrograms` + `activeCatchupProgram`), the unified live
tab for Favorites and Recent (`createUnifiedLiveEpgView`, both Xtream and
M3U), and the M3U playlist player (`epgPrograms` + `activeEpgProgram` while
`activePlaybackUrl` is set). `PortalInlinePlayerComponent` hosts no catch-up
and passes nothing. Like the Up next card, the segments reach Embedded MPV
under the frame-copy engine only, the one that mounts `app-player-controls`;
the native-view legacy dock keeps its plain slider.
### Up next card
@@ -306,6 +306,10 @@ tab can gate the timeline's archive window. `tv_archive_duration` is
interpreted as **days** everywhere, matching
`live-stream-layout.controlledArchiveDays` (issue #1138).
While a programme plays from the archive, both entry points draw it on the
player's seek bar as a titled segment; see "Timeline segments" in the
[player controls contract](player-controls-contract.md#timeline-segments).
Programme details in the Live TV and Favorites/Recent EPG timeline/list also
offer **Copy archive URL**. This uses the same resolver and persisted server
timezone without changing playback. See the M3U module's "Copy archive URL"