Merge pull request #267 from LePips/final-work-for-winter-break-2022
Some polishing
This commit is contained in:
commit
fa28b4019b
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
/*
|
||||
* SwiftFin is subject to the terms of the Mozilla Public
|
||||
* License, v2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
||||
*/
|
||||
|
||||
import Foundation
|
||||
import JellyfinAPI
|
||||
|
||||
extension MediaStream {
|
||||
|
||||
func externalURL(base: String) -> URL? {
|
||||
guard let deliveryURL = deliveryUrl else { return nil }
|
||||
var baseComponents = URLComponents(string: base)
|
||||
baseComponents?.path += deliveryURL
|
||||
|
||||
return baseComponents?.url
|
||||
}
|
||||
}
|
|
@ -67,6 +67,8 @@ final class VideoPlayerViewModel: ViewModel {
|
|||
}
|
||||
@Published var autoplayEnabled: Bool {
|
||||
willSet {
|
||||
previousItemVideoPlayerViewModel?.autoplayEnabled = newValue
|
||||
nextItemVideoPlayerViewModel?.autoplayEnabled = newValue
|
||||
Defaults[.autoplayEnabled] = newValue
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +117,16 @@ final class VideoPlayerViewModel: ViewModel {
|
|||
return Int64(currentSeconds) * 10_000_000
|
||||
}
|
||||
|
||||
// MARK: Helpers
|
||||
|
||||
var currentAudioStream: MediaStream? {
|
||||
return audioStreams.first(where: { $0.index == selectedAudioStreamIndex })
|
||||
}
|
||||
|
||||
var currentSubtitleStream: MediaStream? {
|
||||
return subtitleStreams.first(where: { $0.index == selectedSubtitleStreamIndex })
|
||||
}
|
||||
|
||||
// Necessary PassthroughSubject to capture manual scrubbing from sliders
|
||||
let sliderScrubbingSubject = PassthroughSubject<VideoPlayerViewModel, Never>()
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
||||
*/
|
||||
|
||||
import CachedAsyncImage
|
||||
import SwiftUI
|
||||
|
||||
struct ImageView: View {
|
||||
|
@ -31,7 +32,7 @@ struct ImageView: View {
|
|||
private var failureImage: some View {
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.foregroundColor(Color.systemFill)
|
||||
.foregroundColor(Color(UIColor.darkGray))
|
||||
|
||||
Text(failureInitials)
|
||||
.font(.largeTitle)
|
||||
|
@ -40,21 +41,36 @@ struct ImageView: View {
|
|||
}
|
||||
|
||||
var body: some View {
|
||||
AsyncImage(url: source) { phase in
|
||||
if let image = phase.image {
|
||||
CachedAsyncImage(url: source, urlCache: .imageCache, transaction: Transaction(animation: .easeInOut)) { phase in
|
||||
switch phase {
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
} else if phase.error != nil {
|
||||
case .failure(_):
|
||||
failureImage
|
||||
} else {
|
||||
default:
|
||||
// TODO: remove once placeholder hash image fixed
|
||||
|
||||
#if os(tvOS)
|
||||
ZStack {
|
||||
Color.gray.ignoresSafeArea()
|
||||
|
||||
Color.black.ignoresSafeArea()
|
||||
|
||||
ProgressView()
|
||||
}
|
||||
#else
|
||||
ZStack {
|
||||
Color.gray.ignoresSafeArea()
|
||||
|
||||
ProgressView()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension URLCache {
|
||||
|
||||
static let imageCache = URLCache(memoryCapacity: 512*1000*1000, diskCapacity: 10*1000*1000*1000)
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ struct EpisodesRowView: View {
|
|||
HStack(alignment: .top) {
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
ImageView(src: episode.getBackdropImage(maxWidth: 445),
|
||||
ImageView(src: episode.getBackdropImage(maxWidth: 500),
|
||||
bh: episode.getBackdropImageBlurHash())
|
||||
.mask(Rectangle().frame(width: 500, height: 280))
|
||||
.frame(width: 500, height: 280)
|
||||
|
|
|
@ -22,8 +22,13 @@ struct ContinueWatchingCard: View {
|
|||
} label: {
|
||||
ZStack(alignment: .bottom) {
|
||||
|
||||
ImageView(src: item.getBackdropImage(maxWidth: 500))
|
||||
.frame(width: 500, height: 281.25)
|
||||
if item.itemType == .episode {
|
||||
ImageView(src: item.getSeriesBackdropImage(maxWidth: 500))
|
||||
.frame(width: 500, height: 281.25)
|
||||
} else {
|
||||
ImageView(src: item.getBackdropImage(maxWidth: 500))
|
||||
.frame(width: 500, height: 281.25)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
Text(item.getItemProgressString() ?? "")
|
||||
|
@ -57,6 +62,7 @@ struct ContinueWatchingCard: View {
|
|||
.fontWeight(.semibold)
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(1)
|
||||
.frame(width: 500, alignment: .leading)
|
||||
|
||||
if item.itemType == .episode {
|
||||
Text(item.getEpisodeLocator() ?? "")
|
||||
|
@ -64,8 +70,11 @@ struct ContinueWatchingCard: View {
|
|||
.fontWeight(.medium)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
Text("")
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.vertical)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ struct ContinueWatchingView: View {
|
|||
.padding(.leading, 50)
|
||||
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
LazyHStack {
|
||||
LazyHStack(alignment: .top) {
|
||||
ForEach(items, id: \.self) { item in
|
||||
ContinueWatchingCard(item: item)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ struct CinematicEpisodeItemView: View {
|
|||
|
||||
ImageView(src: viewModel.item.getBackdropImage(maxWidth: 1920),
|
||||
bh: viewModel.item.getBackdropImageBlurHash())
|
||||
.frame(height: UIScreen.main.bounds.height - 10)
|
||||
.ignoresSafeArea()
|
||||
|
||||
ScrollView {
|
||||
|
|
|
@ -16,10 +16,60 @@ struct LatestMediaView: View {
|
|||
@Default(.showPosterLabels) var showPosterLabels
|
||||
|
||||
var body: some View {
|
||||
PortraitItemsRowView(rowTitle: L10n.latestWithString(viewModel.library.name ?? ""),
|
||||
items: viewModel.items,
|
||||
showItemTitles: showPosterLabels) { item in
|
||||
homeRouter.route(to: \.modalItem, item)
|
||||
VStack(alignment: .leading) {
|
||||
|
||||
L10n.latestWithString(viewModel.library.name ?? "").text
|
||||
.font(.title3)
|
||||
.padding(.horizontal, 50)
|
||||
|
||||
ScrollView(.horizontal) {
|
||||
HStack(alignment: .top) {
|
||||
ForEach(viewModel.items, id: \.self) { item in
|
||||
|
||||
VStack(spacing: 15) {
|
||||
Button {
|
||||
homeRouter.route(to: \.modalItem, item)
|
||||
} label: {
|
||||
ImageView(src: item.portraitHeaderViewURL(maxWidth: 257))
|
||||
.frame(width: 257, height: 380)
|
||||
}
|
||||
.frame(height: 380)
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
|
||||
if showPosterLabels {
|
||||
Text(item.title)
|
||||
.lineLimit(2)
|
||||
.frame(width: 257)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
homeRouter.route(to: \.library, (viewModel: .init(parentID: viewModel.library.id!,
|
||||
filters: LibraryFilters(filters: [], sortOrder: [.descending], sortBy: [.dateAdded])),
|
||||
title: viewModel.library.name ?? ""))
|
||||
} label: {
|
||||
ZStack {
|
||||
Color(UIColor.darkGray)
|
||||
.opacity(0.5)
|
||||
|
||||
VStack(spacing: 20) {
|
||||
Image(systemName: "chevron.right")
|
||||
.font(.title)
|
||||
|
||||
L10n.seeAll.text
|
||||
.font(.title3)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(width: 257, height: 380)
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
.padding(.horizontal, 50)
|
||||
.padding(.vertical)
|
||||
}
|
||||
.edgesIgnoringSafeArea(.horizontal)
|
||||
}
|
||||
.focusSection()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,13 @@ struct NextUpCard: View {
|
|||
Button {
|
||||
homeRouter.route(to: \.modalItem, item)
|
||||
} label: {
|
||||
ImageView(src: item.getBackdropImage(maxWidth: 500))
|
||||
.frame(width: 500, height: 281.25)
|
||||
if item.itemType == .episode {
|
||||
ImageView(src: item.getSeriesBackdropImage(maxWidth: 500))
|
||||
.frame(width: 500, height: 281.25)
|
||||
} else {
|
||||
ImageView(src: item.getBackdropImage(maxWidth: 500))
|
||||
.frame(width: 500, height: 281.25)
|
||||
}
|
||||
}
|
||||
.buttonStyle(CardButtonStyle())
|
||||
.padding(.top)
|
||||
|
|
|
@ -24,7 +24,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
// MARK: variables
|
||||
|
||||
private var viewModel: VideoPlayerViewModel
|
||||
private var vlcMediaPlayer = VLCMediaPlayer()
|
||||
private var vlcMediaPlayer: VLCMediaPlayer
|
||||
private var lastPlayerTicks: Int64 = 0
|
||||
private var lastProgressReportTicks: Int64 = 0
|
||||
private var viewModelListeners = Set<AnyCancellable>()
|
||||
|
@ -59,6 +59,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
init(viewModel: VideoPlayerViewModel) {
|
||||
|
||||
self.viewModel = viewModel
|
||||
self.vlcMediaPlayer = VLCMediaPlayer()
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
|
@ -118,14 +119,6 @@ class VLCPlayerViewController: UIViewController {
|
|||
|
||||
view.backgroundColor = .black
|
||||
|
||||
// Outside of 'setupMediaPlayer' such that they
|
||||
// aren't unnecessarily set more than once
|
||||
vlcMediaPlayer.delegate = self
|
||||
vlcMediaPlayer.drawable = videoContentView
|
||||
|
||||
// TODO: custom font sizes
|
||||
vlcMediaPlayer.perform(Selector(("setTextRendererFontSize:")), with: 16)
|
||||
|
||||
setupMediaPlayer(newViewModel: viewModel)
|
||||
|
||||
setupPanGestureRecognizer()
|
||||
|
@ -211,20 +204,20 @@ class VLCPlayerViewController: UIViewController {
|
|||
hideConfirmCloseOverlay()
|
||||
|
||||
if Defaults[.downActionShowsMenu] {
|
||||
if !displayingContentOverlay {
|
||||
if !displayingContentOverlay && !displayingOverlay {
|
||||
didSelectMenu()
|
||||
}
|
||||
}
|
||||
case .leftArrow:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
if !displayingContentOverlay {
|
||||
if !displayingContentOverlay && !displayingOverlay {
|
||||
didSelectBackward()
|
||||
}
|
||||
case .rightArrow:
|
||||
hideConfirmCloseOverlay()
|
||||
|
||||
if !displayingContentOverlay {
|
||||
if !displayingContentOverlay && !displayingOverlay {
|
||||
didSelectForward()
|
||||
}
|
||||
case .pageUp: ()
|
||||
|
@ -246,9 +239,6 @@ class VLCPlayerViewController: UIViewController {
|
|||
hideOverlay()
|
||||
} else if displayingContentOverlay {
|
||||
hideOverlayContent()
|
||||
|
||||
showOverlay()
|
||||
restartOverlayDismissTimer()
|
||||
} else if viewModel.confirmClose && !displayingConfirmClose {
|
||||
|
||||
showConfirmCloseOverlay()
|
||||
|
@ -387,6 +377,28 @@ extension VLCPlayerViewController {
|
|||
/// Use case for this is setting new media within the same VLCPlayerViewController
|
||||
func setupMediaPlayer(newViewModel: VideoPlayerViewModel) {
|
||||
|
||||
// remove old player
|
||||
|
||||
if vlcMediaPlayer.media != nil {
|
||||
viewModelListeners.forEach({ $0.cancel() })
|
||||
|
||||
vlcMediaPlayer.stop()
|
||||
viewModel.sendStopReport()
|
||||
viewModel.playerOverlayDelegate = nil
|
||||
}
|
||||
|
||||
vlcMediaPlayer = VLCMediaPlayer()
|
||||
|
||||
// setup with new player and view model
|
||||
|
||||
vlcMediaPlayer = VLCMediaPlayer()
|
||||
|
||||
vlcMediaPlayer.delegate = self
|
||||
vlcMediaPlayer.drawable = videoContentView
|
||||
|
||||
// TODO: Custom subtitle sizes
|
||||
vlcMediaPlayer.perform(Selector(("setTextRendererFontSize:")), with: 16)
|
||||
|
||||
stopOverlayDismissTimer()
|
||||
|
||||
// Stop current media if there is one
|
||||
|
@ -436,6 +448,13 @@ extension VLCPlayerViewController {
|
|||
func startPlayback() {
|
||||
vlcMediaPlayer.play()
|
||||
|
||||
// Setup external subtitles
|
||||
for externalSubtitle in viewModel.subtitleStreams.filter({ $0.deliveryMethod == .external }) {
|
||||
if let deliveryURL = externalSubtitle.externalURL(base: SessionManager.main.currentLogin.server.currentURI) {
|
||||
vlcMediaPlayer.addPlaybackSlave(deliveryURL, type: .subtitle, enforce: false)
|
||||
}
|
||||
}
|
||||
|
||||
setMediaPlayerTimeAtCurrentSlider()
|
||||
|
||||
viewModel.sendPlayReport()
|
||||
|
@ -672,7 +691,8 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate {
|
|||
}
|
||||
|
||||
// If needing to fix subtitle streams during playback
|
||||
if vlcMediaPlayer.currentVideoSubTitleIndex != viewModel.selectedSubtitleStreamIndex && viewModel.subtitlesEnabled {
|
||||
if vlcMediaPlayer.currentVideoSubTitleIndex != viewModel.selectedSubtitleStreamIndex &&
|
||||
viewModel.subtitlesEnabled {
|
||||
didSelectSubtitleStream(index: viewModel.selectedSubtitleStreamIndex)
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ struct tvOSVLCOverlay: View {
|
|||
if let subtitle = viewModel.subtitle {
|
||||
Text(subtitle)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.lightGray)
|
||||
.foregroundColor(.white)
|
||||
}
|
||||
|
||||
Text(viewModel.title)
|
||||
|
|
|
@ -527,12 +527,14 @@ public final class TvOSSlider: UIControl {
|
|||
|
||||
@objc
|
||||
private func leftTapWasTriggered() {
|
||||
setValue(value-stepValue, animated: true)
|
||||
// setValue(value-stepValue, animated: true)
|
||||
viewModel.playerOverlayDelegate?.didSelectBackward()
|
||||
}
|
||||
|
||||
@objc
|
||||
private func rightTapWasTriggered() {
|
||||
setValue(value+stepValue, animated: true)
|
||||
// setValue(value+stepValue, animated: true)
|
||||
viewModel.playerOverlayDelegate?.didSelectForward()
|
||||
}
|
||||
|
||||
public override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
|
||||
|
|
|
@ -270,10 +270,9 @@
|
|||
E11D224227378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */; };
|
||||
E11D224327378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */; };
|
||||
E12186DE2718F1C50010884C /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = E12186DD2718F1C50010884C /* Defaults */; };
|
||||
E1218C9A271A26BA00EA0737 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1218C99271A26BA00EA0737 /* Nuke */; };
|
||||
E1218C9C271A26C400EA0737 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1218C9B271A26C400EA0737 /* Nuke */; };
|
||||
E1218C9E271A2CD600EA0737 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = E1218C9D271A2CD600EA0737 /* CombineExt */; };
|
||||
E1218CA0271A2CF200EA0737 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1218C9F271A2CF200EA0737 /* Nuke */; };
|
||||
E122A9132788EAAD0060FA63 /* MediaStreamExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E122A9122788EAAD0060FA63 /* MediaStreamExtension.swift */; };
|
||||
E122A9142788EAAD0060FA63 /* MediaStreamExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E122A9122788EAAD0060FA63 /* MediaStreamExtension.swift */; };
|
||||
E1267D3E271A1F46003C492E /* PreferenceUIHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1267D3D271A1F46003C492E /* PreferenceUIHostingController.swift */; };
|
||||
E131691726C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; };
|
||||
E131691826C583BC0074BFEE /* LogConstructor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E131691626C583BC0074BFEE /* LogConstructor.swift */; };
|
||||
|
@ -372,6 +371,8 @@
|
|||
E1AD105C26D9ABDD003E4A08 /* PillHStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD105B26D9ABDD003E4A08 /* PillHStackView.swift */; };
|
||||
E1AD105F26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */; };
|
||||
E1AD106226D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD106126D9B7CD003E4A08 /* ItemPortraitHeaderOverlayView.swift */; };
|
||||
E1AE8E7C2789135A00FBDDAA /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1AE8E7B2789135A00FBDDAA /* Nuke */; };
|
||||
E1AE8E7E2789136D00FBDDAA /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1AE8E7D2789136D00FBDDAA /* Nuke */; };
|
||||
E1B59FD52786ADE500A5287E /* ContinueWatchingCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B59FD42786ADE500A5287E /* ContinueWatchingCard.swift */; };
|
||||
E1B59FD92786AE4600A5287E /* NextUpCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B59FD82786AE4600A5287E /* NextUpCard.swift */; };
|
||||
E1B6DCE8271A23780015B715 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = E1B6DCE7271A23780015B715 /* CombineExt */; };
|
||||
|
@ -403,9 +404,12 @@
|
|||
E1D4BF8C2719F39F00A11E64 /* AppAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF802719D22800A11E64 /* AppAppearance.swift */; };
|
||||
E1D4BF8D2719F3A300A11E64 /* VideoPlayerJumpLength.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1F0204D26CCCA74001C1C3B /* VideoPlayerJumpLength.swift */; };
|
||||
E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D4BF8E271A079A00A11E64 /* BasicAppSettingsView.swift */; };
|
||||
E1D7E5A827892566009D0EF7 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1D7E5A727892566009D0EF7 /* Nuke */; };
|
||||
E1E00A35278628A40022235B /* DoubleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E00A34278628A40022235B /* DoubleExtensions.swift */; };
|
||||
E1E00A36278628A40022235B /* DoubleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E00A34278628A40022235B /* DoubleExtensions.swift */; };
|
||||
E1E00A37278628A40022235B /* DoubleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E00A34278628A40022235B /* DoubleExtensions.swift */; };
|
||||
E1E0F4D8278911680084F701 /* CachedAsyncImage in Frameworks */ = {isa = PBXBuildFile; productRef = E1E0F4D7278911680084F701 /* CachedAsyncImage */; };
|
||||
E1E0F4DA278911A30084F701 /* CachedAsyncImage in Frameworks */ = {isa = PBXBuildFile; productRef = E1E0F4D9278911A30084F701 /* CachedAsyncImage */; };
|
||||
E1E48CC9271E6D410021A2F9 /* RefreshHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E48CC8271E6D410021A2F9 /* RefreshHelper.swift */; };
|
||||
E1E5D5372783A52C00692DFE /* CinematicEpisodeItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E5D5362783A52C00692DFE /* CinematicEpisodeItemView.swift */; };
|
||||
E1E5D5392783A56B00692DFE /* EpisodesRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E5D5382783A56B00692DFE /* EpisodesRowView.swift */; };
|
||||
|
@ -645,6 +649,7 @@
|
|||
E10EAA52277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BaseItemDto+VideoPlayerViewModel.swift"; sourceTree = "<group>"; };
|
||||
E11B1B6B2718CD68006DA3E8 /* JellyfinAPIError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinAPIError.swift; sourceTree = "<group>"; };
|
||||
E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailCoordinator.swift; sourceTree = "<group>"; };
|
||||
E122A9122788EAAD0060FA63 /* MediaStreamExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaStreamExtension.swift; sourceTree = "<group>"; };
|
||||
E1267D3D271A1F46003C492E /* PreferenceUIHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceUIHostingController.swift; sourceTree = "<group>"; };
|
||||
E131691626C583BC0074BFEE /* LogConstructor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogConstructor.swift; sourceTree = "<group>"; };
|
||||
E1384943278036C70024FB48 /* VLCPlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VLCPlayerViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -748,13 +753,14 @@
|
|||
files = (
|
||||
53649AAF269CFAF600A2D8B7 /* Puppy in Frameworks */,
|
||||
E1218C9E271A2CD600EA0737 /* CombineExt in Frameworks */,
|
||||
E1218CA0271A2CF200EA0737 /* Nuke in Frameworks */,
|
||||
6220D0C926D63F3700B8E046 /* Stinsen in Frameworks */,
|
||||
535870912669D7A800D05A09 /* Introspect in Frameworks */,
|
||||
536D3D84267BEA550004248C /* ParallaxView in Frameworks */,
|
||||
53ABFDDC267972BF00886593 /* TVServices.framework in Frameworks */,
|
||||
E1A9999B271A343C008E78C0 /* SwiftUICollection in Frameworks */,
|
||||
E13DD3CD27164CA7009D4DAF /* CoreStore in Frameworks */,
|
||||
E1E0F4DA278911A30084F701 /* CachedAsyncImage in Frameworks */,
|
||||
E1AE8E7E2789136D00FBDDAA /* Nuke in Frameworks */,
|
||||
E178857D278037FD0094FBCF /* JellyfinAPI in Frameworks */,
|
||||
E12186DE2718F1C50010884C /* Defaults in Frameworks */,
|
||||
53ABFDED26799D7700886593 /* ActivityIndicator in Frameworks */,
|
||||
|
@ -771,10 +777,11 @@
|
|||
E10EAA4D277BB716000269ED /* Sliders in Frameworks */,
|
||||
62C29E9C26D0FE4200C1D2E7 /* Stinsen in Frameworks */,
|
||||
E1A99999271A3429008E78C0 /* SwiftUICollection in Frameworks */,
|
||||
E1218C9A271A26BA00EA0737 /* Nuke in Frameworks */,
|
||||
E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */,
|
||||
53352571265EA0A0006CCA86 /* Introspect in Frameworks */,
|
||||
E13DD3C62716499E009D4DAF /* CoreStore in Frameworks */,
|
||||
E1E0F4D8278911680084F701 /* CachedAsyncImage in Frameworks */,
|
||||
E1AE8E7C2789135A00FBDDAA /* Nuke in Frameworks */,
|
||||
625CB57A2678C4A400530A6E /* ActivityIndicator in Frameworks */,
|
||||
E1B6DCE8271A23780015B715 /* CombineExt in Frameworks */,
|
||||
E10EAA45277BB646000269ED /* JellyfinAPI in Frameworks */,
|
||||
|
@ -786,13 +793,13 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E1D7E5A827892566009D0EF7 /* Nuke in Frameworks */,
|
||||
628B95242670CABD0091AF3B /* SwiftUI.framework in Frameworks */,
|
||||
531ABF6C2671F5CC00C0FE20 /* WidgetKit.framework in Frameworks */,
|
||||
E13DD3DD27175CE3009D4DAF /* Defaults in Frameworks */,
|
||||
53649AB5269D423A00A2D8B7 /* Puppy in Frameworks */,
|
||||
536D3D7D267BD5F90004248C /* ActivityIndicator in Frameworks */,
|
||||
E13DD3CF27164E1F009D4DAF /* CoreStore in Frameworks */,
|
||||
E1218C9C271A26C400EA0737 /* Nuke in Frameworks */,
|
||||
E10EAA47277BB670000269ED /* JellyfinAPI in Frameworks */,
|
||||
3B8BA25B211CA261017ABA16 /* Pods_Swiftfin_Widget.framework in Frameworks */,
|
||||
);
|
||||
|
@ -1502,10 +1509,11 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
E18845F426DD631E00B0C5B7 /* BaseItemDto+Stackable.swift */,
|
||||
E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */,
|
||||
E10EAA52277BBD17000269ED /* BaseItemDto+VideoPlayerViewModel.swift */,
|
||||
E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */,
|
||||
5364F454266CA0DC0026ECBA /* BaseItemPersonExtensions.swift */,
|
||||
E11B1B6B2718CD68006DA3E8 /* JellyfinAPIError.swift */,
|
||||
E122A9122788EAAD0060FA63 /* MediaStreamExtension.swift */,
|
||||
E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */,
|
||||
);
|
||||
path = JellyfinAPIExtensions;
|
||||
|
@ -1634,9 +1642,10 @@
|
|||
E13DD3CC27164CA7009D4DAF /* CoreStore */,
|
||||
E12186DD2718F1C50010884C /* Defaults */,
|
||||
E1218C9D271A2CD600EA0737 /* CombineExt */,
|
||||
E1218C9F271A2CF200EA0737 /* Nuke */,
|
||||
E1A9999A271A343C008E78C0 /* SwiftUICollection */,
|
||||
E178857C278037FD0094FBCF /* JellyfinAPI */,
|
||||
E1E0F4D9278911A30084F701 /* CachedAsyncImage */,
|
||||
E1AE8E7D2789136D00FBDDAA /* Nuke */,
|
||||
);
|
||||
productName = "JellyfinPlayer tvOS";
|
||||
productReference = 535870602669D21600D05A09 /* Swiftfin tvOS.app */;
|
||||
|
@ -1671,10 +1680,11 @@
|
|||
E13DD3D227168E65009D4DAF /* Defaults */,
|
||||
E1B6DCE7271A23780015B715 /* CombineExt */,
|
||||
E1B6DCE9271A23880015B715 /* SwiftyJSON */,
|
||||
E1218C99271A26BA00EA0737 /* Nuke */,
|
||||
E1A99998271A3429008E78C0 /* SwiftUICollection */,
|
||||
E10EAA44277BB646000269ED /* JellyfinAPI */,
|
||||
E10EAA4C277BB716000269ED /* Sliders */,
|
||||
E1E0F4D7278911680084F701 /* CachedAsyncImage */,
|
||||
E1AE8E7B2789135A00FBDDAA /* Nuke */,
|
||||
);
|
||||
productName = JellyfinPlayer;
|
||||
productReference = 5377CBF1263B596A003A4E83 /* Swiftfin iOS.app */;
|
||||
|
@ -1699,8 +1709,8 @@
|
|||
53649AB4269D423A00A2D8B7 /* Puppy */,
|
||||
E13DD3CE27164E1F009D4DAF /* CoreStore */,
|
||||
E13DD3DC27175CE3009D4DAF /* Defaults */,
|
||||
E1218C9B271A26C400EA0737 /* Nuke */,
|
||||
E10EAA46277BB670000269ED /* JellyfinAPI */,
|
||||
E1D7E5A727892566009D0EF7 /* Nuke */,
|
||||
);
|
||||
productName = WidgetExtensionExtension;
|
||||
productReference = 628B95202670CABD0091AF3B /* Swiftfin Widget.appex */;
|
||||
|
@ -1759,14 +1769,15 @@
|
|||
536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */,
|
||||
53649AAB269CFAEA00A2D8B7 /* XCRemoteSwiftPackageReference "Puppy" */,
|
||||
62C29E9A26D0FE4100C1D2E7 /* XCRemoteSwiftPackageReference "stinsen" */,
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */,
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */,
|
||||
E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */,
|
||||
E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */,
|
||||
E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
||||
E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */,
|
||||
C4BFD4E327167B63007739E3 /* XCRemoteSwiftPackageReference "SwiftUICollection" */,
|
||||
E10EAA43277BB646000269ED /* XCRemoteSwiftPackageReference "jellyfin-sdk-swift" */,
|
||||
E10EAA4B277BB716000269ED /* XCRemoteSwiftPackageReference "swiftui-sliders" */,
|
||||
E1E0F4D6278911680084F701 /* XCRemoteSwiftPackageReference "SwiftUI-CachedAsyncImage" */,
|
||||
E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */,
|
||||
);
|
||||
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -2051,6 +2062,7 @@
|
|||
E1C812CC277AE40A00918266 /* VideoPlayerView.swift in Sources */,
|
||||
53CD2A40268A49C2002ABD4E /* ItemView.swift in Sources */,
|
||||
53CD2A42268A4B38002ABD4E /* MovieItemView.swift in Sources */,
|
||||
E122A9142788EAAD0060FA63 /* MediaStreamExtension.swift in Sources */,
|
||||
E178859E2780F53B0094FBCF /* SliderView.swift in Sources */,
|
||||
536D3D7F267BDF100004248C /* LatestMediaView.swift in Sources */,
|
||||
E1384944278036C70024FB48 /* VLCPlayerViewController.swift in Sources */,
|
||||
|
@ -2191,6 +2203,7 @@
|
|||
E13DD3F227179378009D4DAF /* UserSignInCoordinator.swift in Sources */,
|
||||
621338932660107500A81A2A /* StringExtensions.swift in Sources */,
|
||||
53FF7F2A263CF3F500585C35 /* LatestMediaView.swift in Sources */,
|
||||
E122A9132788EAAD0060FA63 /* MediaStreamExtension.swift in Sources */,
|
||||
E1C812C5277A90B200918266 /* URLComponentsExtensions.swift in Sources */,
|
||||
62E632EC267D410B0063E547 /* SeriesItemViewModel.swift in Sources */,
|
||||
625CB5732678C32A00530A6E /* HomeViewModel.swift in Sources */,
|
||||
|
@ -2920,14 +2933,6 @@
|
|||
kind = branch;
|
||||
};
|
||||
};
|
||||
E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/kean/Nuke";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 9.0.0;
|
||||
};
|
||||
};
|
||||
E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/CombineCommunity/CombineExt";
|
||||
|
@ -2936,7 +2941,7 @@
|
|||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */ = {
|
||||
E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/JohnEstropia/CoreStore.git";
|
||||
requirement = {
|
||||
|
@ -2952,6 +2957,14 @@
|
|||
minimumVersion = 6.0.0;
|
||||
};
|
||||
};
|
||||
E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/kean/Nuke";
|
||||
requirement = {
|
||||
kind = upToNextMinorVersion;
|
||||
minimumVersion = 9.6.0;
|
||||
};
|
||||
};
|
||||
E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON";
|
||||
|
@ -2960,6 +2973,14 @@
|
|||
minimumVersion = 5.0.0;
|
||||
};
|
||||
};
|
||||
E1E0F4D6278911680084F701 /* XCRemoteSwiftPackageReference "SwiftUI-CachedAsyncImage" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/lorenzofiamingo/SwiftUI-CachedAsyncImage";
|
||||
requirement = {
|
||||
branch = main;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
|
@ -3038,39 +3059,24 @@
|
|||
package = E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */;
|
||||
productName = Defaults;
|
||||
};
|
||||
E1218C99271A26BA00EA0737 /* Nuke */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = Nuke;
|
||||
};
|
||||
E1218C9B271A26C400EA0737 /* Nuke */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = Nuke;
|
||||
};
|
||||
E1218C9D271A2CD600EA0737 /* CombineExt */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */;
|
||||
productName = CombineExt;
|
||||
};
|
||||
E1218C9F271A2CF200EA0737 /* Nuke */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1218C98271A26BA00EA0737 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = Nuke;
|
||||
};
|
||||
E13DD3C52716499E009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3CC27164CA7009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3CE27164E1F009D4DAF /* CoreStore */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore.git" */;
|
||||
package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */;
|
||||
productName = CoreStore;
|
||||
};
|
||||
E13DD3D227168E65009D4DAF /* Defaults */ = {
|
||||
|
@ -3098,6 +3104,16 @@
|
|||
package = C4BFD4E327167B63007739E3 /* XCRemoteSwiftPackageReference "SwiftUICollection" */;
|
||||
productName = SwiftUICollection;
|
||||
};
|
||||
E1AE8E7B2789135A00FBDDAA /* Nuke */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = Nuke;
|
||||
};
|
||||
E1AE8E7D2789136D00FBDDAA /* Nuke */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = Nuke;
|
||||
};
|
||||
E1B6DCE7271A23780015B715 /* CombineExt */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1267D42271A212C003C492E /* XCRemoteSwiftPackageReference "CombineExt" */;
|
||||
|
@ -3108,6 +3124,21 @@
|
|||
package = E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
|
||||
productName = SwiftyJSON;
|
||||
};
|
||||
E1D7E5A727892566009D0EF7 /* Nuke */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = Nuke;
|
||||
};
|
||||
E1E0F4D7278911680084F701 /* CachedAsyncImage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1E0F4D6278911680084F701 /* XCRemoteSwiftPackageReference "SwiftUI-CachedAsyncImage" */;
|
||||
productName = CachedAsyncImage;
|
||||
};
|
||||
E1E0F4D9278911A30084F701 /* CachedAsyncImage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E1E0F4D6278911680084F701 /* XCRemoteSwiftPackageReference "SwiftUI-CachedAsyncImage" */;
|
||||
productName = CachedAsyncImage;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 5377CBE9263B596A003A4E83 /* Project object */;
|
||||
|
|
|
@ -100,6 +100,15 @@
|
|||
"version": "1.4.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "CachedAsyncImage",
|
||||
"repositoryURL": "https://github.com/lorenzofiamingo/SwiftUI-CachedAsyncImage",
|
||||
"state": {
|
||||
"branch": "main",
|
||||
"revision": "eb489a699be1f6e6c1a19fecdd6bfdc556474fd6",
|
||||
"version": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Introspect",
|
||||
"repositoryURL": "https://github.com/siteline/SwiftUI-Introspect",
|
||||
|
|
|
@ -63,19 +63,20 @@ struct SettingsView: View {
|
|||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Networking")) {
|
||||
Picker("Default local quality", selection: $inNetworkStreamBitrate) {
|
||||
ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
||||
Text(bitrate.name).tag(bitrate.value)
|
||||
}
|
||||
}
|
||||
|
||||
Picker("Default remote quality", selection: $outOfNetworkStreamBitrate) {
|
||||
ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
||||
Text(bitrate.name).tag(bitrate.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Implement these for playback
|
||||
// Section(header: Text("Networking")) {
|
||||
// Picker("Default local quality", selection: $inNetworkStreamBitrate) {
|
||||
// ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
||||
// Text(bitrate.name).tag(bitrate.value)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Picker("Default remote quality", selection: $outOfNetworkStreamBitrate) {
|
||||
// ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
||||
// Text(bitrate.name).tag(bitrate.value)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Section(header: Text("Video Player")) {
|
||||
Picker("Jump Forward Length", selection: $jumpForwardLength) {
|
||||
|
|
|
@ -24,7 +24,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
// MARK: variables
|
||||
|
||||
private var viewModel: VideoPlayerViewModel
|
||||
private var vlcMediaPlayer = VLCMediaPlayer()
|
||||
private var vlcMediaPlayer: VLCMediaPlayer
|
||||
private var lastPlayerTicks: Int64 = 0
|
||||
private var lastProgressReportTicks: Int64 = 0
|
||||
private var viewModelListeners = Set<AnyCancellable>()
|
||||
|
@ -49,6 +49,7 @@ class VLCPlayerViewController: UIViewController {
|
|||
init(viewModel: VideoPlayerViewModel) {
|
||||
|
||||
self.viewModel = viewModel
|
||||
self.vlcMediaPlayer = VLCMediaPlayer()
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
|
@ -97,14 +98,6 @@ class VLCPlayerViewController: UIViewController {
|
|||
|
||||
view.backgroundColor = .black
|
||||
|
||||
// These are kept outside of 'setupMediaPlayer' such that
|
||||
// they aren't unnecessarily set more than once
|
||||
vlcMediaPlayer.delegate = self
|
||||
vlcMediaPlayer.drawable = videoContentView
|
||||
|
||||
// TODO: Custom subtitle sizes
|
||||
vlcMediaPlayer.perform(Selector(("setTextRendererFontSize:")), with: 14)
|
||||
|
||||
setupMediaPlayer(newViewModel: viewModel)
|
||||
|
||||
refreshJumpBackwardOverlayView(with: viewModel.jumpBackwardLength)
|
||||
|
@ -287,9 +280,8 @@ extension VLCPlayerViewController {
|
|||
/// Use case for this is setting new media within the same VLCPlayerViewController
|
||||
func setupMediaPlayer(newViewModel: VideoPlayerViewModel) {
|
||||
|
||||
stopOverlayDismissTimer()
|
||||
// remove old player
|
||||
|
||||
// Stop current media if there is one
|
||||
if vlcMediaPlayer.media != nil {
|
||||
viewModelListeners.forEach({ $0.cancel() })
|
||||
|
||||
|
@ -298,6 +290,20 @@ extension VLCPlayerViewController {
|
|||
viewModel.playerOverlayDelegate = nil
|
||||
}
|
||||
|
||||
vlcMediaPlayer = VLCMediaPlayer()
|
||||
|
||||
// setup with new player and view model
|
||||
|
||||
vlcMediaPlayer = VLCMediaPlayer()
|
||||
|
||||
vlcMediaPlayer.delegate = self
|
||||
vlcMediaPlayer.drawable = videoContentView
|
||||
|
||||
// TODO: Custom subtitle sizes
|
||||
vlcMediaPlayer.perform(Selector(("setTextRendererFontSize:")), with: 14)
|
||||
|
||||
stopOverlayDismissTimer()
|
||||
|
||||
lastPlayerTicks = newViewModel.item.userData?.playbackPositionTicks ?? 0
|
||||
lastProgressReportTicks = newViewModel.item.userData?.playbackPositionTicks ?? 0
|
||||
|
||||
|
@ -334,6 +340,13 @@ extension VLCPlayerViewController {
|
|||
func startPlayback() {
|
||||
vlcMediaPlayer.play()
|
||||
|
||||
// Setup external subtitles
|
||||
for externalSubtitle in viewModel.subtitleStreams.filter({ $0.deliveryMethod == .external }) {
|
||||
if let deliveryURL = externalSubtitle.externalURL(base: SessionManager.main.currentLogin.server.currentURI) {
|
||||
vlcMediaPlayer.addPlaybackSlave(deliveryURL, type: .subtitle, enforce: false)
|
||||
}
|
||||
}
|
||||
|
||||
setMediaPlayerTimeAtCurrentSlider()
|
||||
|
||||
viewModel.sendPlayReport()
|
||||
|
@ -526,7 +539,8 @@ extension VLCPlayerViewController: VLCMediaPlayerDelegate {
|
|||
}
|
||||
|
||||
// If needing to fix subtitle streams during playback
|
||||
if vlcMediaPlayer.currentVideoSubTitleIndex != viewModel.selectedSubtitleStreamIndex && viewModel.subtitlesEnabled {
|
||||
if vlcMediaPlayer.currentVideoSubTitleIndex != viewModel.selectedSubtitleStreamIndex &&
|
||||
viewModel.subtitlesEnabled {
|
||||
didSelectSubtitleStream(index: viewModel.selectedSubtitleStreamIndex)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue