Skip to content

Resolve HLS segment and key urls against the playlist url - #3174

Open
Dev-next-gen wants to merge 1 commit into
recloudstream:masterfrom
Dev-next-gen:fix-hls-relative-segment-urls
Open

Dev-next-gen wants to merge 1 commit into
recloudstream:masterfrom
Dev-next-gen:fix-hls-relative-segment-urls

Conversation

@Dev-next-gen

Copy link
Copy Markdown

While reading M3u8Helper2.hslLazy I noticed that segment and key URIs from a media playlist are joined to the playlist's parent directory as plain strings, while the variant URLs in the same flow are resolved by HlsPlaylistParser.UrlUtil.resolveToUrl (RFC 3986). Only plain relative entries survive that join.

With a playlist at https://host/a/b/index.m3u8:

  • a root-relative entry /seg/1.ts became https://host/a/b//seg/1.ts
  • a scheme-relative entry //cdn/seg.ts became https://host/a/b///cdn/seg.ts
  • #EXT-X-KEY:METHOD=AES-128,URI="/keys/k.bin" was fetched from https://host/a/b//keys/k.bin

Those URLs don't exist on the server, so downloads and preview generation of such streams fail. This change resolves non-absolute entries with the same UrlUtil.resolveToUrl the parser already uses. Plain relative entries like seg0.ts resolve to the same URL as before, and absolute http(s):// entries are left as they are. The segment value also carried the trailing newline captured by TS_EXTENSION_REGEX, which I trim before resolving. LazyHlsDownloadData.relativeUrl is unchanged.

To test it I added library/src/jvmTest/.../M3u8HelperTest.kt. It serves playlists from a local com.sun.net.httpserver, checks the resolved segment URLs, downloads every segment through resolveLink, and checks that the key is requested at /keys/k.bin. On master both tests fail:

expected:<[http://127.0.0.1:41035/a/b/seg0.ts, http://127.0.0.1:41035/root/seg1.ts, http://127.0.0.1:41035/proto/seg2.ts]>
but was:<[http://127.0.0.1:41035/a/b/seg0.ts\n, http://127.0.0.1:41035/a/b//root/seg1.ts\n, http://127.0.0.1:41035/a/b///127.0.0.1:41035/proto/seg2.ts\n]>

requested: [/a/b/encrypted.m3u8, /a/b//keys/k.bin]

With the change, ./gradlew library:jvmTest passes (543 tests) on JDK 17 and 21, and ./gradlew library:checkKotlinAbi passes on JDK 17 like in CI. I haven't tried it in the app against a real stream, only through these tests.

AI tools used

hslLazy built segment and key urls by appending the entry to the parent directory of the playlist, so root-relative entries (/seg.ts) and scheme-relative entries (//host/seg.ts) produced urls such as /a/b//seg.ts that do not exist. Use the RFC 3986 resolution that HlsPlaylistParser already applies to variant urls, and trim the newline captured by TS_EXTENSION_REGEX.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant