mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 01:16:15 -08:00
- Introduced tooling for building and staging the macOS `libmpv` runtime for IPTVnator's embedded MPV player. - Added `build-macos-runtime.mjs` for building an LGPL-compatible runtime from source. - Created `stage-macos-runtime.mjs` for staging the built runtime artifacts. - Implemented validation for the packaged embedded MPV runtime in `electron-after-pack.cjs` and `embedded-mpv-macos.cjs`. - Updated packaging scripts to ensure the embedded MPV runtime is correctly integrated and validated during the build process. - Added README files to document the expected layout and usage for the embedded MPV runtime artifacts. Entire-Checkpoint: c6e522b4276c
177 lines
7.7 KiB
Markdown
177 lines
7.7 KiB
Markdown
# Embedded Inline Playback
|
|
|
|
This document records the current contract for embedded playback in portal detail views.
|
|
|
|
## Summary
|
|
|
|
- Embedded web players are `videojs`, `html5`, and `artplayer`.
|
|
- `embedded-mpv` exists as a hidden macOS-only feasibility harness backed by a native `libmpv` addon.
|
|
- External players are `mpv` and `vlc`.
|
|
- Flatpak launches external players on the host via `flatpak-spawn --host`.
|
|
- Live playback stays inline in dedicated live layouts.
|
|
- VOD and series detail playback now also stays inline on canonical detail surfaces.
|
|
- Material dialog playback remains only as a fallback for older non-detail callers.
|
|
|
|
## Scope
|
|
|
|
The first pass is intentionally limited:
|
|
|
|
- Xtream VOD detail route
|
|
- Xtream series detail route
|
|
- Stalker VOD detail view
|
|
- Stalker series detail view
|
|
|
|
Not migrated in this pass:
|
|
|
|
- Generic non-detail playback entry points that still call `PlayerService.openPlayer(...)`
|
|
- Any collection/search surface that does not host a canonical detail surface of its own
|
|
|
|
## Embedded MPV Harness
|
|
|
|
The repository now contains a first-pass native embedded MPV harness for Electron:
|
|
|
|
- shared setting id: `embedded-mpv`
|
|
- native addon owner: `/Users/4gray/Code/iptvnator/apps/electron-backend/src/app/services/embedded-mpv-native.service.ts`
|
|
- IPC bridge: `/Users/4gray/Code/iptvnator/apps/electron-backend/src/app/events/embedded-mpv.events.ts`
|
|
- renderer host: `/Users/4gray/Code/iptvnator/libs/ui/playback/src/lib/embedded-mpv-player/embedded-mpv-player.component.ts`
|
|
- native architecture and release-readiness details: `/Users/4gray/Code/iptvnator/docs/architecture/embedded-mpv-native.md`
|
|
|
|
Current contract:
|
|
|
|
- macOS only
|
|
- experimental opt-in
|
|
- enabled in local development only when `IPTVNATOR_ENABLE_EMBEDDED_MPV_EXPERIMENT=1`
|
|
- enabled in packaged macOS builds only when the bundled native addon and `vendored-lgpl` libmpv runtime load successfully
|
|
- uses IPTVnator-owned controls and `ResolvedPortalPlayback` payloads
|
|
- uses the libmpv render API on macOS and renders through an IPTVnator-owned native `NSView`
|
|
- defaults to libmpv's OpenGL render backend with `hwdec=auto-safe`
|
|
- keeps the previous software renderer as a debug fallback via `IPTVNATOR_EMBEDDED_MPV_RENDERER=sw`
|
|
- emits lightweight render diagnostics when `IPTVNATOR_TRACE_EMBEDDED_MPV=1` is set
|
|
- exposes an IPTVnator-owned fullscreen button that uses the renderer fullscreen API and resyncs the native MPV view bounds after fullscreen transitions
|
|
- auto-hides IPTVnator-owned controls while playback is active and restores them on pointer/focus interaction
|
|
- exposes audio-track metadata from MPV and switches tracks through the `aid` property without reloading the stream
|
|
- passes VOD/episode resume offsets to MPV through the `loadfile` options map; live catchup URLs are treated as already-positioned streams
|
|
- applies the initial volume during session creation and uses async libmpv control calls after startup
|
|
- VLC remains external-only
|
|
|
|
Current limitation:
|
|
|
|
- the current feasibility harness is still experimental and macOS-specific
|
|
- the original macOS `wid` embedding path produced audio with a black video surface inside Electron, so the harness now avoids foreign-window embedding on macOS
|
|
- the OpenGL render path avoids the old per-frame `CGImage` copy path, but it still needs broader interaction, resize, and packaging coverage
|
|
- startup deadlocks seen during early macOS playback bring-up are mitigated, but the feature is still kept behind the explicit experiment flag until more interaction and packaging coverage is proven
|
|
- because of that, the setting is auto-sanitized back to the default inline player unless support detection reports that the experimental runtime is available
|
|
- this follows the rollout gate: keep the native work in-tree, but do not leave it user-facing until playback, resize, focus, and packaging are stable
|
|
|
|
## Components
|
|
|
|
Shared inline player shell:
|
|
|
|
- `/Users/4gray/Code/iptvnator/libs/ui/components/src/lib/portal-inline-player/portal-inline-player.component.ts`
|
|
|
|
Xtream detail hosts:
|
|
|
|
- `/Users/4gray/Code/iptvnator/libs/portal/xtream/feature/src/lib/vod-details/vod-details-route.component.ts`
|
|
- `/Users/4gray/Code/iptvnator/libs/portal/xtream/feature/src/lib/serial-details/serial-details.component.ts`
|
|
|
|
Stalker detail hosts:
|
|
|
|
- `/Users/4gray/Code/iptvnator/libs/portal/catalog/feature/src/lib/category-content-view/category-content-view.component.ts`
|
|
- `/Users/4gray/Code/iptvnator/libs/ui/components/src/lib/stalker-series-view/stalker-series-view.component.ts`
|
|
|
|
Fallback dialog path:
|
|
|
|
- `/Users/4gray/Code/iptvnator/apps/web/src/app/services/player.service.ts`
|
|
- `/Users/4gray/Code/iptvnator/libs/portal/xtream/feature/src/lib/player-dialog/player-dialog.component.ts`
|
|
|
|
## Playback Decision Rule
|
|
|
|
When a detail view starts playback:
|
|
|
|
1. Resolve or construct a typed playback payload.
|
|
2. Check the active player setting.
|
|
3. If the player is embedded, render the inline player inside the current detail view.
|
|
4. If the player is external, hand the same payload to `PlayerService` for MPV/VLC playback.
|
|
|
|
The detail host owns inline state. `PlayerService` is no longer the primary owner of UI playback state for canonical VOD/series detail screens.
|
|
|
|
## Flatpak External Players
|
|
|
|
Flatpak cannot execute host-installed `mpv` or `vlc` binaries directly from the sandbox.
|
|
|
|
Current contract:
|
|
|
|
- Flatpak launches external players through `flatpak-spawn --host`.
|
|
- AppImage, deb/rpm, snap, macOS, and Windows keep the existing direct process spawn flow.
|
|
- VLC keeps the current external-session flow in Flatpak, including the RC port used for progress polling.
|
|
- MPV is intentionally reduced in Flatpak: the app does not reuse an existing MPV instance there and does not open the Unix socket bridge used for non-Flatpak progress polling.
|
|
|
|
This keeps non-Flatpak behavior unchanged while allowing Flatpak builds to open host-installed external players.
|
|
|
|
## Typed Playback Payload
|
|
|
|
Shared playback payloads live in:
|
|
|
|
- `/Users/4gray/Code/iptvnator/libs/shared/interfaces/src/lib/portal-playback.interface.ts`
|
|
|
|
Types introduced:
|
|
|
|
- `PlayerContentInfo`
|
|
- `ResolvedPortalPlayback`
|
|
|
|
These provide a single shape for:
|
|
|
|
- `streamUrl`
|
|
- `title`
|
|
- optional thumbnail and resume start time
|
|
- playback-position metadata
|
|
- optional external-player headers and request metadata
|
|
|
|
## Xtream Behavior
|
|
|
|
Xtream detail views already own canonical routes, so they construct playback locally and decide inline vs external locally.
|
|
|
|
Behavior to preserve:
|
|
|
|
- resume/playback position continues saving from `timeUpdate`
|
|
- back navigation clears inline playback with the route
|
|
- favorites, recent, and search still route into canonical Xtream detail screens before playback
|
|
|
|
## Stalker Behavior
|
|
|
|
Stalker previously resolved playback and opened UI in the same method.
|
|
|
|
Current contract:
|
|
|
|
- `resolveVodPlayback(...)` returns a `ResolvedPortalPlayback`
|
|
- `createLinkToPlayVod(...)` remains as a compatibility wrapper for untouched callers
|
|
- canonical Stalker detail views use the resolver directly and decide inline vs external locally
|
|
|
|
This keeps:
|
|
|
|
- inline/store-state detail navigation intact
|
|
- series and VOD-as-series support intact
|
|
- non-detail callers working until they are migrated
|
|
|
|
## Playback Position Saving
|
|
|
|
The old dialog path saved playback positions from inside `PlayerDialogComponent`.
|
|
|
|
The new contract is:
|
|
|
|
- inline detail hosts listen to `timeUpdate`
|
|
- each host throttles saves
|
|
- each host persists via existing playback-position infrastructure
|
|
|
|
This avoids coupling inline UI state to a global dialog.
|
|
|
|
## Future Migration Rule
|
|
|
|
If a non-detail surface is converted away from dialog playback:
|
|
|
|
- give that surface a canonical inline host
|
|
- switch it to `ResolvedPortalPlayback`
|
|
- do not move portal-specific navigation into `PlayerService`
|
|
|
|
The preferred direction is view-owned inline playback, not a larger dialog manager.
|