mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 13:46:16 -08:00
* docs(playback): design structured HLS diagnostics * docs(playback): plan structured HLS diagnostics * fix(playback): structure HLS diagnostics * docs(playback): document structured HLS evidence * fix(playback): keep HLS startup logs private
213 lines
9.1 KiB
Markdown
213 lines
9.1 KiB
Markdown
# 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. HLS startup development logs are event-only and omit
|
|
provider-supplied channel names and source URLs. 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.
|