From 004f2ea7a5b46be8808db00cb2fb32100e5b1bba Mon Sep 17 00:00:00 2001 From: Stackie Jia Date: Thu, 25 Jun 2026 20:14:16 +0800 Subject: [PATCH] fix(web-ui): strip host from M3U URLs in web player Treat absolute playlist URLs as site-root-relative paths so playback and EPG requests follow the browser's current origin, matching use-relative-path-in-m3u server output. --- web-ui/src/lib/m3u-parser.ts | 24 ++++++++++++++++++++---- web-ui/src/lib/url.ts | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/web-ui/src/lib/m3u-parser.ts b/web-ui/src/lib/m3u-parser.ts index 3ee77a45..af6fa596 100644 --- a/web-ui/src/lib/m3u-parser.ts +++ b/web-ui/src/lib/m3u-parser.ts @@ -1,5 +1,6 @@ import type { PlayerSegment } from "../mpegts"; import type { Channel, M3UMetadata, Source } from "../types/player"; +import { toPlaylistRelativePath } from "./url"; /** * Parse M3U playlist content @@ -34,7 +35,7 @@ export function parseM3U(content: string): M3UMetadata { if (line.startsWith("#EXTM3U")) { const tvgUrlMatch = line.match(/x-tvg-url="([^"]+)"/); if (tvgUrlMatch) { - tvgUrl = tvgUrlMatch[1]; + tvgUrl = toPlaylistRelativePath(tvgUrlMatch[1]); } const catchupMatch = line.match(/catchup="([^"]+)"/); if (catchupMatch) { @@ -42,7 +43,7 @@ export function parseM3U(content: string): M3UMetadata { } const catchupSourceMatch = line.match(/catchup-source="([^"]+)"/); if (catchupSourceMatch) { - defaultCatchupSource = catchupSourceMatch[1]; + defaultCatchupSource = toPlaylistRelativePath(catchupSourceMatch[1]); } continue; } @@ -77,7 +78,7 @@ export function parseM3U(content: string): M3UMetadata { tvgId: tvgIdMatch?.[1], tvgName: tvgNameMatch?.[1], catchup: catchupMatch?.[1] || defaultCatchup, - catchupSource: catchupSourceMatch?.[1] || defaultCatchupSource, + catchupSource: resolveCatchupSource(catchupSourceMatch?.[1] || defaultCatchupSource), }; continue; } @@ -87,6 +88,9 @@ export function parseM3U(content: string): M3UMetadata { // Extract optional $