WebPlayerViewComponent remounts the engine component for every playback
application, and the DOM Fullscreen API exits the moment its element leaves
the document. The fullscreen element was the engine shell, so every next-
episode click, autoplay hand-off, channel zap and alternative-source switch
dropped the viewer back to the page.
app-player-controls gains a `fullscreenTarget` input; HTML5, Video.js,
ArtPlayer and Embedded MPV forward it, and WebPlayerViewComponent passes its
own host element, which spans all applications of one mount. Keeping
fullscreen exposed a latent bug: the Electron header handoff set plain
fields under OnPush hosts and was only rendered thanks to the fullscreen
exit's stage resize; `channel`/`vjsOptions` are signals now.
Covered by unit regressions (fullscreen target, WebPlayerView remount, OnPush
handoff), a web-e2e run through a manual and an automatic episode switch, and
a manual Electron check. Docs and release note updated.
Closes#1498
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Video.js was constructed without the controls option — the component relied
on a [controls] template binding on the original <video> element instead.
player.reset(), which every raw MPEG-TS/live source change goes through,
replaces the tech <video> element; the binding's target is disposed, so live
playback ended up with no native controls and a vjs-controls-disabled control
bar: no visible controls at all.
Enable controls through the Video.js constructor options in legacy mode and
drop the template binding. The Video.js control bar is a player-level child
that survives loadTech_, so it stays across resets — and the quality selector
and aspect-ratio panel buttons it hosts become reachable again.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(playback): show media title overlay in fullscreen shared controls
In fullscreen with the shared player-controls layer, a pointer-transparent
overlay at the top of the player now names the content while controls are
revealed: one line for movies and live channels, two lines for series
(series name + S01E03 label). The overlay follows the bar's auto-hide
transition and stays hidden outside fullscreen, where page chrome already
names the content.
Data flows top-down: the Xtream/Stalker series detail views pass the series
name via a new PortalInlinePlayerComponent.seriesTitle input (Xtream episode
playback titles carry the episode name, not the series), the inline player
builds the two-line form from the episode metadata label, and
WebPlayerViewComponent falls back to playback.title for movies/channels
while skipping raw stream-URL fallbacks. All four shared-controls hosts
(HTML5, Video.js, ArtPlayer, Embedded MPV frame-copy) forward the value.
To stay under the max-lines limit, scrub/timeline state is extracted into
ControlsTimeline and the playback-diagnostics display helpers into
web-player-view-diagnostics.utils.ts, with behavior unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: mirror fullscreen media-title contract into AGENTS.md
Addresses Codex review: the Shared Player Controls section in AGENTS.md
must stay in sync with the CLAUDE.md description of the new mediaTitle
input, fullscreen overlay behavior, and series-title wiring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(videojs): add feature-flagged shared controls
Rebuild the Video.js shared-controls integration on the current player lifecycle with Tech rebinds, source-scoped tracks, reset ordering, volume preservation, diagnostics gating, and default-off compatibility.
Credits and supersedes the stacked implementation proposed in #1153.
Co-authored-by: Lars Emig <lars.emig@pickware.de>
* fix(videojs): harden MPEG-TS reset lifecycle
---------
Co-authored-by: Lars Emig <lars.emig@pickware.de>