mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
improved conditional proxying
We don't test every single stream anymore. If we get an 200, 206 or 403 we immediately stop testing streams. Unknown streams are also skipped. This speeds up starting playback, since we don'T have to wait for the network anymore.
This commit is contained in:
parent
d6cfadab9a
commit
30cdaf88e1
@ -56,82 +56,101 @@ extension PlayerModel {
|
||||
}
|
||||
}
|
||||
|
||||
func streamsWithInstance(instance _: Instance, streams: [Stream], completion: @escaping ([Stream]) -> Void) {
|
||||
func streamsWithInstance(instance: Instance, streams: [Stream], completion: @escaping ([Stream]) -> Void) {
|
||||
// Queue for stream processing
|
||||
let streamProcessingQueue = DispatchQueue(label: "stream.yattee.streamProcessing.Queue", qos: .userInitiated)
|
||||
let streamProcessingQueue = DispatchQueue(label: "stream.yattee.streamProcessing.Queue")
|
||||
// Queue for accessing the processedStreams array
|
||||
let processedStreamsQueue = DispatchQueue(label: "stream.yattee.processedStreams.Queue")
|
||||
// DispatchGroup for managing multiple tasks
|
||||
let streamProcessingGroup = DispatchGroup()
|
||||
|
||||
var processedStreams = [Stream]()
|
||||
let instance = instance
|
||||
|
||||
var hasForbiddenAsset = false
|
||||
var hasAllowedAsset = false
|
||||
|
||||
for stream in streams {
|
||||
streamProcessingQueue.async(group: streamProcessingGroup) {
|
||||
let forbiddenAssetTestGroup = DispatchGroup()
|
||||
var hasForbiddenAsset = false
|
||||
if !hasAllowedAsset, !hasForbiddenAsset, !instance.proxiesVideos, stream.format != Stream.Format.unknown {
|
||||
let (nonHLSAssets, hlsURLs) = self.getAssets(from: [stream])
|
||||
if let firstStream = nonHLSAssets.first {
|
||||
let asset = firstStream.0
|
||||
let url = firstStream.1
|
||||
let requestRange = firstStream.2
|
||||
|
||||
let (nonHLSAssets, hlsURLs) = self.getAssets(from: [stream])
|
||||
|
||||
if let randomStream = nonHLSAssets.randomElement() {
|
||||
let instance = randomStream.0
|
||||
let asset = randomStream.1
|
||||
let url = randomStream.2
|
||||
let requestRange = randomStream.3
|
||||
|
||||
// swiftlint:disable:next shorthand_optional_binding
|
||||
if let asset = asset, let instance = instance, !instance.proxiesVideos {
|
||||
if instance.app == .invidious {
|
||||
self.testAsset(url: url, range: requestRange, isHLS: false, forbiddenAssetTestGroup: forbiddenAssetTestGroup) { isForbidden in
|
||||
hasForbiddenAsset = isForbidden
|
||||
self.testAsset(url: url, range: requestRange, isHLS: false, forbiddenAssetTestGroup: forbiddenAssetTestGroup) { status in
|
||||
switch status {
|
||||
case HTTPStatus.Forbidden:
|
||||
hasForbiddenAsset = true
|
||||
case HTTPStatus.PartialContent:
|
||||
hasAllowedAsset = true
|
||||
case HTTPStatus.OK:
|
||||
hasAllowedAsset = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if instance.app == .piped {
|
||||
self.testPipedAssets(asset: asset, requestRange: requestRange, isHLS: false, forbiddenAssetTestGroup: forbiddenAssetTestGroup) { isForbidden in
|
||||
hasForbiddenAsset = isForbidden
|
||||
self.testPipedAssets(asset: asset!, requestRange: requestRange, isHLS: false, forbiddenAssetTestGroup: forbiddenAssetTestGroup) { status in
|
||||
switch status {
|
||||
case HTTPStatus.Forbidden:
|
||||
hasForbiddenAsset = true
|
||||
case HTTPStatus.PartialContent:
|
||||
hasAllowedAsset = true
|
||||
case HTTPStatus.OK:
|
||||
hasAllowedAsset = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let randomHLS = hlsURLs.randomElement() {
|
||||
let instance = randomHLS.0
|
||||
let asset = AVURLAsset(url: randomHLS.1)
|
||||
|
||||
if instance?.app == .piped {
|
||||
self.testPipedAssets(asset: asset, requestRange: nil, isHLS: true, forbiddenAssetTestGroup: forbiddenAssetTestGroup) { isForbidden in
|
||||
hasForbiddenAsset = isForbidden
|
||||
} else if let firstHLS = hlsURLs.first {
|
||||
let asset = AVURLAsset(url: firstHLS)
|
||||
if instance.app == .piped {
|
||||
self.testPipedAssets(asset: asset, requestRange: nil, isHLS: true, forbiddenAssetTestGroup: forbiddenAssetTestGroup) { status in
|
||||
switch status {
|
||||
case HTTPStatus.Forbidden:
|
||||
hasForbiddenAsset = true
|
||||
case HTTPStatus.PartialContent:
|
||||
hasAllowedAsset = true
|
||||
case HTTPStatus.OK:
|
||||
hasAllowedAsset = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forbiddenAssetTestGroup.wait()
|
||||
|
||||
// Post-processing code
|
||||
if let instance = stream.instance {
|
||||
if instance.app == .invidious {
|
||||
if hasForbiddenAsset || instance.proxiesVideos {
|
||||
if let audio = stream.audioAsset {
|
||||
stream.audioAsset = InvidiousAPI.proxiedAsset(instance: instance, asset: audio)
|
||||
}
|
||||
if let video = stream.videoAsset {
|
||||
stream.videoAsset = InvidiousAPI.proxiedAsset(instance: instance, asset: video)
|
||||
if instance.app == .invidious, hasForbiddenAsset || instance.proxiesVideos {
|
||||
if let audio = stream.audioAsset {
|
||||
stream.audioAsset = InvidiousAPI.proxiedAsset(instance: instance, asset: audio)
|
||||
}
|
||||
if let video = stream.videoAsset {
|
||||
stream.videoAsset = InvidiousAPI.proxiedAsset(instance: instance, asset: video)
|
||||
}
|
||||
} else if instance.app == .piped, !instance.proxiesVideos, !hasForbiddenAsset {
|
||||
if let hlsURL = stream.hlsURL {
|
||||
PipedAPI.nonProxiedAsset(url: hlsURL) { possibleNonProxiedURL in
|
||||
if let nonProxiedURL = possibleNonProxiedURL {
|
||||
stream.hlsURL = nonProxiedURL.url
|
||||
}
|
||||
}
|
||||
} else if instance.app == .piped, !instance.proxiesVideos, !hasForbiddenAsset {
|
||||
if let hlsURL = stream.hlsURL {
|
||||
PipedAPI.nonProxiedAsset(url: hlsURL) { possibleNonProxiedURL in
|
||||
if let nonProxiedURL = possibleNonProxiedURL {
|
||||
stream.hlsURL = nonProxiedURL.url
|
||||
}
|
||||
} else {
|
||||
if let audio = stream.audioAsset {
|
||||
PipedAPI.nonProxiedAsset(asset: audio) { nonProxiedAudioAsset in
|
||||
stream.audioAsset = nonProxiedAudioAsset
|
||||
}
|
||||
} else {
|
||||
if let audio = stream.audioAsset {
|
||||
PipedAPI.nonProxiedAsset(asset: audio) { nonProxiedAudioAsset in
|
||||
stream.audioAsset = nonProxiedAudioAsset
|
||||
}
|
||||
}
|
||||
if let video = stream.videoAsset {
|
||||
PipedAPI.nonProxiedAsset(asset: video) { nonProxiedVideoAsset in
|
||||
stream.videoAsset = nonProxiedVideoAsset
|
||||
}
|
||||
}
|
||||
if let video = stream.videoAsset {
|
||||
PipedAPI.nonProxiedAsset(asset: video) { nonProxiedVideoAsset in
|
||||
stream.videoAsset = nonProxiedVideoAsset
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -152,21 +171,21 @@ extension PlayerModel {
|
||||
}
|
||||
}
|
||||
|
||||
private func getAssets(from streams: [Stream]) -> (nonHLSAssets: [(Instance?, AVURLAsset?, URL, String?)], hlsURLs: [(Instance?, URL)]) {
|
||||
var nonHLSAssets = [(Instance?, AVURLAsset?, URL, String?)]()
|
||||
var hlsURLs = [(Instance?, URL)]()
|
||||
private func getAssets(from streams: [Stream]) -> (nonHLSAssets: [(AVURLAsset?, URL, String?)], hlsURLs: [URL]) {
|
||||
var nonHLSAssets = [(AVURLAsset?, URL, String?)]()
|
||||
var hlsURLs = [URL]()
|
||||
|
||||
for stream in streams {
|
||||
if stream.isHLS {
|
||||
if let url = stream.hlsURL?.url {
|
||||
hlsURLs.append((stream.instance, url))
|
||||
hlsURLs.append(url)
|
||||
}
|
||||
} else {
|
||||
if let asset = stream.audioAsset {
|
||||
nonHLSAssets.append((stream.instance, asset, asset.url, stream.requestRange))
|
||||
nonHLSAssets.append((asset, asset.url, stream.requestRange))
|
||||
}
|
||||
if let asset = stream.videoAsset {
|
||||
nonHLSAssets.append((stream.instance, asset, asset.url, stream.requestRange))
|
||||
nonHLSAssets.append((asset, asset.url, stream.requestRange))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,24 +193,24 @@ extension PlayerModel {
|
||||
return (nonHLSAssets, hlsURLs)
|
||||
}
|
||||
|
||||
private func testAsset(url: URL, range: String?, isHLS: Bool, forbiddenAssetTestGroup: DispatchGroup, completion: @escaping (Bool) -> Void) {
|
||||
private func testAsset(url: URL, range: String?, isHLS: Bool, forbiddenAssetTestGroup: DispatchGroup, completion: @escaping (Int) -> Void) {
|
||||
// In case the range is nil, generate a random one.
|
||||
let randomEnd = Int.random(in: 200 ... 800)
|
||||
let requestRange = range ?? "0-\(randomEnd)"
|
||||
|
||||
forbiddenAssetTestGroup.enter()
|
||||
URLTester.testURLResponse(url: url, range: requestRange, isHLS: isHLS) { statusCode in
|
||||
completion(statusCode == HTTPStatus.Forbidden)
|
||||
completion(statusCode)
|
||||
forbiddenAssetTestGroup.leave()
|
||||
}
|
||||
}
|
||||
|
||||
private func testPipedAssets(asset: AVURLAsset, requestRange: String?, isHLS: Bool, forbiddenAssetTestGroup: DispatchGroup, completion: @escaping (Bool) -> Void) {
|
||||
private func testPipedAssets(asset: AVURLAsset, requestRange: String?, isHLS: Bool, forbiddenAssetTestGroup: DispatchGroup, completion: @escaping (Int) -> Void) {
|
||||
PipedAPI.nonProxiedAsset(asset: asset) { possibleNonProxiedAsset in
|
||||
if let nonProxiedAsset = possibleNonProxiedAsset {
|
||||
self.testAsset(url: nonProxiedAsset.url, range: requestRange, isHLS: isHLS, forbiddenAssetTestGroup: forbiddenAssetTestGroup, completion: completion)
|
||||
} else {
|
||||
completion(false)
|
||||
completion(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user