From 13f457f52ada2081e36b558a47a30afadd8bf2d8 Mon Sep 17 00:00:00 2001 From: Ethan Pippin Date: Sat, 15 Jan 2022 13:01:42 -0700 Subject: [PATCH] allow force direct play as a temporary measure --- .../BaseItemDto+VideoPlayerViewModel.swift | 29 +++++++++++-------- .../SwiftfinStore/SwiftfinStoreDefaults.swift | 1 + .../VideoPlayerViewModel.swift | 13 +++++---- .../ExperimentalSettingsView.swift | 4 +++ .../VideoPlayer/VLCPlayerViewController.swift | 19 +++++++++++- .../tvOSOverlay/tvOSVLCOverlay.swift | 3 +- .../ExperimentalSettingsView.swift | 4 +++ .../VideoPlayer/VLCPlayerOverlayView.swift | 3 +- .../VideoPlayer/VLCPlayerViewController.swift | 20 +++++++++---- 9 files changed, 71 insertions(+), 25 deletions(-) diff --git a/Shared/Extensions/JellyfinAPIExtensions/BaseItemDto+VideoPlayerViewModel.swift b/Shared/Extensions/JellyfinAPIExtensions/BaseItemDto+VideoPlayerViewModel.swift index 1253e8d7..a619bf9c 100644 --- a/Shared/Extensions/JellyfinAPIExtensions/BaseItemDto+VideoPlayerViewModel.swift +++ b/Shared/Extensions/JellyfinAPIExtensions/BaseItemDto+VideoPlayerViewModel.swift @@ -48,24 +48,28 @@ extension BaseItemDto { let defaultSubtitleStream = subtitleStreams .first(where: { $0.index! == currentMediaSource.defaultSubtitleStreamIndex ?? -1 }) - var streamURL: URLComponents + var directStreamURL: URLComponents + let transcodedStreamURL: URLComponents? let streamType: ServerStreamType if let transcodeURL = currentMediaSource.transcodingUrl { streamType = .transcode - streamURL = URLComponents(string: SessionManager.main.currentLogin.server.currentURI.appending(transcodeURL))! + transcodedStreamURL = URLComponents(string: SessionManager.main.currentLogin.server.currentURI + .appending(transcodeURL))! } else { streamType = .direct - streamURL = URLComponents(string: SessionManager.main.currentLogin.server.currentURI)! - streamURL.path = "/Videos/\(self.id!)/stream" - streamURL.addQueryItem(name: "Static", value: "true") - streamURL.addQueryItem(name: "MediaSourceId", value: self.id!) - streamURL.addQueryItem(name: "Tag", value: self.etag) - streamURL.addQueryItem(name: "MinSegments", value: "6") + transcodedStreamURL = nil + } - if mediaSources.count > 1 { - streamURL.addQueryItem(name: "MediaSourceId", value: currentMediaSource.id) - } + directStreamURL = URLComponents(string: SessionManager.main.currentLogin.server.currentURI)! + directStreamURL.path = "/Videos/\(self.id!)/stream" + directStreamURL.addQueryItem(name: "Static", value: "true") + directStreamURL.addQueryItem(name: "MediaSourceId", value: self.id!) + directStreamURL.addQueryItem(name: "Tag", value: self.etag) + directStreamURL.addQueryItem(name: "MinSegments", value: "6") + + if mediaSources.count > 1 { + directStreamURL.addQueryItem(name: "MediaSourceId", value: currentMediaSource.id) } // MARK: VidoPlayerViewModel Creation @@ -102,7 +106,8 @@ extension BaseItemDto { let videoPlayerViewModel = VideoPlayerViewModel(item: modifiedSelfItem, title: modifiedSelfItem.name ?? "", subtitle: subtitle, - streamURL: streamURL.url!, + directStreamURL: directStreamURL.url!, + transcodedStreamURL: transcodedStreamURL?.url, streamType: streamType, response: response, audioStreams: audioStreams, diff --git a/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift b/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift index 5a50a736..35bfa228 100644 --- a/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift +++ b/Shared/SwiftfinStore/SwiftfinStoreDefaults.swift @@ -70,6 +70,7 @@ extension Defaults.Keys { enum Experimental { static let syncSubtitleStateWithAdjacent = Key("experimental.syncSubtitleState", default: false, suite: SwiftfinStore.Defaults.generalSuite) + static let forceDirectPlay = Key("forceDirectPlay", default: false, suite: SwiftfinStore.Defaults.generalSuite) static let liveTVAlphaEnabled = Key("liveTVAlphaEnabled", default: false, suite: SwiftfinStore.Defaults.generalSuite) } diff --git a/Shared/ViewModels/VideoPlayerViewModel/VideoPlayerViewModel.swift b/Shared/ViewModels/VideoPlayerViewModel/VideoPlayerViewModel.swift index 25b48078..c23d6fe0 100644 --- a/Shared/ViewModels/VideoPlayerViewModel/VideoPlayerViewModel.swift +++ b/Shared/ViewModels/VideoPlayerViewModel/VideoPlayerViewModel.swift @@ -106,7 +106,8 @@ final class VideoPlayerViewModel: ViewModel { private(set) var item: BaseItemDto let title: String let subtitle: String? - let streamURL: URL + let directStreamURL: URL + let transcodedStreamURL: URL? let audioStreams: [MediaStream] let subtitleStreams: [MediaStream] let overlayType: OverlayType @@ -167,7 +168,8 @@ final class VideoPlayerViewModel: ViewModel { init(item: BaseItemDto, title: String, subtitle: String?, - streamURL: URL, + directStreamURL: URL, + transcodedStreamURL: URL?, streamType: ServerStreamType, response: PlaybackInfoResponse, audioStreams: [MediaStream], @@ -187,7 +189,8 @@ final class VideoPlayerViewModel: ViewModel { self.item = item self.title = title self.subtitle = subtitle - self.streamURL = streamURL + self.directStreamURL = directStreamURL + self.transcodedStreamURL = transcodedStreamURL self.streamType = streamType self.response = response self.audioStreams = audioStreams @@ -561,7 +564,7 @@ extension VideoPlayerViewModel { func createEmbeddedSubtitleStream(with subtitleStream: MediaStream) -> URL { - guard let baseURL = URLComponents(url: streamURL, resolvingAgainstBaseURL: false) else { fatalError() } + guard let baseURL = URLComponents(url: directStreamURL, resolvingAgainstBaseURL: false) else { fatalError() } guard let queryItems = baseURL.queryItems else { fatalError() } var newURL = baseURL @@ -593,7 +596,7 @@ extension VideoPlayerViewModel: Hashable { func hash(into hasher: inout Hasher) { hasher.combine(item) - hasher.combine(streamURL) + hasher.combine(directStreamURL) hasher.combine(filename) hasher.combine(versionName) } diff --git a/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift b/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift index 2c466f2a..b53b52aa 100644 --- a/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift +++ b/Swiftfin tvOS/Views/SettingsView/ExperimentalSettingsView.swift @@ -11,6 +11,8 @@ import SwiftUI struct ExperimentalSettingsView: View { + @Default(.Experimental.forceDirectPlay) + var forceDirectPlay @Default(.Experimental.syncSubtitleStateWithAdjacent) var syncSubtitleStateWithAdjacent @Default(.Experimental.liveTVAlphaEnabled) @@ -20,6 +22,8 @@ struct ExperimentalSettingsView: View { Form { Section { + Toggle("Force Direct Play", isOn: $forceDirectPlay) + Toggle("Sync Subtitles with Adjacent Episodes", isOn: $syncSubtitleStateWithAdjacent) Toggle("Live TV (Alpha)", isOn: $liveTVAlphaEnabled) diff --git a/Swiftfin tvOS/Views/VideoPlayer/VLCPlayerViewController.swift b/Swiftfin tvOS/Views/VideoPlayer/VLCPlayerViewController.swift index 97809fe0..07a82b2a 100644 --- a/Swiftfin tvOS/Views/VideoPlayer/VLCPlayerViewController.swift +++ b/Swiftfin tvOS/Views/VideoPlayer/VLCPlayerViewController.swift @@ -425,7 +425,16 @@ extension VLCPlayerViewController { // TODO: Custom buffer/cache amounts - let media = VLCMedia(url: newViewModel.streamURL) + let media: VLCMedia + + if let transcodedURL = newViewModel.transcodedStreamURL, + !Defaults[.Experimental.forceDirectPlay] + { + media = VLCMedia(url: transcodedURL) + } else { + media = VLCMedia(url: newViewModel.directStreamURL) + } + media.addOption("--prefetch-buffer-size=1048576") media.addOption("--network-caching=5000") @@ -452,6 +461,14 @@ extension VLCPlayerViewController { } viewModel = newViewModel + + if viewModel.streamType == .direct { + LogManager.shared.log.debug("Player set up with direct play stream for item: \(viewModel.item.id ?? "--")") + } else if viewModel.streamType == .transcode && Defaults[.Experimental.forceDirectPlay] { + LogManager.shared.log.debug("Player set up with forced direct stream for item: \(viewModel.item.id ?? "--")") + } else { + LogManager.shared.log.debug("Player set up with transcoded stream for item: \(viewModel.item.id ?? "--")") + } } // MARK: startPlayback diff --git a/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/tvOSVLCOverlay.swift b/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/tvOSVLCOverlay.swift index 0aad1deb..64eac230 100644 --- a/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/tvOSVLCOverlay.swift +++ b/Swiftfin tvOS/Views/VideoPlayer/tvOSOverlay/tvOSVLCOverlay.swift @@ -141,7 +141,8 @@ struct tvOSVLCOverlay_Previews: PreviewProvider { static let videoPlayerViewModel = VideoPlayerViewModel(item: BaseItemDto(), title: "Glorious Purpose", subtitle: "Loki - S1E1", - streamURL: URL(string: "www.apple.com")!, + directStreamURL: URL(string: "www.apple.com")!, + transcodedStreamURL: nil, streamType: .direct, response: PlaybackInfoResponse(), audioStreams: [MediaStream(displayTitle: "English", index: -1)], diff --git a/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift b/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift index 81901b82..271cb887 100644 --- a/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift +++ b/Swiftfin/Views/SettingsView/ExperimentalSettingsView.swift @@ -11,6 +11,8 @@ import SwiftUI struct ExperimentalSettingsView: View { + @Default(.Experimental.forceDirectPlay) + var forceDirectPlay @Default(.Experimental.syncSubtitleStateWithAdjacent) var syncSubtitleStateWithAdjacent @@ -18,6 +20,8 @@ struct ExperimentalSettingsView: View { Form { Section { + Toggle("Force Direct Play", isOn: $forceDirectPlay) + Toggle("Sync Subtitles with Adjacent Episodes", isOn: $syncSubtitleStateWithAdjacent) } header: { diff --git a/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift b/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift index 66c94fa9..9a969078 100644 --- a/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift +++ b/Swiftfin/Views/VideoPlayer/VLCPlayerOverlayView.swift @@ -383,7 +383,8 @@ struct VLCPlayerCompactOverlayView_Previews: PreviewProvider { static let videoPlayerViewModel = VideoPlayerViewModel(item: BaseItemDto(), title: "Glorious Purpose", subtitle: "Loki - S1E1", - streamURL: URL(string: "www.apple.com")!, + directStreamURL: URL(string: "www.apple.com")!, + transcodedStreamURL: nil, streamType: .direct, response: PlaybackInfoResponse(), audioStreams: [MediaStream(displayTitle: "English", index: -1)], diff --git a/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift b/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift index ca36f1df..5af087db 100644 --- a/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift +++ b/Swiftfin/Views/VideoPlayer/VLCPlayerViewController.swift @@ -316,7 +316,16 @@ extension VLCPlayerViewController { lastPlayerTicks = newViewModel.item.userData?.playbackPositionTicks ?? 0 lastProgressReportTicks = newViewModel.item.userData?.playbackPositionTicks ?? 0 - let media = VLCMedia(url: newViewModel.streamURL) + let media: VLCMedia + + if let transcodedURL = newViewModel.transcodedStreamURL, + !Defaults[.Experimental.forceDirectPlay] + { + media = VLCMedia(url: transcodedURL) + } else { + media = VLCMedia(url: newViewModel.directStreamURL) + } + media.addOption("--prefetch-buffer-size=1048576") media.addOption("--network-caching=5000") @@ -344,11 +353,12 @@ extension VLCPlayerViewController { viewModel = newViewModel - switch viewModel.streamType { - case .transcode: - LogManager.shared.log.debug("Player set up with transcoded stream for item: \(viewModel.item.id ?? "--")") - case .direct: + if viewModel.streamType == .direct { LogManager.shared.log.debug("Player set up with direct play stream for item: \(viewModel.item.id ?? "--")") + } else if viewModel.streamType == .transcode && Defaults[.Experimental.forceDirectPlay] { + LogManager.shared.log.debug("Player set up with forced direct stream for item: \(viewModel.item.id ?? "--")") + } else { + LogManager.shared.log.debug("Player set up with transcoded stream for item: \(viewModel.item.id ?? "--")") } }