From 1fe208756be5b59afd968430a2fae22c7f33df17 Mon Sep 17 00:00:00 2001 From: 4gray Date: Thu, 30 Jul 2026 09:41:48 +0200 Subject: [PATCH] fix(playback): show explicit HTTP playback errors --- .../web-player-view-diagnostics.utils.ts | 16 ++++++- .../web-player-view.component.spec.ts | 46 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/libs/ui/playback/src/lib/web-player-view/web-player-view-diagnostics.utils.ts b/libs/ui/playback/src/lib/web-player-view/web-player-view-diagnostics.utils.ts index d852115a0..60d5b8800 100644 --- a/libs/ui/playback/src/lib/web-player-view/web-player-view-diagnostics.utils.ts +++ b/libs/ui/playback/src/lib/web-player-view/web-player-view-diagnostics.utils.ts @@ -28,6 +28,10 @@ export function getDiagnosticDescriptionKey( } export function getDiagnosticMeta(issue: PlaybackDiagnostic): string { + if (issue.httpStatus !== undefined) { + return `HTTP ${issue.httpStatus}`; + } + const codecs = [...issue.videoCodecs, ...issue.audioCodecs].join(', '); if (codecs) { return codecs; @@ -82,11 +86,21 @@ export function getDiagnosticDetails( }, { labelKey: 'PLAYBACK_DIAGNOSTICS.DETAIL_ERROR_DETAILS', - value: issue.details ?? '', + value: formatDiagnosticErrorDetails(issue), }, ].filter(({ value }) => value.trim().length > 0); } +function formatDiagnosticErrorDetails(issue: PlaybackDiagnostic): string { + return [ + issue.httpStatus !== undefined ? `HTTP ${issue.httpStatus}` : '', + issue.nativeErrorType ?? '', + issue.details ?? '', + ] + .filter((value) => value.trim().length > 0) + .join(' · '); +} + function getDiagnosticTranslationBase(issue: PlaybackDiagnostic): string { switch (issue.code) { case PlaybackDiagnosticCode.UnsupportedContainer: diff --git a/libs/ui/playback/src/lib/web-player-view/web-player-view.component.spec.ts b/libs/ui/playback/src/lib/web-player-view/web-player-view.component.spec.ts index d74d113c9..340e2d423 100644 --- a/libs/ui/playback/src/lib/web-player-view/web-player-view.component.spec.ts +++ b/libs/ui/playback/src/lib/web-player-view/web-player-view.component.spec.ts @@ -289,6 +289,34 @@ describe('WebPlayerViewComponent', () => { ]); }); + it('renders explicit HTTP evidence without recommending an external fallback', () => { + runtimeCapabilities.supportsManagedExternalPlayers = true; + const issue = createHttpDiagnostic(); + + fixture.detectChanges(); + component.handlePlaybackIssue(issue); + fixture.detectChanges(); + + const banner = fixture.debugElement.query( + By.css('[data-test-id="playback-diagnostic-banner"]') + ); + const mpvButton = fixture.debugElement.query( + By.css('[data-test-id="playback-fallback-mpv"]') + ); + + expect(banner.nativeElement.textContent).toContain('HTTP 404'); + expect(mpvButton).toBeNull(); + expect(component.getDiagnosticMeta(issue)).toBe('HTTP 404'); + expect(component.getDiagnosticDetails(issue)).toEqual( + expect.arrayContaining([ + { + labelKey: 'PLAYBACK_DIAGNOSTICS.DETAIL_ERROR_DETAILS', + value: 'HTTP 404 · networkrequestfailed', + }, + ]) + ); + }); + it('keeps query-declared HLS streams on the HLS mime type', () => { const streamUrl = 'https://example.com/play?extension=m3u8&token=signed'; @@ -831,3 +859,21 @@ function createNetworkDiagnostic(): PlaybackDiagnostic { externalFallbackRecommended: false, }; } + +function createHttpDiagnostic(): PlaybackDiagnostic { + return { + code: PlaybackDiagnosticCode.NetworkError, + source: PlaybackDiagnosticSource.Native, + sourceUrl: 'https://example.com/live/missing.m3u8', + container: 'm3u8', + mimeType: 'application/x-mpegURL', + player: 'videojs', + audioCodecs: [], + videoCodecs: [], + nativeErrorCode: 4, + nativeErrorMessage: 'source not supported', + httpStatus: 404, + nativeErrorType: 'networkrequestfailed', + externalFallbackRecommended: false, + }; +}