Use Chrome/122 on every Viaplay CDN hop, like the standalone MPD player.

iOS only sent that UA when the hostname looked like viaplay; stored MPDs often do not. Event plays now pin the browser session for the whole fetch chain, still direct to the CDN.
This commit is contained in:
Jos Vooges | STH 2026-09-28 21:19:22 +02:00
parent 6b2eaf89c6
commit 084bcdaeff
7 changed files with 41 additions and 18 deletions

View file

@ -345,7 +345,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 69;
CURRENT_PROJECT_VERSION = 70;
DEVELOPMENT_TEAM = X25NYX3K49;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@ -360,7 +360,7 @@
"$(inherited)",
"@executable_path/Frameworks"
);
MARKETING_VERSION = 0.5.56;
MARKETING_VERSION = 0.5.57;
OTHER_LDFLAGS = ("$(inherited)", "-ObjC");
PRODUCT_BUNDLE_IDENTIFIER = nl.vonas.mediacluster.ios;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -378,7 +378,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 69;
CURRENT_PROJECT_VERSION = 70;
DEVELOPMENT_TEAM = X25NYX3K49;
ENABLE_BITCODE = NO;
ENABLE_PREVIEWS = YES;
@ -393,7 +393,7 @@
"$(inherited)",
"@executable_path/Frameworks"
);
MARKETING_VERSION = 0.5.56;
MARKETING_VERSION = 0.5.57;
OTHER_LDFLAGS = ("$(inherited)", "-ObjC");
PRODUCT_BUNDLE_IDENTIFIER = nl.vonas.mediacluster.ios;
PRODUCT_NAME = "$(TARGET_NAME)";

View file

@ -47,7 +47,8 @@ final class AVLivePlayerController: NSObject, ObservableObject {
url: URL,
fallback: URL? = nil,
format: String? = nil,
clearKeys: [ClearKeyEntry] = []
clearKeys: [ClearKeyEntry] = [],
browserCdnHeaders: Bool = false
) async {
generation &+= 1
let gen = generation
@ -78,7 +79,8 @@ final class AVLivePlayerController: NSObject, ObservableObject {
let started = try await ClearKeyDashProxy.shared.start(
manifestURL: url,
keys: clearKeys,
preferHlsForAVPlayer: true
preferHlsForAVPlayer: true,
browserCdnHeaders: browserCdnHeaders
)
guard gen == generation, !stopping else { return }
playURL = started.url

View file

@ -217,7 +217,8 @@ final class ClearKeyDashProxy {
func start(
manifestURL: URL,
keys: [ClearKeyEntry],
preferHlsForAVPlayer: Bool = false
preferHlsForAVPlayer: Bool = false,
browserCdnHeaders: Bool = false
) async throws -> StartResult {
let map = ClearKeyKeyMap(entries: keys)
guard !map.isEmpty else {
@ -235,7 +236,11 @@ final class ClearKeyDashProxy {
self.keyMap = map
self.isHlsMode = hls
self.preferHlsOutput = preferHlsForAVPlayer
self.useViaplayBrowserHeaders = ViaplayPlaybackHeaders.matches(manifestURL)
self.useViaplayBrowserHeaders =
browserCdnHeaders || ViaplayPlaybackHeaders.matches(manifestURL)
if self.useViaplayBrowserHeaders {
proxyLog.info("CDN headers=Chrome/122 for whole session")
}
self.dashVideoRep = nil
self.dashAudioRep = nil
self.dashAudioReps = []
@ -1112,7 +1117,7 @@ final class ClearKeyDashProxy {
req.timeoutInterval = 15
req.cachePolicy = .reloadIgnoringLocalCacheData
req.setValue("bytes", forHTTPHeaderField: "Accept-Ranges")
let browser = withState { useViaplayBrowserHeaders } || ViaplayPlaybackHeaders.matches(current)
let browser = withState { useViaplayBrowserHeaders }
let session: URLSession
if browser {
ViaplayPlaybackHeaders.apply(to: &req)

View file

@ -21,6 +21,12 @@ struct PlayRequest: Identifiable {
/// Provider-/titel-logo voor laad-animatie (events, films, series).
let logoUrl: String?
/// Zelfde Chrome/122-UA als de werkende losse MPD-speler, voor de hele CDN-sessie.
var usesViaplayCdn: Bool {
ViaplayPlaybackHeaders.matches(url)
|| (watchId ?? "").localizedCaseInsensitiveContains("viaplay")
}
static func vod(
url: URL,
title: String,
@ -579,7 +585,8 @@ struct PlayerScreen: View {
fallback: request.fallbackUrl,
format: request.format,
clearKeys: keys,
preferHls: true
preferHls: true,
browserCdnHeaders: request.usesViaplayCdn
)
let maxWaitNs: UInt64 = 18_000_000_000
let stepNs: UInt64 = 200_000_000
@ -597,7 +604,8 @@ struct PlayerScreen: View {
url: request.url,
fallback: request.fallbackUrl,
format: request.format,
clearKeys: keys
clearKeys: keys,
browserCdnHeaders: request.usesViaplayCdn
)
let maxWaitNs: UInt64 = 18_000_000_000
let stepNs: UInt64 = 200_000_000
@ -620,7 +628,8 @@ struct PlayerScreen: View {
fallback: request.fallbackUrl,
format: request.format,
clearKeys: keys,
preferHls: true
preferHls: true,
browserCdnHeaders: request.usesViaplayCdn
)
waited = 0
while waited < 8_000_000_000 && !vlc.isPlaying && !vlc.hasError {
@ -638,7 +647,8 @@ struct PlayerScreen: View {
url: request.url,
fallback: request.fallbackUrl,
format: request.format,
clearKeys: []
clearKeys: [],
browserCdnHeaders: request.usesViaplayCdn
)
let maxWaitNs: UInt64 = 4_000_000_000
let stepNs: UInt64 = 200_000_000

View file

@ -278,7 +278,8 @@ final class VLCPlayerController: NSObject, ObservableObject, VLCMediaPlayerDeleg
fallback: URL? = nil,
format: String? = nil,
clearKeys: [ClearKeyEntry] = [],
preferHls: Bool = false
preferHls: Bool = false,
browserCdnHeaders: Bool = false
) async {
// Annuleer pending finishStop / delayed proxy-stop van vorige sessie.
stopGeneration &+= 1
@ -310,7 +311,8 @@ final class VLCPlayerController: NSObject, ObservableObject, VLCMediaPlayerDeleg
let started = try await ClearKeyDashProxy.shared.start(
manifestURL: url,
keys: clearKeys,
preferHlsForAVPlayer: preferHls
preferHlsForAVPlayer: preferHls,
browserCdnHeaders: browserCdnHeaders
)
playURL = started.url
proxySession = started.session

View file

@ -768,6 +768,9 @@ private struct HubPlaybackModifier: ViewModifier {
set: { if !$0 { playback.info = nil } }
)) {
if let info = playback.info, let url = URL(string: info.streamUrl) {
let sid = info.streamId
let viaplay = ViaplayPlaybackHeaders.matches(url)
|| sid.localizedCaseInsensitiveContains("viaplay")
PlayerScreen(request: .live(
url: url,
title: info.name,
@ -776,8 +779,9 @@ private struct HubPlaybackModifier: ViewModifier {
drm: info.drm,
watchSessionId: info.watchSessionId,
watchKind: "event",
watchId: info.streamId.isEmpty ? nil : info.streamId,
logoUrl: info.logoUrl
watchId: viaplay ? (sid.isEmpty ? "viaplay" : sid) : (sid.isEmpty ? nil : sid),
logoUrl: info.logoUrl,
isLive: info.live ?? true
))
.environmentObject(app)
}

View file

@ -96,7 +96,7 @@ struct SettingsScreen: View {
Section("Info") {
LabeledContent("App", value: "VMC iOS")
LabeledContent("Versie", value: "0.5.56")
LabeledContent("Versie", value: "0.5.57")
LabeledContent("Live TV", value: app.iptvEnabled ? "Aan" : "Uit")
LabeledContent("Events", value: app.eventsEnabled ? "Aan" : "Uit")
}