From 561daf588c832a0c7cded314a37d0723709a0da0 Mon Sep 17 00:00:00 2001 From: Charlie Fish Date: Fri, 21 Aug 2026 18:16:39 -0600 Subject: [PATCH] Restore stable stream for automatic quality --- apps/frontend/app/_player/Player.tsx | 9 +++++---- apps/frontend/tests/player/Player.test.tsx | 12 ++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/frontend/app/_player/Player.tsx b/apps/frontend/app/_player/Player.tsx index b302061..95de54a 100644 --- a/apps/frontend/app/_player/Player.tsx +++ b/apps/frontend/app/_player/Player.tsx @@ -317,8 +317,8 @@ interface AirPlayAvailabilityEvent extends Event { /** * Build the master playlist URL for a channel; respects the optional - * `quality` pin by appending `?profile=`. `auto` requests the - * multivariant graph so hls.js can change renditions before buffer exhaustion. + * `quality` pin by appending `?profile=`. `auto` retains the proven + * single-stream browser conversion; explicit quality choices remain available. */ function buildSrc( channelId: string, @@ -326,7 +326,7 @@ function buildSrc( viewerId?: string ): string { const base = `/api/v1/stream/${encodeURIComponent(channelId)}/master.m3u8`; - const profile = !quality || quality === "auto" ? "auto" : quality; + const profile = !quality || quality === "auto" ? "original-quality" : quality; const search = new URLSearchParams({ profile }); if (viewerId) { search.set("viewerId", viewerId); @@ -378,7 +378,8 @@ function buildViewerReleaseUrl( quality: PlayerQuality, viewerId: string ): string { - const query = new URLSearchParams({ profile: quality }); + const profile = quality === "auto" ? "original-quality" : quality; + const query = new URLSearchParams({ profile }); return `/api/v1/stream/${encodeURIComponent(channelId)}/viewers/${encodeURIComponent(viewerId)}/release?${query.toString()}`; } diff --git a/apps/frontend/tests/player/Player.test.tsx b/apps/frontend/tests/player/Player.test.tsx index ad192e1..1c5f8bb 100644 --- a/apps/frontend/tests/player/Player.test.tsx +++ b/apps/frontend/tests/player/Player.test.tsx @@ -148,7 +148,7 @@ describe("Player", () => { ([source]) => source as string ); expect(sources).toHaveLength(1); - expectLiveSource(sources[0]!, CHANNEL_ID, "auto"); + expectLiveSource(sources[0]!, CHANNEL_ID, "original-quality"); expect( new URL(sources[0]!, "http://localhost").searchParams.get("viewerId") ).toBe(clientViewerId); @@ -169,11 +169,11 @@ describe("Player", () => { const instance = fakeInstances[0]!; expect(instance.attachMedia).toHaveBeenCalled(); const source = instance.loadSource.mock.calls[0]?.[0] as string; - const viewerId = expectLiveSource(source, CHANNEL_ID, "auto"); + const viewerId = expectLiveSource(source, CHANNEL_ID, "original-quality"); unmount(); expect(sendBeacon).toHaveBeenCalledWith( - `/api/v1/stream/${CHANNEL_ID}/viewers/${viewerId}/release?profile=auto` + `/api/v1/stream/${CHANNEL_ID}/viewers/${viewerId}/release?profile=original-quality` ); }); @@ -205,7 +205,7 @@ describe("Player", () => { expectLiveSource( fakeInstances[0]?.loadSource.mock.calls[0]?.[0] as string, CHANNEL_ID, - "auto" + "original-quality" ); expect(screen.queryByTestId("player-error")).not.toBeInTheDocument(); }); @@ -222,7 +222,7 @@ describe("Player", () => { await waitFor(() => expect(FakeHls.isSupported).toHaveBeenCalled()); expect(fakeInstances).toHaveLength(0); - expectLiveSource(video.src, CHANNEL_ID, "auto"); + expectLiveSource(video.src, CHANNEL_ID, "original-quality"); }); it("explains when neither HLS playback engine is supported", async () => { @@ -554,7 +554,7 @@ describe("Player", () => { instance.loadSource.mock.calls.length - 1 ]?.[0] as string, "00000000-0000-4000-8000-000000000002", - "auto" + "original-quality" ); });