mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 01:56:16 -08:00
docs(playback): design structured mpegts diagnostics
This commit is contained in:
1 parent
9bb1811984
commit
ae4718d88b
1 file changed
+301
@@ -0,0 +1,301 @@
|
||||
# Structured mpegts.js Diagnostics
|
||||
|
||||
## Context
|
||||
|
||||
PR #1314 stopped treating ambiguous native media errors as codec evidence and
|
||||
retained explicit HTTP status. PR #1316 added an allowlisted hls.js boundary,
|
||||
PR #1317 added one for Video.js/VHS, and PR #1318 added one for Shaka Player.
|
||||
mpegts.js is now the remaining browser source engine whose diagnostic path
|
||||
serializes arbitrary error payloads and classifies them with substring
|
||||
heuristics.
|
||||
|
||||
The locked workspace installs mpegts.js `1.8.0`. Its public player error event
|
||||
has three arguments: error type, error detail, and an information value. The
|
||||
runtime exports exact `ErrorTypes` and `ErrorDetails` constants. The current
|
||||
IPTVnator classifier instead lowercases the arguments, serializes arbitrary
|
||||
`info`, and searches the resulting text for network, access, codec, format,
|
||||
MSE, and early-EOF fragments. This can misdiagnose failures, retain provider
|
||||
text, and miss reliable facts such as the HTTP status carried by
|
||||
`HttpStatusCodeInvalid`.
|
||||
|
||||
All three built-in web players own a mpegts.js integration:
|
||||
|
||||
- `HtmlVideoPlayerComponent` for the built-in HTML5 player;
|
||||
- `VjsMpegTsSession` for Video.js;
|
||||
- `ArtPlayerSourceSession` for ArtPlayer.
|
||||
|
||||
They must cross the same evidence boundary so the selected player does not
|
||||
change the diagnosis for an identical engine event.
|
||||
|
||||
## Goals
|
||||
|
||||
- Add one minimal, allowlisted `MpegTsPlaybackEvidence` boundary shared by all
|
||||
three mpegts.js owners.
|
||||
- Version-lock the accepted public constants to installed mpegts.js `1.8.0`.
|
||||
- Classify only exact, internally consistent public type/detail pairs.
|
||||
- Surface a validated HTTP 4xx/5xx status for
|
||||
`NetworkError + HttpStatusCodeInvalid`.
|
||||
- Preserve the existing useful distinction for unrecoverable early EOF while
|
||||
replacing text inference with the exact public detail.
|
||||
- Prevent arbitrary `info`, messages, URLs, headers, bodies, credentials, and
|
||||
provider objects from reaching stored or rendered diagnostics.
|
||||
- Shape the evidence so a later player-neutral recommendation layer can use it
|
||||
without coupling diagnostics to `PlayerController`.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Building the cross-player recommendation matrix.
|
||||
- Moving recommendations, diagnostics, or fallback policy into
|
||||
`PlayerController`.
|
||||
- Automatic failover, player preference changes, retries beyond those already
|
||||
owned by mpegts.js, probes, persistence, correlation, or diagnostic history.
|
||||
- Adding new top-level diagnostic codes or changing diagnostic layout and
|
||||
translations.
|
||||
- Inferring CORS, mixed content, Content Security Policy, private-network
|
||||
access, codec, format, or pipeline stage from message text.
|
||||
- Inspecting mpegts.js loaders, demuxers, workers, or MediaSource internals at
|
||||
runtime.
|
||||
- Changing source selection, live/VOD mode, playback controls, duration
|
||||
correction, or engine cleanup.
|
||||
|
||||
## Approaches Considered
|
||||
|
||||
### Public allowlisted evidence boundary (selected)
|
||||
|
||||
Normalize the public error-event arguments immediately into a small evidence
|
||||
object. Accept only exact mpegts.js `1.8.0` type/detail constants, derive stage
|
||||
and failure from consistent pairs, and read only a validated numeric status
|
||||
from the documented network error-info slot. Classification and rendering then
|
||||
receive the sanitized evidence rather than the raw event.
|
||||
|
||||
This is the strongest stable contract available. It fixes HTTP diagnostics,
|
||||
removes unsafe serialization, keeps all three players consistent, and gives a
|
||||
future recommendation layer explicit facts instead of prose.
|
||||
|
||||
### Exact constants plus message heuristics
|
||||
|
||||
Keep the public constants but continue reading `info.msg` to infer browser
|
||||
access or more specific causes. This could preserve a few synthetic CORS cases,
|
||||
but browser fetch exceptions commonly expose only generic text such as
|
||||
`Failed to fetch`. Message text is not a stable public taxonomy and may contain
|
||||
provider data. This approach is rejected.
|
||||
|
||||
### Add HTTP status to the existing classifier
|
||||
|
||||
Special-case `HttpStatusCodeInvalid` while leaving the rest of the substring
|
||||
classifier unchanged. This would address issue #1159 narrowly but retain the
|
||||
privacy and accuracy problems for every other mpegts.js failure. It would also
|
||||
leave no coherent evidence contract for later recommendations. This approach
|
||||
is rejected.
|
||||
|
||||
## Version-Locked Public Contract
|
||||
|
||||
The production allowlist accepts the exact public constants exported by
|
||||
mpegts.js `1.8.0`.
|
||||
|
||||
Error types:
|
||||
|
||||
- `NetworkError`;
|
||||
- `MediaError`;
|
||||
- `OtherError`.
|
||||
|
||||
Error details:
|
||||
|
||||
- `Exception`;
|
||||
- `HttpStatusCodeInvalid`;
|
||||
- `ConnectingTimeout`;
|
||||
- `UnrecoverableEarlyEof`;
|
||||
- `MediaMSEError`;
|
||||
- `FormatError`;
|
||||
- `FormatUnsupported`;
|
||||
- `CodecUnsupported`.
|
||||
|
||||
The package also exports loader-only `EarlyEof`, but it is not a public player
|
||||
`ErrorDetails` value. mpegts.js attempts its finite-source reconnect internally
|
||||
and exposes only `UnrecoverableEarlyEof` through the player error event when
|
||||
recovery cannot complete. IPTVnator must not create a terminal diagnostic for
|
||||
the internal recoverable value.
|
||||
|
||||
A contract test compares the allowlist and package version with the real
|
||||
installed runtime. A dependency upgrade must fail that test and trigger a new
|
||||
audit before changed or additional constants are accepted.
|
||||
|
||||
## Evidence Contract
|
||||
|
||||
`MpegTsPlaybackEvidence` contains:
|
||||
|
||||
- `engineType`: exact `NetworkError`, `MediaError`, or `OtherError`, otherwise
|
||||
`unknown`;
|
||||
- `engineDetails`: one exact public mpegts.js detail, otherwise `unknown`;
|
||||
- `disposition`: `terminal`;
|
||||
- `stage`: `loader`, `demux`, `media-source`, or `unknown`;
|
||||
- `failure`: `http`, `timeout`, `network`, `truncated-stream`, `format`,
|
||||
`codec`, `media-source`, or `unknown`;
|
||||
- optional `httpStatus`: an integer from 400 through 599.
|
||||
|
||||
Stage and failure names are app-owned and stable. Exact engine type and detail
|
||||
remain available separately so technical output still identifies the public
|
||||
mpegts.js condition.
|
||||
|
||||
The evidence object does not retain:
|
||||
|
||||
- `info.msg` or any other message;
|
||||
- arbitrary or serialized `info` values;
|
||||
- request, response, redirect, or source URLs;
|
||||
- headers, response text, bodies, events, exceptions, or loader objects;
|
||||
- provider metadata, tokens, cookies, credentials, or unknown properties.
|
||||
|
||||
The existing `PlaybackDiagnostic.sourceUrl` remains the active source metadata
|
||||
used by Retry, Copy URL, and explicit external-player actions. No URL is copied
|
||||
from an engine error.
|
||||
|
||||
## Sanitization And HTTP Status
|
||||
|
||||
`createMpegTsPlaybackEvidence(type, details, info)` validates exact,
|
||||
case-sensitive public values. Unknown strings, differently cased variants,
|
||||
numbers, objects, and missing values become `unknown`; message fragments never
|
||||
upgrade them.
|
||||
|
||||
The boundary reads `info.code` only for the exact
|
||||
`NetworkError + HttpStatusCodeInvalid` pair. It retains the value only when it
|
||||
is an integer from 400 through 599. Status-like fields on any other pair,
|
||||
inside nested objects, or supplied as strings are ignored. No other `info`
|
||||
property is read or copied.
|
||||
|
||||
The validated status is mirrored to the top-level diagnostic so the existing
|
||||
metadata badge shows `HTTP 404` or `HTTP 5xx` without a UI redesign.
|
||||
|
||||
## Stage And Failure Mapping
|
||||
|
||||
Only internally consistent public type/detail pairs receive a stage or failure:
|
||||
|
||||
| Public type | Public detail | Stage | Failure |
|
||||
| --- | --- | --- | --- |
|
||||
| `NetworkError` | `HttpStatusCodeInvalid` | `loader` | `http` |
|
||||
| `NetworkError` | `ConnectingTimeout` | `loader` | `timeout` |
|
||||
| `NetworkError` | `Exception` | `loader` | `network` |
|
||||
| `NetworkError` | `UnrecoverableEarlyEof` | `loader` | `truncated-stream` |
|
||||
| `MediaError` | `FormatError` | `demux` | `format` |
|
||||
| `MediaError` | `FormatUnsupported` | `demux` | `format` |
|
||||
| `MediaError` | `CodecUnsupported` | `demux` | `codec` |
|
||||
| `MediaError` | `MediaMSEError` | `media-source` | `media-source` |
|
||||
|
||||
`OtherError`, unknown values, and mismatched pairs keep both fields unknown.
|
||||
For example, `OtherError + CodecUnsupported` must not become codec evidence.
|
||||
This fail-closed rule prevents a future engine change or malformed event from
|
||||
borrowing meaning from only half of the public contract.
|
||||
|
||||
## Lifecycle And Disposition
|
||||
|
||||
The public player `ERROR` event is terminal for IPTVnator's diagnostic
|
||||
boundary. The installed engine handles recoverable finite-source early EOF
|
||||
inside `IOController`; only failed recovery becomes
|
||||
`UnrecoverableEarlyEof` and reaches the player event. Network, demux, and MSE
|
||||
error paths likewise reach the player event after the active engine operation
|
||||
has failed.
|
||||
|
||||
IPTVnator does not subscribe to internal recovery events or duplicate engine
|
||||
retry logic. All accepted evidence therefore records `disposition=terminal`.
|
||||
|
||||
## User-Facing Classification
|
||||
|
||||
`classifyMpegTsPlaybackIssue` consumes sanitized evidence with this mapping:
|
||||
|
||||
1. `failure=http`, `timeout`, or `network` → `network-error`.
|
||||
2. `failure=truncated-stream` → `media-decode-error`.
|
||||
3. Exact `MediaError + FormatUnsupported` → `unsupported-container`.
|
||||
4. Exact `MediaError + CodecUnsupported` → `unsupported-codec`.
|
||||
5. `failure=format` or `media-source` → `media-decode-error`.
|
||||
6. Everything else → `unknown-playback-error`.
|
||||
|
||||
The existing code-derived fallback behavior remains intentional:
|
||||
|
||||
- HTTP, timeout, generic network, and unknown failures do not claim that a
|
||||
different decoder will fix the provider response;
|
||||
- truncated-stream, unsupported-container, unsupported-codec, format, and
|
||||
MediaSource failures may offer configured MPV/VLC actions because another
|
||||
demuxer or media pipeline can plausibly handle the same source.
|
||||
|
||||
No mpegts.js error becomes `browser-access-error`. The public constants do not
|
||||
distinguish CORS, mixed content, CSP, or private-network access from a generic
|
||||
fetch exception, and status zero is not sufficient evidence.
|
||||
|
||||
## Runtime Integration
|
||||
|
||||
The raw event must cross the boundary once in each owner:
|
||||
|
||||
- `emitMpegTsPlaybackError` creates evidence for
|
||||
`HtmlVideoPlayerComponent`;
|
||||
- `VjsMpegTsSession` creates evidence before emitting its issue;
|
||||
- `ArtPlayerSourceSession` creates evidence before emitting its issue.
|
||||
|
||||
All three call the same classifier with source metadata that preserves their
|
||||
existing `InlinePlaybackPlayer` identity. No owner keeps or forwards the raw
|
||||
event after normalization. Listener binding, stale-engine guards, live/VOD
|
||||
mode, duration correction, source routing, play calls, and teardown remain
|
||||
unchanged.
|
||||
|
||||
## Relationship To Shared Controls And Recommendations
|
||||
|
||||
`PlayerController` remains the engine-neutral command/state/capability
|
||||
contract. It does not own error taxonomy, fallback policy, or provider
|
||||
evidence.
|
||||
|
||||
Playback diagnostics are a sibling player-neutral layer: engine adapters emit
|
||||
sanitized evidence, the diagnostic classifier maps it to a user-facing issue,
|
||||
and the existing viewport renders that issue. A later recommendation layer can
|
||||
consume diagnostic code, source, engine evidence, source metadata, and runtime
|
||||
capabilities to explain whether another player is likely to help. That later
|
||||
work must not require parsing the technical-details string or changing the
|
||||
controls contract.
|
||||
|
||||
## User Interface
|
||||
|
||||
The existing technical `Error details` row renders only structured mpegts.js
|
||||
evidence, for example:
|
||||
|
||||
`stage=loader · failure=http · type=NetworkError · details=HttpStatusCodeInvalid · disposition=terminal · HTTP 404`
|
||||
|
||||
When `issue.mpegTs` exists, legacy raw `details` and native message fields are
|
||||
ignored even if a caller accidentally supplies them. Existing titles,
|
||||
descriptions, HTTP badge, Retry, Copy URL, external-player actions, layout, and
|
||||
translations remain unchanged.
|
||||
|
||||
## Testing
|
||||
|
||||
Use test-driven development:
|
||||
|
||||
- Compare the accepted constants and version with the real installed
|
||||
mpegts.js `1.8.0` runtime.
|
||||
- Cover every consistent public type/detail mapping.
|
||||
- Prove mismatched, unknown, differently cased, and malformed inputs remain
|
||||
unknown.
|
||||
- Prove only exact `HttpStatusCodeInvalid` can expose a validated HTTP 4xx/5xx
|
||||
status.
|
||||
- Prove `info.msg`, nested status, URLs, headers, bodies, exceptions, and
|
||||
arbitrary provider objects never enter evidence or rendered details.
|
||||
- Cover HTTP 404, timeout, exception, unrecoverable early EOF, format error,
|
||||
unsupported format, unsupported codec, MSE error, other, and unknown
|
||||
classification.
|
||||
- Cover evidence creation and issue emission through HTML5, Video.js, and
|
||||
ArtPlayer integrations.
|
||||
- Prove the rendered detail row uses only structured mpegts.js evidence and
|
||||
preserves the HTTP metadata badge.
|
||||
|
||||
Run the focused red/green tests, complete `ui-playback` unit and lint targets,
|
||||
web typecheck, i18n validation, release-note validation, and the repository
|
||||
test-impact pass. No new E2E case is required because source selection,
|
||||
playback lifecycle, controls, actions, and diagnostic layout remain unchanged;
|
||||
the engine event, three adapter boundaries, classifier, and rendered output are
|
||||
covered directly and deterministically.
|
||||
|
||||
## Documentation And Release Note
|
||||
|
||||
Update `docs/architecture/embedded-inline-playback.md` as the canonical
|
||||
browser diagnostic contract. Update the mpegts.js diagnostic summaries in
|
||||
`AGENTS.md` and `CLAUDE.md` because they describe the affected player engines
|
||||
and evidence boundaries. No `player-controls-contract.md` change is needed
|
||||
because the controls contract does not change.
|
||||
|
||||
Add a `fix(playback)` note under `.changes/` because users receive accurate HTTP
|
||||
status, safer technical details, and more precise mpegts.js diagnoses.
|
||||
Reference in new issue
Block a user