diff --git a/docs/architecture/embedded-inline-playback.md b/docs/architecture/embedded-inline-playback.md index 868a8776a..a2e376864 100644 --- a/docs/architecture/embedded-inline-playback.md +++ b/docs/architecture/embedded-inline-playback.md @@ -159,6 +159,8 @@ Supported diagnostic codes are: `network-error` is reserved for provider/network loading failures. Browser security failures such as CORS, mixed content, Content Security Policy, and private-network-access blocks are classified as `browser-access-error` so the UI can explain that the browser player was blocked before playback reached decoding. +mpegts.js `Early-EOF` failures on MPEG-TS streams are classified as `media-decode-error` instead of generic `network-error`. These failures usually mean the fetch stream ended before mpegts.js expected a complete transport stream, and external players may still handle the same URL more tolerant of short reads or malformed TS boundaries. + The banner keeps the primary message compact, then exposes technical details on demand: diagnostic code, reporting player/source, detected container/MIME, video/audio codecs, native browser error fields, and raw HLS/mpegts details. HLS manifest codec metadata also drives a concise browser-support hint for codecs that Chromium/Electron commonly cannot decode inline, such as HEVC, AC-3, E-AC-3, DTS, and MPEG-2 video. URL extension metadata is filtered before diagnostics and player selection use it. Web script extensions such as `.php` are not shown as stream containers; explicit media query metadata such as `extension=ts` or `format=m3u8` is preferred when present. diff --git a/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.spec.ts b/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.spec.ts index 6284b65f9..0dbf6413f 100644 --- a/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.spec.ts +++ b/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.spec.ts @@ -244,6 +244,25 @@ describe('playback diagnostics', () => { expect(issue.externalFallbackRecommended).toBe(true); }); + it('classifies mpegts early EOF failures as fallback-actionable media errors', () => { + const issue = classifyMpegTsPlaybackIssue( + { + type: 'NetworkError', + details: 'UnrecoverableEarlyEof', + info: { msg: 'Fetch stream meet Early-EOF' }, + }, + createPlaybackSourceMetadata({ + url: 'https://provider.example/movie/123.ts', + mimeType: 'video/mp2t', + player: 'videojs', + }) + ); + + expect(issue.code).toBe(PlaybackDiagnosticCode.MediaDecodeError); + expect(issue.externalFallbackRecommended).toBe(true); + expect(issue.details).toContain('Early-EOF'); + }); + it('classifies mpegts codec errors as unsupported codec fallbacks', () => { const issue = classifyMpegTsPlaybackIssue( { diff --git a/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.ts b/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.ts index a36024acb..8cf24499c 100644 --- a/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.ts +++ b/libs/ui/playback/src/lib/playback-diagnostics/playback-diagnostics.util.ts @@ -13,6 +13,7 @@ import { isBrowserAccessFailure, isCodecFailure, isDrmOrEncryptionFailure, + isEarlyEofFailure, isNetworkFailure, normalizeErrorDetails, } from './playback-error-patterns.util'; @@ -152,6 +153,15 @@ export function classifyMpegTsPlaybackIssue( const lowerDetails = details.toLowerCase(); const lowerType = (error.type ?? '').toLowerCase(); + if (isEarlyEofFailure(lowerDetails)) { + return createDiagnostic({ + code: DiagnosticCode.MediaDecodeError, + source: DiagnosticSource.MpegTs, + metadata, + details, + }); + } + if (isNetworkFailure(lowerType, lowerDetails)) { return createDiagnostic({ code: isBrowserAccessFailure(lowerDetails) diff --git a/libs/ui/playback/src/lib/playback-diagnostics/playback-error-patterns.util.ts b/libs/ui/playback/src/lib/playback-diagnostics/playback-error-patterns.util.ts index 9044469b0..22f3b9724 100644 --- a/libs/ui/playback/src/lib/playback-diagnostics/playback-error-patterns.util.ts +++ b/libs/ui/playback/src/lib/playback-diagnostics/playback-error-patterns.util.ts @@ -45,6 +45,11 @@ export function isBrowserAccessFailure(details: string): boolean { ); } +export function isEarlyEofFailure(details: string): boolean { + const compactDetails = details.replace(/[^a-z0-9]/g, ''); + return compactDetails.includes('earlyeof'); +} + export function isCodecFailure(details: string): boolean { return ( details.includes('codec') ||