diff --git a/AGENTS.md b/AGENTS.md index 2af3566df..40f0defb9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -159,8 +159,19 @@ Key files: interaction and shortcuts and exits the HTML5 shell's own fullscreen so the diagnostic actions remain visible. The flag-off path keeps native controls and legacy series navigation unchanged. -- Video.js and ArtPlayer are not wired yet. Their existing skins remain active, - and the web rollout token remains default-off. +- Video.js is the third guarded consumer. `VjsPlayerComponent` provides a + component-scoped `WebVideoControlsAdapter`; its bridge binds the current Tech + video, rebinds after `playerreset`, exposes source-stable audio/subtitle IDs, + preserves caption preference and explicit subtitle-off state, and reads + duration from Video.js. Reset-driven raw MPEG-TS changes pause first, + coalesce to the latest desired source, preserve actual volume across + Video.js's reset, and restart when authoritative live/VOD metadata changes. + The flag-on path disables native controls, Video.js + click/double-click/hotkey actions, and spatial navigation; + diagnostic gating and owned-fullscreen exit match HTML5. The flag-off path + keeps the existing Video.js skin and legacy series navigation unchanged. +- ArtPlayer is not wired yet. Its existing skin remains active, and the web + rollout token remains default-off. - Canonical docs: `docs/architecture/player-controls-contract.md` and `docs/architecture/embedded-mpv-native.md` diff --git a/CLAUDE.md b/CLAUDE.md index 20947f568..5c4dd0925 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -618,7 +618,7 @@ This project uses modern Angular signal-based APIs and patterns. **ALWAYS** use - External players: MPV, VLC (via IPC to Electron backend) - Embedded MPV (experimental, macOS/Windows/Linux): renders mpv video inside the Electron window through a native addon. macOS uses the libmpv render API in an `NSOpenGLView`; Windows uses in-process libmpv with `--wid` against an app-owned child `HWND`; Linux spawns an out-of-process `mpv --wid=` controlled over a JSON IPC socket (X11/XWayland only, requires system `mpv` on PATH; subtitles/speed/aspect/recording are not exported there). mpv's own screensaver inhibition does not apply to any of these paths, so `EmbeddedMpvNativeService` holds an Electron `powerSaveBlocker` (`prevent-display-sleep`) whenever any session's status is `playing`, and releases it on pause, dispose, or shutdown. Service: `apps/electron-backend/src/app/services/embedded-mpv-native.service.ts`; full architecture: `docs/architecture/embedded-mpv-native.md`. - Embedded MPV frame-copy engine (experimental, macOS Apple Silicon + Linux + Windows; enabled via `Settings > Playback > Embedded MPV: frame-copy engine` (restart required) or `IPTVNATOR_ENABLE_EMBEDDED_MPV_FRAME_COPY=1` on top of the embedded MPV experiment flag): a per-session helper renders mpv offscreen at viewport size (headless CGL on macOS, headless EGL on Linux, WGL against a hidden window on Windows) and publishes BGRA frames into a shm ring (POSIX shm; a `Local\` named file mapping on Windows); the preload frame pump uploads them onto a renderer ``, so controls/dialogs are ordinary DOM above the video. Frame-copy is the first runtime consumer of shared `app-player-controls`: `PlayerControlsComponent` and its surface/shortcut/fullscreen collaborators own the DOM UI interactions, while the component-scoped `EmbeddedMpvControlsAdapter` maps session state and commands and coordinates correlated recording state; native-view retains the legacy fixed dock. Stored and explicit opt-ins relax the sandbox only while the base embedded-MPV feature is enabled and a platform-supported packaged runtime contains both the regular-file helper (`iptvnator_mpv_helper` / `.exe`) and readable regular frame-reader addon; packaged discovery is restricted to packaged resources. A disabled base experiment keeps embedded MPV unavailable with the sandbox intact, while a missing, mode-stripped, or incomplete frame-copy runtime falls back to the native engine without relaxing the sandbox. On Linux the engine is dev-build-only for now: the helper links system libmpv (build deps: `libmpv-dev`, `libegl-dev`, `libgl-dev`, `libopengl-dev`, `libgbm-dev`) and is stripped from packages until bundled-runtime staging lands. On Windows the helper links vendored libmpv and package validation requires the exact MPV DLL named in the helper's PE import table beside the executable. Backend process adapter: `apps/electron-backend/src/app/services/embedded-mpv-frame-copy.adapter.ts`; shared-controls adapter: `libs/ui/playback/src/lib/embedded-mpv-player/embedded-mpv-controls.adapter.ts`; helper: `apps/electron-backend/native/helper/`; details in `docs/architecture/embedded-mpv-native.md` ("Frame-Copy Engine"). -- Shared player-controls layer: `libs/ui/playback/src/lib/player-controls/` exports the engine-neutral `PlayerController` contract, standalone `app-player-controls`, a generic web-video adapter/helper, and a default-off web rollout token. Embedded MPV frame-copy consumes it through `EmbeddedMpvControlsAdapter`; the host selects exactly one UI, so native-view retains its compositor-safe dock. `showControls=false` detaches the shared surface, modal overlays gate frame-copy playback shortcuts, fullscreen remains DOM-based with Embedded MPV bounds sync, and a playback/session transition key prevents engine or session handoff from presenting stale recording feedback while timers and pending commands are cancelled. Same-session IPC replies yield to a broadcast snapshot received while the command was pending, so a successful recording acknowledgement cannot be rolled back by a stale reply. The built-in HTML5/hls.js player is the second guarded consumer: `HtmlVideoPlayerComponent` provides a component-scoped `WebVideoControlsAdapter`, while its local bridge owns HLS/native tracks, MPEG-TS VOD duration correction, caption preference, and source cleanup. `HtmlVideoElementSession` owns native video-event lifecycle, persisted volume, start-time/time/ended propagation, and legacy post-play caption suppression. `WebPlayerViewComponent.resolvedIsLive` supplies authoritative metadata; visible playback diagnostics disable shared pointer/keyboard ownership and exit the HTML5 shell's own fullscreen so retry/fallback actions remain visible. The default-off path retains native controls and legacy series navigation. Video.js and ArtPlayer remain unwired with their existing skins. Contract: `docs/architecture/player-controls-contract.md`. +- Shared player-controls layer: `libs/ui/playback/src/lib/player-controls/` exports the engine-neutral `PlayerController` contract, standalone `app-player-controls`, a generic web-video adapter/helper, and a default-off web rollout token. Embedded MPV frame-copy consumes it through `EmbeddedMpvControlsAdapter`; the host selects exactly one UI, so native-view retains its compositor-safe dock. `showControls=false` detaches the shared surface, modal overlays gate frame-copy playback shortcuts, fullscreen remains DOM-based with Embedded MPV bounds sync, and a playback/session transition key prevents engine or session handoff from presenting stale recording feedback while timers and pending commands are cancelled. Same-session IPC replies yield to a broadcast snapshot received while the command was pending, so a successful recording acknowledgement cannot be rolled back by a stale reply. The built-in HTML5/hls.js player is the second guarded consumer: `HtmlVideoPlayerComponent` provides a component-scoped `WebVideoControlsAdapter`, while its local bridge owns HLS/native tracks, MPEG-TS VOD duration correction, caption preference, and source cleanup. `HtmlVideoElementSession` owns native video-event lifecycle, persisted volume, start-time/time/ended propagation, and legacy post-play caption suppression. Video.js is the third guarded consumer: `VjsPlayerComponent` provides a component-scoped `WebVideoControlsAdapter`; its bridge rebinds the current Tech video after `playerreset`, exposes source-stable audio/subtitle IDs, preserves caption preference and explicit subtitle-off state, and reads Video.js duration. Reset-driven raw MPEG-TS changes pause first, coalesce to the latest desired source, preserve actual volume across Video.js's reset, and restart when authoritative live/VOD metadata changes. With the flag on, Video.js native controls, click/double-click/hotkey actions, and spatial navigation are disabled. `WebPlayerViewComponent.resolvedIsLive` supplies authoritative metadata; visible playback diagnostics disable shared pointer/keyboard ownership and exit the active HTML5 or Video.js shell's own fullscreen so retry/fallback actions remain visible. Default-off paths retain native/Video.js controls and legacy series navigation. ArtPlayer remains unwired with its existing skin. Contract: `docs/architecture/player-controls-contract.md`. **VOD/Series Detail Pages (two-state layout)**: diff --git a/docs/architecture/player-controls-contract.md b/docs/architecture/player-controls-contract.md index aa4aa3d97..48b60b18f 100644 --- a/docs/architecture/player-controls-contract.md +++ b/docs/architecture/player-controls-contract.md @@ -7,7 +7,7 @@ Embedded MPV rendering and native-view bounds behavior remain documented in ## Current status -The shared-controls foundation from PR #1148 now has two runtime consumers: +The shared-controls foundation from PR #1148 now has three runtime consumers: - the `PlayerController` contract, default state, and capability presets; - the standalone `app-player-controls` presentation component and its @@ -17,7 +17,9 @@ The shared-controls foundation from PR #1148 now has two runtime consumers: - the component-scoped `EmbeddedMpvControlsAdapter`; - an `EmbeddedMpvPlayerComponent` host integration for the frame-copy engine; - a feature-flagged `HtmlVideoPlayerComponent` integration backed by - `WebVideoControlsAdapter` and a player-local engine bridge; and + `WebVideoControlsAdapter` and a player-local engine bridge; +- a feature-flagged `VjsPlayerComponent` integration backed by a + component-scoped `WebVideoControlsAdapter` and Video.js bridge; and - focused unit/component tests. When Embedded MPV reports `engine: 'frame-copy'`, the component mounts @@ -33,10 +35,15 @@ MPEG-TS VOD duration, and authoritative live/VOD metadata to the generic web adapter. When the flag is disabled, the native controls and legacy series navigation remain unchanged and the adapter is not attached. -Video.js and ArtPlayer do not consume the shared layer yet. Their existing -skins remain active, and `WEB_PLAYER_SHARED_CONTROLS_ENABLED` remains -default-off, so the guarded HTML5 integration does not change normal runtime -behavior. +Video.js consumes the same token and shared presentation atomically. Its bridge +binds the adapter to the current Video.js Tech `