mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 01:16:15 -08:00
feat(playback): report Embedded MPV file chapters on the timeline (#1771)
This commit is contained in:
1 parent
d0e366a368
commit
9bc577a4c9
24 files changed
+931
-5
No files matched your search
@@ -487,6 +487,8 @@ Audio tracks are discovered from MPV's `track-list` property. The selected track
|
||||
|
||||
Subtitle tracks mirror the audio-track contract: same `track-list` source, same parsing pipeline, but selected through MPV's `sid` property. A `trackId` of `-1` from the renderer is interpreted as "disable subtitles" and translated to `sid=no` at the addon boundary. Playback speed is observed and set through MPV's `speed` property, clamped at the addon to `[0.25, 4.0]`. Aspect override uses MPV's `video-aspect-override` property as a passthrough string ("no", "16:9", "4:3", "21:9", "2.35:1"). All four properties (`sid`, `speed`, `video-aspect-override`, plus `aid`) are observed at session init so renderer state stays in sync with the native side without needing extra round-trips.
|
||||
|
||||
File chapters come from MPV's `chapter-list` property, observed as a node next to `track-list` by the macOS and Windows addons and the frame-copy helper, and cleared on every `START_FILE` so a replacement file never shows the previous one's chapters. Each snapshot carries `chapters: [{ timeSeconds, title? }]` (the helper always emits the key, because the adapter merges snapshot events field by field); `EmbeddedMpvNativeService` validates it with `normalizeEmbeddedMpvChapters` into `EmbeddedMpvSession.chapters`, and an older binary without the field yields `[]`. The Linux `mpv --wid` poller does not read chapters. The renderer maps them to timeline segments — see "Timeline segments" in the [player controls contract](player-controls-contract.md).
|
||||
|
||||
The renderer learns which features the loaded addon binary supports through the `EmbeddedMpvSupport.capabilities` field returned from `getEmbeddedMpvSupport()`. The service probes `typeof addon.<method> === 'function'` for each optional native export. Older addon binaries with the original audio-only surface return `capabilities: { subtitles: false, playbackSpeed: false, aspectOverride: false, screenshot: false, recording: false }`, and the renderer hides the corresponding controls instead of throwing at runtime. Linux intentionally does not export libmpv-only optional controls while it uses the process-isolated `mpv --wid` backend.
|
||||
|
||||
Linux audio-track discovery works differently from macOS/Windows because the hand-rolled JSON IPC reply parser only understands scalar `data` values: the poll loop reads `track-list/count` every tick and walks the scalar `track-list/N/{type,id,title,lang,default,forced}` sub-properties only when the count changes. The selected track is reconciled from the scalar `aid` property on every tick (`aid` reads back non-numeric when audio is disabled, which maps to "no selection"). Track switching still goes through `set_property aid` over the same socket.
|
||||
|
||||
@@ -366,7 +366,23 @@ 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.
|
||||
over a titled segment.
|
||||
|
||||
**Chapter producer.** Embedded MPV reports the file's own chapters: the
|
||||
addons and the frame-copy helper observe mpv `chapter-list` and publish it
|
||||
as `EmbeddedMpvSession.chapters` (`{ timeSeconds, title? }`, validated in
|
||||
main by `normalizeEmbeddedMpvChapters`). `buildChapterTimelineSegments`
|
||||
(`chapter-timeline-segments.ts`) runs each chapter from its start to the
|
||||
next one's, the last to the duration, orders them and drops repeated or
|
||||
out-of-range starts; an untitled chapter becomes an untitled segment, and
|
||||
no chapters or no finite duration yields `null`.
|
||||
`EmbeddedMpvPlayerComponent.controlsTimelineSegments`
|
||||
(`embeddedMpvTimelineSegments`) passes the host's segments when it
|
||||
supplies any and the chapter segments otherwise, so catch-up programmes
|
||||
always win; `sameTimelineSegments` keeps a re-polled, unchanged list from
|
||||
counting as a change. The Linux native-view `mpv --wid` backend reads no
|
||||
chapters, and the web engines report none (streamed HLS/DASH carries no
|
||||
chapter track), so their VOD and series stay one plain bar.
|
||||
|
||||
**Catch-up producer.** Archive playback of a live channel passes the EPG
|
||||
programmes overlapping its archive window.
|
||||
@@ -413,8 +429,9 @@ episode: `upNextThresholdSeconds` is 4% of the duration clamped to
|
||||
`timelineSegments` carry a closing-credits chapter in the last third
|
||||
(`creditsStartSeconds`: "Credits", "Outro", "Ending", an anime `ED`, and a
|
||||
few localized names), the card appears when it starts instead, at most
|
||||
5 min before the end. No engine reports file chapters today, so in practice
|
||||
the adaptive lead applies. The countdown shows whole minutes, and seconds
|
||||
5 min before the end. Embedded MPV under the frame-copy engine supplies
|
||||
file chapters (see the chapter producer above); every other engine, and a
|
||||
file without a credits chapter, uses the adaptive lead. The countdown shows whole minutes, and seconds
|
||||
in the last minute. A
|
||||
still that fails to load falls back to the label tile. A
|
||||
click emits `nextEpisodeRequested` directly — not through the
|
||||
|
||||
Reference in new issue
Block a user