mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
fix(playback): preserve Shaka text error evidence
This commit is contained in:
1 parent
50ca78d3a8
commit
8a5b6e85cc
8 files changed
+97
-13
No files matched your search
@@ -3,4 +3,4 @@ type: fix
|
||||
area: playback
|
||||
---
|
||||
|
||||
Shaka playback errors now use exact engine evidence, preserve external-player fallback when browser prerequisites are missing, keep recoverable retries non-terminal, and omit provider URLs, credentials, and response data from technical details.
|
||||
Shaka playback errors now use exact engine evidence, including subtitle parsing, preserve external-player fallback when browser prerequisites are missing, keep recoverable retries non-terminal, and omit provider URLs, credentials, and response data from technical details.
|
||||
@@ -212,10 +212,11 @@ Key files:
|
||||
`Channel.drm`, and the shared bridge exposes Shaka audio/text tracks via
|
||||
source kind `shaka`. The Shaka `5.2.2` diagnostic boundary version-locks
|
||||
public severity/category/code evidence, ignores recoverable error events,
|
||||
treats rejected loads as terminal lifecycle outcomes, and never retains or
|
||||
renders raw messages or `error.data`. A failed browser-support preflight
|
||||
stays unknown but keeps external fallback for clear DASH; KODIPROP DRM still
|
||||
suppresses it. See the CLAUDE.md "Video Players" feature entry and
|
||||
treats rejected loads as terminal lifecycle outcomes, preserves exact public
|
||||
DASH text-parser category/code evidence with unknown stage/failure, and never
|
||||
retains or renders raw messages or `error.data`. A failed browser-support
|
||||
preflight stays unknown but keeps external fallback for clear DASH; KODIPROP
|
||||
DRM still suppresses it. See the CLAUDE.md "Video Players" feature entry and
|
||||
`docs/architecture/m3u-playlist-module.md` ("DASH + ClearKey Playback").
|
||||
- The built-in HTML5/hls.js player is the second guarded consumer.
|
||||
`HtmlVideoPlayerComponent` provides a component-scoped
|
||||
|
||||
@@ -737,9 +737,10 @@ app as a real argument, so it is not an option.
|
||||
`libs/ui/playback/src/lib/shaka-engine/`. Its Shaka `5.2.2` diagnostic
|
||||
boundary version-locks public severity/category/code evidence, ignores
|
||||
recoverable error events, treats rejected loads as terminal lifecycle
|
||||
outcomes, and never retains or renders raw messages or `error.data`. A failed
|
||||
browser-support preflight stays unknown but keeps external fallback for clear
|
||||
DASH; KODIPROP DRM still suppresses it. Details in
|
||||
outcomes, preserves exact public DASH text-parser category/code evidence with
|
||||
unknown stage/failure, and never retains or renders raw messages or
|
||||
`error.data`. A failed browser-support preflight stays unknown but keeps
|
||||
external fallback for clear DASH; KODIPROP DRM still suppresses it. Details in
|
||||
`docs/architecture/m3u-playlist-module.md` ("DASH + ClearKey Playback").
|
||||
- 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=<x11-window>` 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. Renderer bounds are CSS pixels; the service converts them to native units in the main process (`embedded-mpv-bounds.util.ts`: × page zoom everywhere, × display scale on Windows/Linux whose child windows are positioned in physical pixels; frame-copy bounds stay unscaled), and the session controller re-syncs bounds when `devicePixelRatio` changes. Service: `apps/electron-backend/src/app/services/embedded-mpv-native.service.ts`; full architecture: `docs/architecture/embedded-mpv-native.md`.
|
||||
|
||||
@@ -412,7 +412,9 @@ category alone is not container incompatibility, and Shaka messages never infer
|
||||
CORS, codec, DRM, container, or stage. The public critical
|
||||
`STREAMING_ENGINE_STARTUP_INVALID_STATE` code remains exact evidence while its
|
||||
stage and failure stay unknown because the code does not identify a user-facing
|
||||
media cause.
|
||||
media cause. Public DASH text-parser codes are also retained exactly; their
|
||||
`TEXT` category proves the parser subsystem, but not a safe manifest, segment,
|
||||
or media cause, so stage and failure remain unknown.
|
||||
|
||||
A failed public `Player.isBrowserSupported()` preflight is not a Shaka error
|
||||
and therefore retains fully unknown technical evidence instead of being
|
||||
|
||||
@@ -1004,10 +1004,12 @@ player in settings.
|
||||
validated HTTP status. Exact category/code pairs classify failures, while an
|
||||
ambiguous Manifest category or unknown pair remains an unknown diagnostic.
|
||||
The public streaming-startup code `5006` is retained exactly but keeps
|
||||
unknown stage/failure. A failed `Player.isBrowserSupported()` preflight also
|
||||
stays unknown rather than claiming container incompatibility; clear DASH
|
||||
still offers configured external-player actions, while KODIPROP DRM keeps
|
||||
them disabled because those players never receive its keys.
|
||||
unknown stage/failure. Public DASH text-parser codes likewise retain their
|
||||
exact `TEXT` category/code but keep stage/failure unknown. A failed
|
||||
`Player.isBrowserSupported()` preflight also stays unknown rather than
|
||||
claiming container incompatibility; clear DASH still offers configured
|
||||
external-player actions, while KODIPROP DRM keeps them disabled because
|
||||
those players never receive its keys.
|
||||
Channels with `drm.supported === false` emit a `DrmOrEncryption` diagnostic
|
||||
with a fixed safe detail string and without starting an engine.
|
||||
- HTML5 player: `extension === 'mpd'` branch in `playChannel()`. ArtPlayer:
|
||||
|
||||
@@ -38,6 +38,16 @@ export const SHAKA_ERROR_CODE = {
|
||||
REQUEST_FILTER_ERROR: 1006,
|
||||
RESPONSE_FILTER_ERROR: 1007,
|
||||
SEGMENT_MISSING: 1011,
|
||||
// Text parsing reachable from DASH playback. HLS-only and app-uninvoked
|
||||
// external-track/src= codes stay outside this boundary.
|
||||
INVALID_TEXT_HEADER: 2000,
|
||||
INVALID_TEXT_CUE: 2001,
|
||||
UNABLE_TO_DETECT_ENCODING: 2003,
|
||||
BAD_ENCODING: 2004,
|
||||
INVALID_XML: 2005,
|
||||
INVALID_MP4_TTML: 2007,
|
||||
INVALID_MP4_VTT: 2008,
|
||||
INVALID_MP4_CEA: 2010,
|
||||
BUFFER_READ_OUT_OF_BOUNDS: 3000,
|
||||
JS_INTEGER_OVERFLOW: 3001,
|
||||
EBML_OVERFLOW: 3002,
|
||||
|
||||
@@ -210,6 +210,41 @@ describe('Shaka playback evidence', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
['INVALID_TEXT_HEADER', 2000],
|
||||
['INVALID_TEXT_CUE', 2001],
|
||||
['UNABLE_TO_DETECT_ENCODING', 2003],
|
||||
['BAD_ENCODING', 2004],
|
||||
['INVALID_XML', 2005],
|
||||
['INVALID_MP4_TTML', 2007],
|
||||
['INVALID_MP4_VTT', 2008],
|
||||
['INVALID_MP4_CEA', 2010],
|
||||
])('preserves the exact public DASH text code %s', (_name, code) => {
|
||||
expect(
|
||||
createEvidence({ severity: 2, category: 2, code }, 'terminal')
|
||||
).toEqual({
|
||||
severity: 'critical',
|
||||
category: 'text',
|
||||
engineCode: code,
|
||||
disposition: 'terminal',
|
||||
stage: 'unknown',
|
||||
failure: 'unknown',
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects public text codes from app-uninvoked explicit-track APIs', () => {
|
||||
expect(
|
||||
createEvidence({ severity: 2, category: 2, code: 2014 }, 'terminal')
|
||||
).toEqual({
|
||||
severity: 'critical',
|
||||
category: 'text',
|
||||
engineCode: 'unknown',
|
||||
disposition: 'terminal',
|
||||
stage: 'unknown',
|
||||
failure: 'unknown',
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
label: 'manifest parsing',
|
||||
|
||||
@@ -286,6 +286,39 @@ describe('ShakaVideoSession', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves a terminal text-parser event without retaining parser data', async () => {
|
||||
const secret = 'subtitle-parser-secret';
|
||||
const environment = createFakeShakaEnvironment();
|
||||
const session = createSession(environment);
|
||||
session.start(video, 'http://example.com/text-track.mpd');
|
||||
await flush();
|
||||
|
||||
const player = environment.instances[0];
|
||||
player.dispatch('error', {
|
||||
severity: 2,
|
||||
category: 2,
|
||||
code: 2000,
|
||||
message: `malformed WebVTT from ${secret}`,
|
||||
data: [{ cue: secret }],
|
||||
});
|
||||
|
||||
expect(issues).toHaveLength(1);
|
||||
expect(issues[0].code).toBe(
|
||||
PlaybackDiagnosticCode.UnknownPlaybackError
|
||||
);
|
||||
expect(issues[0].shaka).toEqual({
|
||||
severity: 'critical',
|
||||
category: 'text',
|
||||
engineCode: 2000,
|
||||
disposition: 'terminal',
|
||||
stage: 'unknown',
|
||||
failure: 'unknown',
|
||||
});
|
||||
expect(JSON.stringify(issues[0])).not.toContain(secret);
|
||||
expect(player.destroyCount).toBe(1);
|
||||
expect(session.getPlayer()).toBeNull();
|
||||
});
|
||||
|
||||
it('emits a critical in-flight error once before teardown interrupts load', async () => {
|
||||
const environment = createFakeShakaEnvironment({
|
||||
onCreate: (player) => {
|
||||
|
||||
Reference in new issue
Block a user