mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
docs(playback): design structured HLS diagnostics
This commit is contained in:
1 parent
bf13849d69
commit
fc393e5ec7
1 file changed
+210
@@ -0,0 +1,210 @@
|
||||
# Structured HLS Diagnostics
|
||||
|
||||
## Context
|
||||
|
||||
PR #1314 made native media diagnostics evidence-based, but the HLS path still
|
||||
normalizes `type`, `details`, `message`, and an arbitrary `error` payload into
|
||||
one string. `classifyHlsPlaybackIssue` then searches that string for broad
|
||||
fragments such as `network`, `status`, and `codec`. This can misclassify a
|
||||
provider message, and serializing arbitrary values can retain URLs,
|
||||
credentials, response content, loader context, or other provider data.
|
||||
|
||||
IPTVnator currently installs hls.js 1.6.16. Its public `ErrorData` supplies
|
||||
structured `type`, `details`, `fatal`, and an optional `response.code`.
|
||||
Specific `ErrorDetails` values also identify the manifest, level, segment, key,
|
||||
or media stage. The same payload contains unsafe or unbounded fields, including
|
||||
`error`, `reason`, `networkDetails`, `context`, `loader`, `url`, and response
|
||||
URL/text/data, which are not needed for classification.
|
||||
|
||||
Both the HTML5 player and ArtPlayer subscribe to `Hls.Events.ERROR`. They
|
||||
currently ignore `fatal: false` before calling the classifier, but each adapter
|
||||
builds the broad string input independently.
|
||||
|
||||
## Goals
|
||||
|
||||
- Create one structured HLS evidence boundary for the installed hls.js error
|
||||
shape.
|
||||
- Retain only allowlisted engine type/detail identifiers, the final
|
||||
fatal/recoverable disposition, a stage derived from exact details, a
|
||||
structured failure kind, and a validated HTTP status when present.
|
||||
- Classify HLS failures from exact engine values rather than substring
|
||||
heuristics.
|
||||
- Keep insufficient evidence explicitly unknown.
|
||||
- Ensure recoverable hls.js events never become terminal playback diagnostics.
|
||||
- Use the same extraction and classification path in HTML5 and ArtPlayer.
|
||||
- Show only the sanitized evidence in technical diagnostic details.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Diagnostic history, persistence, correlation, or telemetry.
|
||||
- Additional manifest or stream probes.
|
||||
- Automatic player failover.
|
||||
- A Shaka or mpegts.js diagnostic redesign.
|
||||
- A cross-player confidence or likelihood matrix.
|
||||
- Inferring browser access failures from status zero, `TypeError`, or error
|
||||
message text.
|
||||
- Changing hls.js retry, level-switch, or recovery behavior.
|
||||
|
||||
## Approaches Considered
|
||||
|
||||
### Boundary sanitizer (selected)
|
||||
|
||||
Convert hls.js `ErrorData` into a small `HlsPlaybackEvidence` value at the
|
||||
adapter boundary. The classifier accepts only that value. This centralizes the
|
||||
allowlist, makes unsafe fields structurally unavailable to classification and
|
||||
UI code, and gives HTML5 and ArtPlayer identical behavior.
|
||||
|
||||
### Pass `ErrorData` directly
|
||||
|
||||
This would preserve the strongest TypeScript relationship with hls.js, but it
|
||||
would leave every consumer able to read or render URLs, loader state, headers,
|
||||
response payloads, and arbitrary errors. It also makes privacy depend on each
|
||||
future call site remembering the same exclusions.
|
||||
|
||||
### Keep the broad input and tighten string tests
|
||||
|
||||
Exact comparisons could improve classification, but the adapters would still
|
||||
copy arbitrary messages and objects into diagnostics. This would not establish
|
||||
the requested safe evidence contract.
|
||||
|
||||
## Evidence Contract
|
||||
|
||||
`HlsPlaybackEvidence` contains:
|
||||
|
||||
- `engineType`: one of the installed hls.js `ErrorTypes` values, otherwise
|
||||
`unknown`;
|
||||
- `engineDetails`: one of the installed hls.js `ErrorDetails` values,
|
||||
including its existing `unknown` value;
|
||||
- `disposition`: `fatal` when `ErrorData.fatal === true`, otherwise
|
||||
`recoverable`;
|
||||
- `stage`: `manifest`, `level`, `segment`, `key`, `media`, or `unknown`;
|
||||
- `failure`: `http`, `timeout`, `network`, `access`, or `unknown`;
|
||||
- optional `httpStatus`: an integer from 100 through 599 copied only from
|
||||
`ErrorData.response.code`.
|
||||
|
||||
The `access` value is part of the contract but hls.js 1.6.16 does not expose a
|
||||
reliable structured CORS, mixed-content, CSP, or private-network-access code.
|
||||
Status zero and generic fetch failures can also mean DNS, offline, connection,
|
||||
or abort failures. The extractor therefore does not emit `access` for current
|
||||
runtime shapes; it uses `network` or `unknown` and never inspects message text.
|
||||
|
||||
The extractor does not copy:
|
||||
|
||||
- `ErrorData.url`;
|
||||
- `context`, including request URLs and headers;
|
||||
- `networkDetails` or loader instances;
|
||||
- `response.url`, `response.text`, or `response.data`;
|
||||
- `error`, deprecated `err`, `reason`, events, fragments, or arbitrary values.
|
||||
|
||||
The existing playback metadata still carries the active source URL for the
|
||||
pre-existing Retry, Copy URL, and explicit external-player workflows. No HLS
|
||||
error URL is copied into evidence or shown in technical details.
|
||||
|
||||
## Stage Mapping
|
||||
|
||||
Stages are derived only from exact `ErrorDetails` values:
|
||||
|
||||
- `manifest`: manifest load, timeout, parsing, and incompatible-codec details;
|
||||
- `level`: level load, timeout, parsing, empty, and switch details, plus
|
||||
audio/subtitle track playlist load details;
|
||||
- `segment`: fragment load, timeout, parsing, decrypt, and gap details;
|
||||
- `key`: key load/timeout and key-system details;
|
||||
- `media`: buffer, mux/remux, attach-media, and playback-stall details;
|
||||
- `unknown`: internal, aborted, interstitial, unrecognized, or otherwise
|
||||
unmapped details.
|
||||
|
||||
This mapping describes the engine stage, not root-cause likelihood. For
|
||||
example, a segment-stage timeout is still classified as a network timeout.
|
||||
|
||||
## Failure Mapping
|
||||
|
||||
Failure kind uses this precedence:
|
||||
|
||||
1. Exact timeout details produce `timeout`.
|
||||
2. A validated 4xx or 5xx `response.code` produces `http`.
|
||||
3. Exact network load-error details, or the exact `networkError` engine type,
|
||||
produce `network`.
|
||||
4. No current hls.js 1.6.16 field independently proves `access`.
|
||||
5. Everything else is `unknown`.
|
||||
|
||||
A 1xx, 2xx, or 3xx status remains retained as factual response metadata but
|
||||
does not by itself produce an HTTP-failure kind.
|
||||
|
||||
## Classification
|
||||
|
||||
`classifyHlsPlaybackIssue` returns `PlaybackDiagnostic | null`:
|
||||
|
||||
1. `recoverable` returns `null` before classification.
|
||||
2. Exact incompatible/add-codec details produce `unsupported-codec`.
|
||||
3. Exact key-system or fragment-decrypt evidence produces
|
||||
`drm-or-encryption`.
|
||||
4. Exact network type, load/timeout details, or HTTP failure evidence produces
|
||||
`network-error`.
|
||||
5. Exact media or mux type produces `media-decode-error`.
|
||||
6. Everything else produces `unknown-playback-error`.
|
||||
|
||||
The HLS path does not emit `browser-access-error` without structured access
|
||||
evidence. It also does not classify `keyLoadError` as DRM: failure to fetch an
|
||||
encryption key is network evidence, while `fragDecryptError` and key-system
|
||||
details are encryption/DRM evidence.
|
||||
|
||||
The normalized `PlaybackDiagnostic` retains the sanitized HLS evidence and
|
||||
copies its validated HTTP status into the existing top-level `httpStatus`
|
||||
field. External fallback recommendations continue to derive from the final
|
||||
diagnostic code.
|
||||
|
||||
## Adapter Flow
|
||||
|
||||
HTML5 and ArtPlayer both use:
|
||||
|
||||
1. `createHlsPlaybackEvidence(data)`;
|
||||
2. `classifyHlsPlaybackIssue(evidence, sourceMetadata)`;
|
||||
3. emit only when the classifier returns a diagnostic.
|
||||
|
||||
The fatal gate therefore lives in the shared classifier rather than being
|
||||
duplicated in the two adapters. hls.js registers its final error-controller
|
||||
listener during construction, before IPTVnator subscribes, so the application
|
||||
observes the final `fatal` value after retry/alternate handling has had a
|
||||
chance to update it.
|
||||
|
||||
## User Interface
|
||||
|
||||
The existing technical “Error details” row renders a deterministic, safe HLS
|
||||
summary made only from the evidence fields, for example:
|
||||
|
||||
`stage=manifest · failure=http · type=networkError · details=manifestLoadError · disposition=fatal · HTTP 404`
|
||||
|
||||
No HLS error message, URL, header, body, response text, or arbitrary provider
|
||||
payload appears. Existing title/description and HTTP metadata rendering remain
|
||||
unchanged, so no new translation keys or layout changes are required.
|
||||
|
||||
## Testing
|
||||
|
||||
Use test-driven development:
|
||||
|
||||
- Add extractor tests using hls.js 1.6.16-shaped manifest, level, segment, key,
|
||||
media, HTTP, timeout, and unknown payloads.
|
||||
- Prove unrecognized runtime values become `unknown`.
|
||||
- Prove response URLs/text/data, request context/headers, error messages,
|
||||
network details, and credential-shaped payloads do not appear in evidence or
|
||||
rendered details.
|
||||
- Add classifier tests for exact codec, DRM, network, media, and unknown
|
||||
values.
|
||||
- Prove misleading strings cannot override structured engine values.
|
||||
- Prove recoverable events return `null`.
|
||||
- Update HTML5 and ArtPlayer integration tests to cover fatal HTTP evidence and
|
||||
recoverable suppression through the shared path.
|
||||
- Add a focused view test for the deterministic safe HLS summary.
|
||||
|
||||
Run the complete `ui-playback` unit target, its lint target, the web typecheck,
|
||||
i18n drift validation, and release-note validation. No E2E is required because
|
||||
the player workflow and diagnostic controls are unchanged; adapter, classifier,
|
||||
and rendered-detail behavior are covered at their closest unit/component
|
||||
boundaries.
|
||||
|
||||
## Documentation And Release Note
|
||||
|
||||
Update `docs/architecture/embedded-inline-playback.md`, the canonical playback
|
||||
diagnostic description, to replace raw HLS details with the structured
|
||||
contract. Add a `fix(playback)` release note because users receive more accurate
|
||||
HLS diagnoses and safer technical details.
|
||||
Reference in new issue
Block a user