From 0d1eaaca5c51eb1ae0c6fd79b9679cc086b32d45 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sun, 17 Oct 2021 23:49:56 +0200 Subject: [PATCH] Add tvOS streams selection --- Model/Instance.swift | 8 ++++---- Model/InvidiousAPI.swift | 1 + Model/PlayerStreams.swift | 8 ++++++++ Shared/Navigation/ContentView.swift | 6 ++++-- Shared/Player/PlaybackBar.swift | 6 +----- Shared/Player/Player.swift | 31 ++++++++++++++++++++++++++++- Shared/Watch Now/WatchNowView.swift | 1 + 7 files changed, 49 insertions(+), 12 deletions(-) diff --git a/Model/Instance.swift b/Model/Instance.swift index afbebde8..4ba539cb 100644 --- a/Model/Instance.swift +++ b/Model/Instance.swift @@ -20,13 +20,13 @@ struct Instance: Defaults.Serializable, Hashable, Identifiable { let sid: String let anonymous: Bool - init(id: String? = nil, instanceID: UUID, name: String? = nil, url: String, sid: String? = nil, anonymous: Bool = false) { + init(id: String? = nil, instanceID: UUID? = nil, name: String? = nil, url: String? = nil, sid: String? = nil, anonymous: Bool = false) { self.anonymous = anonymous - self.id = id ?? (anonymous ? "anonymous-\(instanceID)" : UUID().uuidString) - self.instanceID = instanceID + self.id = id ?? (anonymous ? "anonymous-\(instanceID!)" : UUID().uuidString) + self.instanceID = instanceID ?? UUID() self.name = name - self.url = url + self.url = url ?? "" self.sid = sid ?? "" } diff --git a/Model/InvidiousAPI.swift b/Model/InvidiousAPI.swift index 27be1b7f..5695eb7f 100644 --- a/Model/InvidiousAPI.swift +++ b/Model/InvidiousAPI.swift @@ -15,6 +15,7 @@ final class InvidiousAPI: Service, ObservableObject { super.init() guard !account.isNil else { + self.account = .init(name: "Empty") return } diff --git a/Model/PlayerStreams.swift b/Model/PlayerStreams.swift index 7bfa7e00..a8d6fd07 100644 --- a/Model/PlayerStreams.swift +++ b/Model/PlayerStreams.swift @@ -10,6 +10,10 @@ extension PlayerModel { !stream.isNil && stream != streamSelection } + var availableStreamsSorted: [Stream] { + availableStreams.sorted(by: streamsSorter) + } + func loadAvailableStreams( _ video: Video, completionHandler: @escaping ([Stream]) -> Void = { _ in } @@ -97,4 +101,8 @@ extension PlayerModel { func streamsWithAssetsFromInstance(instance: Instance, streams: [Stream]) -> [Stream] { streams.map { stream in stream.withAssetsFrom(instance) } } + + func streamsSorter(_ lhs: Stream, _ rhs: Stream) -> Bool { + lhs.kind == rhs.kind ? (lhs.resolution.height > rhs.resolution.height) : (lhs.kind < rhs.kind) + } } diff --git a/Shared/Navigation/ContentView.swift b/Shared/Navigation/ContentView.swift index d20820fd..80233258 100644 --- a/Shared/Navigation/ContentView.swift +++ b/Shared/Navigation/ContentView.swift @@ -78,10 +78,12 @@ struct ContentView: View { func configure() { SiestaLog.Category.enabled = .common - if let account = instances.defaultAccount { + if let account = instances.defaultAccount ?? + // TODO: Remove when piped supports videos information + accounts.all.first(where: { $0.instance.app == .invidious }) + { accounts.setAccount(account) } - player.accounts = accounts playlists.accounts = accounts search.accounts = accounts diff --git a/Shared/Player/PlaybackBar.swift b/Shared/Player/PlaybackBar.swift index 6bb5a4fa..102bcfba 100644 --- a/Shared/Player/PlaybackBar.swift +++ b/Shared/Player/PlaybackBar.swift @@ -139,14 +139,10 @@ struct PlaybackBar: View { } private func availableStreamsForInstance(_ instance: Instance) -> [Stream.Kind: [Stream]] { - let streams = player.availableStreams.filter { $0.instance == instance }.sorted(by: streamsSorter) + let streams = player.availableStreams.filter { $0.instance == instance }.sorted(by: player.streamsSorter) return Dictionary(grouping: streams, by: \.kind!) } - - private func streamsSorter(_ lhs: Stream, _ rhs: Stream) -> Bool { - lhs.kind == rhs.kind ? (lhs.resolution.height > rhs.resolution.height) : (lhs.kind < rhs.kind) - } } struct PlaybackBar_Previews: PreviewProvider { diff --git a/Shared/Player/Player.swift b/Shared/Player/Player.swift index 7b30c440..325c89a8 100644 --- a/Shared/Player/Player.swift +++ b/Shared/Player/Player.swift @@ -20,8 +20,37 @@ struct Player: UIViewControllerRepresentable { controller.playerModel = player player.controller = controller + #if os(tvOS) + player.controller?.playerViewController.transportBarCustomMenuItems = [streamingQualityMenu] + #endif + return controller } - func updateUIViewController(_: PlayerViewController, context _: Context) {} + func updateUIViewController(_: PlayerViewController, context _: Context) { + #if os(tvOS) + player.controller?.playerViewController.transportBarCustomMenuItems = [streamingQualityMenu] + #endif + } + + #if os(tvOS) + var streamingQualityMenu: UIMenu { + UIMenu( + title: "Streaming quality", + image: UIImage(systemName: "antenna.radiowaves.left.and.right"), + children: streamingQualityMenuActions + ) + } + + var streamingQualityMenuActions: [UIAction] { + player.availableStreamsSorted.map { stream in + let image = player.streamSelection == stream ? UIImage(systemName: "checkmark") : nil + + return UIAction(title: stream.description, image: image) { _ in + self.player.streamSelection = stream + self.player.upgradeToStream(stream) + } + } + } + #endif } diff --git a/Shared/Watch Now/WatchNowView.swift b/Shared/Watch Now/WatchNowView.swift index 2e6d322d..b8e4d12b 100644 --- a/Shared/Watch Now/WatchNowView.swift +++ b/Shared/Watch Now/WatchNowView.swift @@ -29,6 +29,7 @@ struct WatchNowView: View { } } } + .id(UUID()) #if os(tvOS) .edgesIgnoringSafeArea(.horizontal) #else