Files
iptvnator/docs/superpowers/plans/2026-07-16-videojs-shared-controls.md
T
4grayandLars Emig 4e572c60ca feat(videojs): add feature-flagged shared controls (#1195)
* 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>
2026-07-16 23:08:18 +02:00

201 lines
5.7 KiB
Markdown

# Video.js Shared Controls Replacement Implementation Plan
> Execute with test-driven development. Each behavior change starts with a
> focused failing test, then the minimum implementation, then targeted and broad
> verification.
## Task 1: Extract focused Video.js types
Files:
- Add `libs/ui/playback/src/lib/vjs-player/vjs-player.types.ts`.
- Update `vjs-player.component.ts` imports.
Steps:
1. Move only the API shapes shared by collaborators.
2. Preserve existing runtime behavior.
3. Run the existing Video.js component spec.
## Task 2: Extract and harden audio-track ownership
Files:
- Add `vjs-audio-tracks.ts`.
- Add `vjs-audio-tracks.spec.ts`.
- Update `vjs-player.component.ts`.
Tests first:
- project labels and stable IDs;
- select exactly one valid track;
- stale/invalid ID is a no-op;
- legacy menu remains available flag-off;
- add/remove/change/labelchange refresh through stable callbacks;
- identity-aware bind and exact cleanup.
Implementation:
- Preserve the useful logging/menu behavior from #1153.
- Reset IDs at each source boundary.
- Use the same collaborator in legacy and shared modes.
## Task 3: Add Video.js subtitle-track ownership
Files:
- Add `vjs-text-tracks.ts`.
- Add `vjs-text-tracks.spec.ts`.
Tests first:
- filter captions/subtitles;
- stable IDs within a source;
- select one track and disable the rest;
- `-1` explicitly disables all tracks;
- stale ID is a no-op;
- global caption suppression/restoration;
- explicit off survives preference and track-list events;
- source reset and exact listener cleanup.
Implementation:
- Use `player.textTracks()`.
- Keep the helper Video.js-specific.
## Task 4: Extract raw MPEG-TS session
Files:
- Add `vjs-mpegts-session.ts`.
- Add `vjs-mpegts-session.spec.ts`.
- Remove the corresponding code from `vjs-player.component.ts`.
Tests first:
- source detection including query-declared HLS;
- authoritative live/VOD option;
- attach/load/play on the supplied current Tech video;
- VOD duration normalization;
- error classification;
- missing video handling;
- idempotent destroy and exact listener cleanup.
Implementation:
- Keep raw MPEG-TS attachment in the session and put pause/coalesced-reset
ordering in a focused reset coordinator.
- Make `start` accept the current Tech video explicitly.
## Task 5: Add a rebindable Tech video session
Files:
- Add `vjs-video-element-session.ts`.
- Add `vjs-video-element-session.spec.ts`.
Tests first:
- attach once;
- rebind A → B removes all listeners from A and adds them once to B;
- loaded/playing clear the diagnostic;
- ended emits once;
- destroy is idempotent.
## Task 6: Add the shared-controls bridge
Files:
- Add `vjs-player-controls.bridge.ts`.
- Add `vjs-player-controls.bridge.spec.ts`.
Tests first:
- attach to the current Tech video;
- adapter accessors expose live/VOD, duration, audio, and subtitles;
- rebind detaches A and attaches B exactly once;
- source clear resets track state;
- input refresh reapplies captions and classification;
- destroy cleans track listeners and adapter exactly once.
Implementation:
- Use the component-scoped `WebVideoControlsAdapter`.
- Delegate track ownership to the focused collaborators.
## Task 7: Integrate the component and host
Files:
- Update `vjs-player.component.ts`, `.html`, and focused specs.
- Add `vjs-player.component.shared-controls.spec.ts`.
- Update `web-player-view.component.html`.
- Update `web-player-view.component.shared-controls.spec.ts`.
Tests first:
- flag-off preserves Video.js chrome and legacy navigation;
- flag-on renders exactly one shared controls UI;
- flag-on disables native controls, Video.js gestures/hotkeys, and spatial nav;
- shared controls use the real shell;
- diagnostic gating disables controls/shortcuts and exits owned fullscreen;
- both host Video.js branches receive `showCaptions` and
`interactionEnabled`;
- `playerreset` rebinds the video session and controls bridge;
- reset-required changes coalesce while applying only the latest desired
source;
- active playback pauses before `reset()`, and reset volume=1 never overwrites
the user's actual volume;
- pre-ready reset does not start MPEG-TS twice;
- raw MPEG-TS restarts when authoritative live/VOD metadata changes.
Implementation ordering:
1. Create Video.js and register stable player lifecycle handlers.
2. On initial ready, bind the current Tech video and active source.
3. Before reset, snapshot actual volume, pause, and coalesce the latest desired
source.
4. On any `playerreset`, restore volume, rebind sessions, and apply only the
latest desired source before starting MPEG-TS.
5. Track whether the current Tech already has its source so pre-ready reset
cannot double-start playback.
6. Destroy coordinator/bridge/session collaborators before `player.dispose()`.
## Task 8: Reduce file baselines and update canonical docs
Files:
- Update `tools/eslint/max-lines-baseline.mjs`.
- Update `docs/architecture/player-controls-contract.md`.
- Update `AGENTS.md` and `CLAUDE.md` only where their current shared-controls
description becomes stale.
- Update `web-player-controls.flag.ts` documentation.
Checks:
- `vjs-player.component.ts` is below 400 lines.
- Split the component spec if needed and remove stale max-lines baselines.
## Task 9: Verification and PR loop
Run:
```bash
pnpm nx test ui-playback --skip-nx-cache
pnpm nx lint ui-playback --skip-nx-cache
pnpm run typecheck:ci
pnpm run coverage:ci
pnpm run lint
git diff --check
```
Then:
1. Push the replacement branch.
2. Open a replacement PR that credits #1153 and states it supersedes it.
3. Trigger fresh Codex and Greptile reviews.
4. Resolve only verified findings.
5. Require full green CI.
6. Squash merge the replacement.
7. Close #1153 with thanks and a link to the merged replacement.