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:
parent
6b2eaf89c6
commit
084bcdaeff
7 changed files with 41 additions and 18 deletions
|
|
@ -345,7 +345,7 @@
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 69;
|
CURRENT_PROJECT_VERSION = 70;
|
||||||
DEVELOPMENT_TEAM = X25NYX3K49;
|
DEVELOPMENT_TEAM = X25NYX3K49;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
|
|
@ -360,7 +360,7 @@
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks"
|
"@executable_path/Frameworks"
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.5.56;
|
MARKETING_VERSION = 0.5.57;
|
||||||
OTHER_LDFLAGS = ("$(inherited)", "-ObjC");
|
OTHER_LDFLAGS = ("$(inherited)", "-ObjC");
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = nl.vonas.mediacluster.ios;
|
PRODUCT_BUNDLE_IDENTIFIER = nl.vonas.mediacluster.ios;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
|
@ -378,7 +378,7 @@
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 69;
|
CURRENT_PROJECT_VERSION = 70;
|
||||||
DEVELOPMENT_TEAM = X25NYX3K49;
|
DEVELOPMENT_TEAM = X25NYX3K49;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
|
|
@ -393,7 +393,7 @@
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks"
|
"@executable_path/Frameworks"
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.5.56;
|
MARKETING_VERSION = 0.5.57;
|
||||||
OTHER_LDFLAGS = ("$(inherited)", "-ObjC");
|
OTHER_LDFLAGS = ("$(inherited)", "-ObjC");
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = nl.vonas.mediacluster.ios;
|
PRODUCT_BUNDLE_IDENTIFIER = nl.vonas.mediacluster.ios;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ final class AVLivePlayerController: NSObject, ObservableObject {
|
||||||
url: URL,
|
url: URL,
|
||||||
fallback: URL? = nil,
|
fallback: URL? = nil,
|
||||||
format: String? = nil,
|
format: String? = nil,
|
||||||
clearKeys: [ClearKeyEntry] = []
|
clearKeys: [ClearKeyEntry] = [],
|
||||||
|
browserCdnHeaders: Bool = false
|
||||||
) async {
|
) async {
|
||||||
generation &+= 1
|
generation &+= 1
|
||||||
let gen = generation
|
let gen = generation
|
||||||
|
|
@ -78,7 +79,8 @@ final class AVLivePlayerController: NSObject, ObservableObject {
|
||||||
let started = try await ClearKeyDashProxy.shared.start(
|
let started = try await ClearKeyDashProxy.shared.start(
|
||||||
manifestURL: url,
|
manifestURL: url,
|
||||||
keys: clearKeys,
|
keys: clearKeys,
|
||||||
preferHlsForAVPlayer: true
|
preferHlsForAVPlayer: true,
|
||||||
|
browserCdnHeaders: browserCdnHeaders
|
||||||
)
|
)
|
||||||
guard gen == generation, !stopping else { return }
|
guard gen == generation, !stopping else { return }
|
||||||
playURL = started.url
|
playURL = started.url
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,8 @@ final class ClearKeyDashProxy {
|
||||||
func start(
|
func start(
|
||||||
manifestURL: URL,
|
manifestURL: URL,
|
||||||
keys: [ClearKeyEntry],
|
keys: [ClearKeyEntry],
|
||||||
preferHlsForAVPlayer: Bool = false
|
preferHlsForAVPlayer: Bool = false,
|
||||||
|
browserCdnHeaders: Bool = false
|
||||||
) async throws -> StartResult {
|
) async throws -> StartResult {
|
||||||
let map = ClearKeyKeyMap(entries: keys)
|
let map = ClearKeyKeyMap(entries: keys)
|
||||||
guard !map.isEmpty else {
|
guard !map.isEmpty else {
|
||||||
|
|
@ -235,7 +236,11 @@ final class ClearKeyDashProxy {
|
||||||
self.keyMap = map
|
self.keyMap = map
|
||||||
self.isHlsMode = hls
|
self.isHlsMode = hls
|
||||||
self.preferHlsOutput = preferHlsForAVPlayer
|
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.dashVideoRep = nil
|
||||||
self.dashAudioRep = nil
|
self.dashAudioRep = nil
|
||||||
self.dashAudioReps = []
|
self.dashAudioReps = []
|
||||||
|
|
@ -1112,7 +1117,7 @@ final class ClearKeyDashProxy {
|
||||||
req.timeoutInterval = 15
|
req.timeoutInterval = 15
|
||||||
req.cachePolicy = .reloadIgnoringLocalCacheData
|
req.cachePolicy = .reloadIgnoringLocalCacheData
|
||||||
req.setValue("bytes", forHTTPHeaderField: "Accept-Ranges")
|
req.setValue("bytes", forHTTPHeaderField: "Accept-Ranges")
|
||||||
let browser = withState { useViaplayBrowserHeaders } || ViaplayPlaybackHeaders.matches(current)
|
let browser = withState { useViaplayBrowserHeaders }
|
||||||
let session: URLSession
|
let session: URLSession
|
||||||
if browser {
|
if browser {
|
||||||
ViaplayPlaybackHeaders.apply(to: &req)
|
ViaplayPlaybackHeaders.apply(to: &req)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ struct PlayRequest: Identifiable {
|
||||||
/// Provider-/titel-logo voor laad-animatie (events, films, series).
|
/// Provider-/titel-logo voor laad-animatie (events, films, series).
|
||||||
let logoUrl: String?
|
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(
|
static func vod(
|
||||||
url: URL,
|
url: URL,
|
||||||
title: String,
|
title: String,
|
||||||
|
|
@ -579,7 +585,8 @@ struct PlayerScreen: View {
|
||||||
fallback: request.fallbackUrl,
|
fallback: request.fallbackUrl,
|
||||||
format: request.format,
|
format: request.format,
|
||||||
clearKeys: keys,
|
clearKeys: keys,
|
||||||
preferHls: true
|
preferHls: true,
|
||||||
|
browserCdnHeaders: request.usesViaplayCdn
|
||||||
)
|
)
|
||||||
let maxWaitNs: UInt64 = 18_000_000_000
|
let maxWaitNs: UInt64 = 18_000_000_000
|
||||||
let stepNs: UInt64 = 200_000_000
|
let stepNs: UInt64 = 200_000_000
|
||||||
|
|
@ -597,7 +604,8 @@ struct PlayerScreen: View {
|
||||||
url: request.url,
|
url: request.url,
|
||||||
fallback: request.fallbackUrl,
|
fallback: request.fallbackUrl,
|
||||||
format: request.format,
|
format: request.format,
|
||||||
clearKeys: keys
|
clearKeys: keys,
|
||||||
|
browserCdnHeaders: request.usesViaplayCdn
|
||||||
)
|
)
|
||||||
let maxWaitNs: UInt64 = 18_000_000_000
|
let maxWaitNs: UInt64 = 18_000_000_000
|
||||||
let stepNs: UInt64 = 200_000_000
|
let stepNs: UInt64 = 200_000_000
|
||||||
|
|
@ -620,7 +628,8 @@ struct PlayerScreen: View {
|
||||||
fallback: request.fallbackUrl,
|
fallback: request.fallbackUrl,
|
||||||
format: request.format,
|
format: request.format,
|
||||||
clearKeys: keys,
|
clearKeys: keys,
|
||||||
preferHls: true
|
preferHls: true,
|
||||||
|
browserCdnHeaders: request.usesViaplayCdn
|
||||||
)
|
)
|
||||||
waited = 0
|
waited = 0
|
||||||
while waited < 8_000_000_000 && !vlc.isPlaying && !vlc.hasError {
|
while waited < 8_000_000_000 && !vlc.isPlaying && !vlc.hasError {
|
||||||
|
|
@ -638,7 +647,8 @@ struct PlayerScreen: View {
|
||||||
url: request.url,
|
url: request.url,
|
||||||
fallback: request.fallbackUrl,
|
fallback: request.fallbackUrl,
|
||||||
format: request.format,
|
format: request.format,
|
||||||
clearKeys: []
|
clearKeys: [],
|
||||||
|
browserCdnHeaders: request.usesViaplayCdn
|
||||||
)
|
)
|
||||||
let maxWaitNs: UInt64 = 4_000_000_000
|
let maxWaitNs: UInt64 = 4_000_000_000
|
||||||
let stepNs: UInt64 = 200_000_000
|
let stepNs: UInt64 = 200_000_000
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,8 @@ final class VLCPlayerController: NSObject, ObservableObject, VLCMediaPlayerDeleg
|
||||||
fallback: URL? = nil,
|
fallback: URL? = nil,
|
||||||
format: String? = nil,
|
format: String? = nil,
|
||||||
clearKeys: [ClearKeyEntry] = [],
|
clearKeys: [ClearKeyEntry] = [],
|
||||||
preferHls: Bool = false
|
preferHls: Bool = false,
|
||||||
|
browserCdnHeaders: Bool = false
|
||||||
) async {
|
) async {
|
||||||
// Annuleer pending finishStop / delayed proxy-stop van vorige sessie.
|
// Annuleer pending finishStop / delayed proxy-stop van vorige sessie.
|
||||||
stopGeneration &+= 1
|
stopGeneration &+= 1
|
||||||
|
|
@ -310,7 +311,8 @@ final class VLCPlayerController: NSObject, ObservableObject, VLCMediaPlayerDeleg
|
||||||
let started = try await ClearKeyDashProxy.shared.start(
|
let started = try await ClearKeyDashProxy.shared.start(
|
||||||
manifestURL: url,
|
manifestURL: url,
|
||||||
keys: clearKeys,
|
keys: clearKeys,
|
||||||
preferHlsForAVPlayer: preferHls
|
preferHlsForAVPlayer: preferHls,
|
||||||
|
browserCdnHeaders: browserCdnHeaders
|
||||||
)
|
)
|
||||||
playURL = started.url
|
playURL = started.url
|
||||||
proxySession = started.session
|
proxySession = started.session
|
||||||
|
|
|
||||||
|
|
@ -768,6 +768,9 @@ private struct HubPlaybackModifier: ViewModifier {
|
||||||
set: { if !$0 { playback.info = nil } }
|
set: { if !$0 { playback.info = nil } }
|
||||||
)) {
|
)) {
|
||||||
if let info = playback.info, let url = URL(string: info.streamUrl) {
|
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(
|
PlayerScreen(request: .live(
|
||||||
url: url,
|
url: url,
|
||||||
title: info.name,
|
title: info.name,
|
||||||
|
|
@ -776,8 +779,9 @@ private struct HubPlaybackModifier: ViewModifier {
|
||||||
drm: info.drm,
|
drm: info.drm,
|
||||||
watchSessionId: info.watchSessionId,
|
watchSessionId: info.watchSessionId,
|
||||||
watchKind: "event",
|
watchKind: "event",
|
||||||
watchId: info.streamId.isEmpty ? nil : info.streamId,
|
watchId: viaplay ? (sid.isEmpty ? "viaplay" : sid) : (sid.isEmpty ? nil : sid),
|
||||||
logoUrl: info.logoUrl
|
logoUrl: info.logoUrl,
|
||||||
|
isLive: info.live ?? true
|
||||||
))
|
))
|
||||||
.environmentObject(app)
|
.environmentObject(app)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ struct SettingsScreen: View {
|
||||||
|
|
||||||
Section("Info") {
|
Section("Info") {
|
||||||
LabeledContent("App", value: "VMC iOS")
|
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("Live TV", value: app.iptvEnabled ? "Aan" : "Uit")
|
||||||
LabeledContent("Events", value: app.eventsEnabled ? "Aan" : "Uit")
|
LabeledContent("Events", value: app.eventsEnabled ? "Aan" : "Uit")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue