2021-10-16 22:48:58 +00:00
|
|
|
import Foundation
|
|
|
|
import Siesta
|
2021-10-18 21:53:02 +00:00
|
|
|
import SwiftUI
|
2021-10-16 22:48:58 +00:00
|
|
|
|
|
|
|
extension PlayerModel {
|
|
|
|
var isLoadingAvailableStreams: Bool {
|
|
|
|
streamSelection.isNil || availableStreams.isEmpty
|
|
|
|
}
|
|
|
|
|
|
|
|
var isLoadingStream: Bool {
|
|
|
|
!stream.isNil && stream != streamSelection
|
|
|
|
}
|
|
|
|
|
2021-10-17 21:49:56 +00:00
|
|
|
var availableStreamsSorted: [Stream] {
|
|
|
|
availableStreams.sorted(by: streamsSorter)
|
|
|
|
}
|
|
|
|
|
2022-12-18 12:11:06 +00:00
|
|
|
func loadAvailableStreams(_ video: Video, onCompletion: @escaping (ResponseInfo) -> Void = { _ in }) {
|
2022-12-21 20:16:47 +00:00
|
|
|
captions = nil
|
2021-10-16 22:48:58 +00:00
|
|
|
availableStreams = []
|
2021-12-19 16:56:47 +00:00
|
|
|
|
2022-09-28 14:27:01 +00:00
|
|
|
guard let playerInstance else { return }
|
2021-10-16 22:48:58 +00:00
|
|
|
|
2022-12-21 17:13:41 +00:00
|
|
|
guard let api = playerAPI(video) else { return }
|
2022-06-18 12:39:49 +00:00
|
|
|
logger.info("loading streams from \(playerInstance.description)")
|
2022-12-21 17:13:41 +00:00
|
|
|
fetchStreams(api.video(video.videoID), instance: playerInstance, video: video, onCompletion: onCompletion)
|
2021-10-16 22:48:58 +00:00
|
|
|
}
|
|
|
|
|
2021-10-20 22:21:50 +00:00
|
|
|
private func fetchStreams(
|
|
|
|
_ resource: Resource,
|
|
|
|
instance: Instance,
|
2021-10-16 22:48:58 +00:00
|
|
|
video: Video,
|
|
|
|
onCompletion: @escaping (ResponseInfo) -> Void = { _ in }
|
|
|
|
) {
|
2021-10-20 22:21:50 +00:00
|
|
|
resource
|
2021-10-16 22:48:58 +00:00
|
|
|
.load()
|
|
|
|
.onSuccess { response in
|
|
|
|
if let video: Video = response.typedContent() {
|
2022-12-10 00:23:13 +00:00
|
|
|
VideosCacheModel.shared.storeVideo(video)
|
2022-11-11 19:34:37 +00:00
|
|
|
guard video.videoID == self.currentVideo?.videoID else {
|
2021-12-29 18:55:41 +00:00
|
|
|
self.logger.info("ignoring loaded streams from \(instance.description) as current video has changed")
|
|
|
|
return
|
|
|
|
}
|
2023-05-20 21:47:14 +00:00
|
|
|
self.availableStreams = self.streamsWithInstance(instance: instance, streams: video.streams)
|
2021-12-19 16:56:47 +00:00
|
|
|
} else {
|
|
|
|
self.logger.critical("no streams available from \(instance.description)")
|
2021-10-16 22:48:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
.onCompletion(onCompletion)
|
2022-06-29 22:44:32 +00:00
|
|
|
.onFailure { [weak self] responseError in
|
|
|
|
self?.navigation.presentAlert(title: "Could not load streams", message: responseError.userMessage)
|
|
|
|
self?.videoBeingOpened = nil
|
|
|
|
}
|
2021-10-16 22:48:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func streamsWithInstance(instance: Instance, streams: [Stream]) -> [Stream] {
|
|
|
|
streams.map { stream in
|
|
|
|
stream.instance = instance
|
2021-10-21 23:29:10 +00:00
|
|
|
|
2022-07-21 21:52:09 +00:00
|
|
|
if instance.app == .invidious, instance.proxiesVideos {
|
2022-06-18 12:39:49 +00:00
|
|
|
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)
|
|
|
|
}
|
2021-10-21 23:29:10 +00:00
|
|
|
}
|
2021-10-22 15:00:09 +00:00
|
|
|
|
2021-10-16 22:48:58 +00:00
|
|
|
return stream
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-17 21:49:56 +00:00
|
|
|
func streamsSorter(_ lhs: Stream, _ rhs: Stream) -> Bool {
|
2021-10-22 20:49:31 +00:00
|
|
|
if lhs.resolution.isNil || rhs.resolution.isNil {
|
|
|
|
return lhs.kind < rhs.kind
|
|
|
|
}
|
|
|
|
|
|
|
|
return lhs.kind == rhs.kind ? (lhs.resolution.height > rhs.resolution.height) : (lhs.kind < rhs.kind)
|
2021-10-17 21:49:56 +00:00
|
|
|
}
|
2021-10-16 22:48:58 +00:00
|
|
|
}
|