Better loading and handling streams

This commit is contained in:
Arkadiusz Fal 2021-12-19 17:56:47 +01:00
parent 1fbb0cfa80
commit cef0b2594a
5 changed files with 48 additions and 52 deletions

View File

@ -6,6 +6,14 @@ final class InstancesModel: ObservableObject {
Defaults[.instances] Defaults[.instances]
} }
static var forPlayer: Instance? {
guard let id = Defaults[.playerInstanceID] else {
return nil
}
return InstancesModel.find(id)
}
var lastUsed: Instance? { var lastUsed: Instance? {
guard let id = Defaults[.lastInstanceID] else { guard let id = Defaults[.lastInstanceID] else {
return nil return nil

View File

@ -27,15 +27,13 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
self.account = account self.account = account
signedIn = false signedIn = false
if account.anonymous { validInstance = account.anonymous
validInstance = true
return
}
validInstance = false
configure() configure()
validate()
if !account.anonymous {
validate()
}
} }
func validate() { func validate() {

View File

@ -26,7 +26,7 @@ final class PlayerModel: ObservableObject {
@Published var stream: Stream? @Published var stream: Stream?
@Published var currentRate: Float = 1.0 { didSet { player.rate = currentRate } } @Published var currentRate: Float = 1.0 { didSet { player.rate = currentRate } }
@Published var availableStreams = [Stream]() { didSet { rebuildTVMenu() } } @Published var availableStreams = [Stream]() { didSet { handleAvailableStreamsChange() }}
@Published var streamSelection: Stream? { didSet { rebuildTVMenu() } } @Published var streamSelection: Stream? { didSet { rebuildTVMenu() } }
@Published var queue = [PlayerQueueItem]() { didSet { Defaults[.queue] = queue } } @Published var queue = [PlayerQueueItem]() { didSet { Defaults[.queue] = queue } }
@ -171,10 +171,24 @@ final class PlayerModel: ObservableObject {
} }
} }
private func pauseOnPlayerDismiss() { private func handleAvailableStreamsChange() {
if !playingInPictureInPicture, !presentingPlayer { rebuildTVMenu()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.pause() guard stream.isNil else {
return
}
guard let stream = preferredStream(availableStreams) else {
return
}
streamSelection = stream
playStream(
stream,
of: currentVideo!,
preservingTime: !currentItem.playbackTime.isNil
)
}
} }
} }
} }

View File

@ -54,21 +54,10 @@ extension PlayerModel {
preservedTime = currentItem.playbackTime preservedTime = currentItem.playbackTime
restoreLoadedChannel() restoreLoadedChannel()
loadAvailableStreams(currentVideo!) { streams in loadAvailableStreams(currentVideo!)
guard let stream = self.preferredStream(streams) else {
return
}
self.streamSelection = stream
self.playStream(
stream,
of: self.currentVideo!,
preservingTime: !self.currentItem.playbackTime.isNil
)
}
} }
private func preferredStream(_ streams: [Stream]) -> Stream? { func preferredStream(_ streams: [Stream]) -> Stream? {
let quality = Defaults[.quality] let quality = Defaults[.quality]
var streams = streams var streams = streams

View File

@ -15,21 +15,20 @@ extension PlayerModel {
availableStreams.sorted(by: streamsSorter) availableStreams.sorted(by: streamsSorter)
} }
func loadAvailableStreams( func loadAvailableStreams(_ video: Video) {
_ video: Video,
completionHandler: @escaping ([Stream]) -> Void = { _ in }
) {
availableStreams = [] availableStreams = []
var instancesWithLoadedStreams = [Instance]() let playerInstance = InstancesModel.forPlayer ?? InstancesModel.all.first
InstancesModel.all.forEach { instance in guard !playerInstance.isNil else {
fetchStreams(instance.anonymous.video(video.videoID), instance: instance, video: video) { _ in return
self.completeIfAllInstancesLoaded( }
instance: instance,
streams: self.availableStreams, logger.info("loading streams from \(playerInstance!.description)")
instancesWithLoadedStreams: &instancesWithLoadedStreams,
completionHandler: completionHandler fetchStreams(playerInstance!.anonymous.video(video.videoID), instance: playerInstance!, video: video) { _ in
) InstancesModel.all.filter { $0 != playerInstance }.forEach { instance in
self.logger.info("loading streams from \(instance.description)")
self.fetchStreams(instance.anonymous.video(video.videoID), instance: instance, video: video)
} }
} }
} }
@ -45,25 +44,13 @@ extension PlayerModel {
.onSuccess { response in .onSuccess { response in
if let video: Video = response.typedContent() { if let video: Video = response.typedContent() {
self.availableStreams += self.streamsWithInstance(instance: instance, streams: video.streams) self.availableStreams += self.streamsWithInstance(instance: instance, streams: video.streams)
} else {
self.logger.critical("no streams available from \(instance.description)")
} }
} }
.onCompletion(onCompletion) .onCompletion(onCompletion)
} }
private func completeIfAllInstancesLoaded(
instance: Instance,
streams: [Stream],
instancesWithLoadedStreams: inout [Instance],
completionHandler: @escaping ([Stream]) -> Void
) {
instancesWithLoadedStreams.append(instance)
rebuildTVMenu()
if InstancesModel.all.count == instancesWithLoadedStreams.count {
completionHandler(streams.sorted { $0.kind < $1.kind })
}
}
func streamsWithInstance(instance: Instance, streams: [Stream]) -> [Stream] { func streamsWithInstance(instance: Instance, streams: [Stream]) -> [Stream] {
streams.map { stream in streams.map { stream in
stream.instance = instance stream.instance = instance