From fcbf607493fb05c93b3491423e81ea6e3a66d683 Mon Sep 17 00:00:00 2001 From: Raffi Date: Mon, 11 May 2026 17:46:47 +0200 Subject: [PATCH 1/4] map headers from master manifest request to master manifest load --- .../AVSubtitlesLoader.swift | 16 +++++++++++----- .../Parsers/MasterPlaylistParser.swift | 7 +++++-- .../Parsers/PlaylistParser.swift | 10 ++++++++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift index a552d0d5..239b11f8 100644 --- a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift +++ b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift @@ -22,6 +22,7 @@ class AVSubtitlesLoader: NSObject { private let synchronizer: SubtitlesSynchronizer? private let _id: String private var variantTotalDuration: Double = 0 + private var masterURLRequest: URLRequest? init(subtitles: [TextTrackDescription], id: String, player: THEOplayer? = nil) { self._subtitles = subtitles @@ -42,8 +43,8 @@ class AVSubtitlesLoader: NSObject { } #endif - func handleMasterManifestRequest(_ url: URL) async -> Data? { - let parser = MasterPlaylistParser(url: url) + func handleMasterManifestRequest(_ url: URL, request: URLRequest?) async -> Data? { + let parser = MasterPlaylistParser(url: url, request: request) guard let responseData = await parser.sideLoadSubtitles(subtitles: subtitles) else { print("[AVSubtitlesLoader] ERROR: Couldn't find manifest data") return nil @@ -163,8 +164,13 @@ enum URLScheme: String { } extension AVSubtitlesLoader: MediaPlaylistInterceptor { - func shouldInterceptPlaylistRequest(type: HlsPlaylistType) -> Bool { false } - func didInterceptPlaylistRequest(type: HlsPlaylistType, request: URLRequest) async throws -> URLRequest { request } + func shouldInterceptPlaylistRequest(type: HlsPlaylistType) -> Bool { true } + func didInterceptPlaylistRequest(type: HlsPlaylistType, request: URLRequest) async throws -> URLRequest { + if type == .master { + masterURLRequest = request + } + return request + } func failedToPerformURLRequest(request: URLRequest, response: URLResponse) { if THEOplayerConnectorSideloadedSubtitle.SHOW_DEBUG_LOGS { @@ -190,7 +196,7 @@ extension AVSubtitlesLoader: MediaPlaylistInterceptor { // intercept the master manifest to append the subtitles subtitles = await validateSubtitles() if subtitles.isEmpty { return data } - return await self.handleMasterManifestRequest(url) ?? data + return await self.handleMasterManifestRequest(url, request: masterURLRequest) ?? data case .video: // intercept the variant manifest to get the duration if subtitles.isEmpty { return data } diff --git a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift index 292fcdb5..af076239 100644 --- a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift +++ b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift @@ -12,13 +12,16 @@ class MasterPlaylistParser: PlaylistParser { var constructedManifestArray = [String]() fileprivate var lastMediaLine: Int? fileprivate let subtitlesGroupId = "THEOsubs" + private let request: URLRequest? - override init(url: URL) { + init(url: URL, request: URLRequest?) { + self.request = request super.init(url: url) } func sideLoadSubtitles(subtitles: [TextTrackDescription]) async -> Data? { - guard let _ = await self.loadManifest() else { return nil } + var headers = request?.allHTTPHeaderFields + guard let _ = await self.loadManifest(headers) else { return nil } self.parseManifest() self.appendSubtitlesLines(subtitles: subtitles) let constructed = self.constructedManifestArray.joined(separator: "\n") diff --git a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift index d50dbf81..4eed04f0 100644 --- a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift +++ b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift @@ -16,8 +16,14 @@ class PlaylistParser { self.manifestData = nil } - func loadManifest() async -> Data? { - if let (data, response) = try? await URLSession.shared.data(from: self.manifestURL) { + func loadManifest(_ headers: [String: String]? = nil) async -> Data? { + var request = URLRequest(url: self.manifestURL) + if let headers { + for header in headers { + request.setValue(header.value, forHTTPHeaderField: header.key) + } + } + if let (data, response) = try? await URLSession.shared.data(for: request) { // Update the manifestUrl to the url received in the response (to pickup possible url redirect) if let responseUrl = response.url { self.manifestURL = responseUrl From 687ce2150cf85a98955c2923c98980fd2e767be5 Mon Sep 17 00:00:00 2001 From: Raffi Date: Tue, 12 May 2026 13:38:44 +0200 Subject: [PATCH 2/4] map all requests --- .../AVSubtitlesLoader.swift | 14 +++++++------- .../Parsers/MasterPlaylistParser.swift | 8 +------- .../Parsers/PlaylistParser.swift | 4 +++- .../Parsers/VariantPlaylistParser.swift | 7 ++++--- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift index 239b11f8..6ae35533 100644 --- a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift +++ b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/AVSubtitlesLoader.swift @@ -22,7 +22,7 @@ class AVSubtitlesLoader: NSObject { private let synchronizer: SubtitlesSynchronizer? private let _id: String private var variantTotalDuration: Double = 0 - private var masterURLRequest: URLRequest? + private var requestMap: [URL: URLRequest] = [:] init(subtitles: [TextTrackDescription], id: String, player: THEOplayer? = nil) { self._subtitles = subtitles @@ -53,8 +53,8 @@ class AVSubtitlesLoader: NSObject { return responseData } - func handleVariantManifest(_ url: URL) async -> Data? { - let parser = VariantPlaylistParser(url: url) + func handleVariantManifest(_ url: URL, request: URLRequest?) async -> Data? { + let parser = VariantPlaylistParser(url: url, request: request) guard let playlist = await parser.parse(), let responseData = playlist.manifestData else { @@ -166,8 +166,8 @@ enum URLScheme: String { extension AVSubtitlesLoader: MediaPlaylistInterceptor { func shouldInterceptPlaylistRequest(type: HlsPlaylistType) -> Bool { true } func didInterceptPlaylistRequest(type: HlsPlaylistType, request: URLRequest) async throws -> URLRequest { - if type == .master { - masterURLRequest = request + if let url = request.url { + requestMap[url] = request } return request } @@ -196,11 +196,11 @@ extension AVSubtitlesLoader: MediaPlaylistInterceptor { // intercept the master manifest to append the subtitles subtitles = await validateSubtitles() if subtitles.isEmpty { return data } - return await self.handleMasterManifestRequest(url, request: masterURLRequest) ?? data + return await self.handleMasterManifestRequest(url, request: requestMap[url]) ?? data case .video: // intercept the variant manifest to get the duration if subtitles.isEmpty { return data } - return await self.handleVariantManifest(url) ?? data + return await self.handleVariantManifest(url, request: requestMap[url]) ?? data case .subtitles: // intercept the subtitle request to respond with the HLS subtitle if subtitles.isEmpty { return data } diff --git a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift index af076239..83416ab3 100644 --- a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift +++ b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/MasterPlaylistParser.swift @@ -12,15 +12,9 @@ class MasterPlaylistParser: PlaylistParser { var constructedManifestArray = [String]() fileprivate var lastMediaLine: Int? fileprivate let subtitlesGroupId = "THEOsubs" - private let request: URLRequest? - - init(url: URL, request: URLRequest?) { - self.request = request - super.init(url: url) - } func sideLoadSubtitles(subtitles: [TextTrackDescription]) async -> Data? { - var headers = request?.allHTTPHeaderFields + let headers = request?.allHTTPHeaderFields guard let _ = await self.loadManifest(headers) else { return nil } self.parseManifest() self.appendSubtitlesLines(subtitles: subtitles) diff --git a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift index 4eed04f0..aad3cf55 100644 --- a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift +++ b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/PlaylistParser.swift @@ -10,10 +10,12 @@ import Foundation class PlaylistParser { var manifestURL: URL var manifestData: Data? + let request: URLRequest? - init(url: URL) { + init(url: URL, request: URLRequest?) { self.manifestURL = url self.manifestData = nil + self.request = request } func loadManifest(_ headers: [String: String]? = nil) async -> Data? { diff --git a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/VariantPlaylistParser.swift b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/VariantPlaylistParser.swift index 72adf59d..35c533c9 100644 --- a/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/VariantPlaylistParser.swift +++ b/Code/Sideloaded-TextTracks/Sources/THEOplayerConnectorSideloadedSubtitle/Parsers/VariantPlaylistParser.swift @@ -11,13 +11,14 @@ class VariantPlaylistParser: PlaylistParser { fileprivate(set) var totalPlayListDuration: Double var constructedManifestArray = [String]() - override init(url: URL) { + override init(url: URL, request: URLRequest?) { self.totalPlayListDuration = 0 - super.init(url: url) + super.init(url: url, request: request) } func parse() async -> VariantPlaylistParser? { - guard let _ = await self.loadManifest() else { return nil } + let headers = request?.allHTTPHeaderFields + guard let _ = await self.loadManifest(headers) else { return nil } self.parseManifest() let constructed = self.constructedManifestArray.joined(separator: "\n") if THEOplayerConnectorSideloadedSubtitle.SHOW_DEBUG_LOGS { From 7d59a426ba7a17e448107f03c0cc0a759a863941 Mon Sep 17 00:00:00 2001 From: Raffi Date: Tue, 12 May 2026 13:40:09 +0200 Subject: [PATCH 3/4] add changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60e2685a..c1e7081f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- SideloadedSubtitle + - Fixed an issue where internal network requests would cause a user agent mismatch. + ## [11.0.1] - 2026-04-21 ### Fixed From b00de2c05e043d52ba8842cd90a890f660a15880 Mon Sep 17 00:00:00 2001 From: Raffi Date: Tue, 12 May 2026 13:40:39 +0200 Subject: [PATCH 4/4] adjust changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e7081f..428507fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Fixed + - SideloadedSubtitle - Fixed an issue where internal network requests would cause a user agent mismatch.