From a7ed08e2b570f9db73b7c3449e0fb0895c7f42dc Mon Sep 17 00:00:00 2001 From: Aiden Vigue Date: Sun, 20 Jun 2021 23:18:22 -0400 Subject: [PATCH] release 49 --- JellyfinPlayer tvOS/Info.plist | 2 +- JellyfinPlayer.xcodeproj/project.pbxproj | 12 +++--- JellyfinPlayer/ContinueWatchingView.swift | 2 - JellyfinPlayer/HomeView.swift | 33 +++++++---------- JellyfinPlayer/Info.plist | 14 ++++--- JellyfinPlayer/LibraryFilterView.swift | 19 +++++----- JellyfinPlayer/VideoPlayer.swift | 37 +++++++++++++------ Shared/Typings/Typings.swift | 8 ++-- .../ViewModels/LibraryFilterViewModel.swift | 4 +- WidgetExtension/Info.plist | 2 +- 10 files changed, 72 insertions(+), 61 deletions(-) diff --git a/JellyfinPlayer tvOS/Info.plist b/JellyfinPlayer tvOS/Info.plist index 6d37a895..34b9158f 100644 --- a/JellyfinPlayer tvOS/Info.plist +++ b/JellyfinPlayer tvOS/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 43 + $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS UILaunchScreen diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index b7cfb356..5d0f0316 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -1002,7 +1002,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "JellyfinPlayer tvOS/JellyfinPlayer tvOS.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 49; DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer tvOS/Preview Content\""; DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_PREVIEWS = YES; @@ -1030,7 +1030,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = "JellyfinPlayer tvOS/JellyfinPlayer tvOS.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 49; DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer tvOS/Preview Content\""; DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_PREVIEWS = YES; @@ -1179,7 +1179,7 @@ CODE_SIGN_ENTITLEMENTS = JellyfinPlayer/JellyfinPlayer.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 49; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_BITCODE = NO; @@ -1213,7 +1213,7 @@ CODE_SIGN_ENTITLEMENTS = JellyfinPlayer/JellyfinPlayer.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 49; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; DEVELOPMENT_TEAM = 9R8RREG67J; @@ -1245,7 +1245,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 49; DEVELOPMENT_TEAM = 9R8RREG67J; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; @@ -1270,7 +1270,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 43; + CURRENT_PROJECT_VERSION = 49; DEVELOPMENT_TEAM = 9R8RREG67J; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; diff --git a/JellyfinPlayer/ContinueWatchingView.swift b/JellyfinPlayer/ContinueWatchingView.swift index 722ed05d..7931102c 100644 --- a/JellyfinPlayer/ContinueWatchingView.swift +++ b/JellyfinPlayer/ContinueWatchingView.swift @@ -80,8 +80,6 @@ struct ContinueWatchingView: View { Spacer().frame(width: 2) }.frame(height: 215) .padding(.bottom, 10) - } else { - EmptyView() } } } diff --git a/JellyfinPlayer/HomeView.swift b/JellyfinPlayer/HomeView.swift index 824c97b1..33cf87e9 100644 --- a/JellyfinPlayer/HomeView.swift +++ b/JellyfinPlayer/HomeView.swift @@ -12,13 +12,14 @@ import SwiftUI struct HomeView: View { @StateObject var viewModel = HomeViewModel() - @State private var orientation = UIDevice.current.orientation @Environment(\.horizontalSizeClass) var hSizeClass @Environment(\.verticalSizeClass) var vSizeClass @State var showingSettings = false var body: some View { - ZStack { + if(viewModel.isLoading) { + ProgressView() + } else { ScrollView { LazyVStack(alignment: .leading) { Spacer().frame(height: hSizeClass == .compact && vSizeClass == .regular ? 0 : 16) @@ -55,25 +56,19 @@ struct HomeView: View { Spacer().frame(height: UIDevice.current.userInterfaceIdiom == .phone ? 20 : 30) } } - if viewModel.isLoading { - ProgressView() - } - } - .onRotate { - orientation = $0 - } - .navigationTitle(MainTabView.Tab.home.localized) - .toolbar { - ToolbarItemGroup(placement: .navigationBarTrailing) { - Button { - showingSettings = true - } label: { - Image(systemName: "gear") + .navigationTitle(MainTabView.Tab.home.localized) + .toolbar { + ToolbarItemGroup(placement: .navigationBarTrailing) { + Button { + showingSettings = true + } label: { + Image(systemName: "gear") + } } } - } - .fullScreenCover(isPresented: $showingSettings) { - SettingsView(viewModel: SettingsViewModel(), close: $showingSettings) + .fullScreenCover(isPresented: $showingSettings) { + SettingsView(viewModel: SettingsViewModel(), close: $showingSettings) + } } } } diff --git a/JellyfinPlayer/Info.plist b/JellyfinPlayer/Info.plist index a31d2e3f..68f1e706 100644 --- a/JellyfinPlayer/Info.plist +++ b/JellyfinPlayer/Info.plist @@ -19,24 +19,26 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 43 + $(CURRENT_PROJECT_VERSION) ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS - NSBluetoothAlwaysUsageDescription - ${PRODUCT_NAME} uses Bluetooth to discover nearby Cast devices. NSAppTransportSecurity + NSAllowsArbitraryLoads + NSAllowsArbitraryLoadsForMedia NSAllowsArbitraryLoadsInWebContent NSAllowsLocalNetworking - NSAllowsArbitraryLoads - + NSBluetoothAlwaysUsageDescription + ${PRODUCT_NAME} uses Bluetooth to discover nearby Cast devices. + NSBluetoothPeripheralUsageDescription + ${PRODUCT_NAME} uses Bluetooth to discover nearby Cast devices. NSBonjourServices _googlecast._tcp @@ -45,6 +47,8 @@ NSLocalNetworkUsageDescription ${PRODUCT_NAME} uses the local network to connect to your Jellyfin server & discover Cast-enabled devices on your WiFi network. + NSMicrophoneUsageDescription + ${PRODUCT_NAME} uses microphone access to listen for ultrasonic tokens when pairing with nearby Cast devices. UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/JellyfinPlayer/LibraryFilterView.swift b/JellyfinPlayer/LibraryFilterView.swift index 4a9db41f..0719d7d2 100644 --- a/JellyfinPlayer/LibraryFilterView.swift +++ b/JellyfinPlayer/LibraryFilterView.swift @@ -27,31 +27,32 @@ struct LibraryFilterView: View { MultiSelector(label: "Genres", options: viewModel.possibleGenres, optionToString: { $0.name ?? "" }, - selected: $viewModel.modifyedFilters.withGenres) + selected: $viewModel.modifiedFilters.withGenres) } if viewModel.enabledFilterType.contains(.filter) { MultiSelector(label: "Filters", options: viewModel.possibleItemFilters, optionToString: { $0.localized }, - selected: $viewModel.modifyedFilters.filters) + selected: $viewModel.modifiedFilters.filters) } if viewModel.enabledFilterType.contains(.tag) { MultiSelector(label: "Tags", options: viewModel.possibleTags, optionToString: { $0 }, - selected: $viewModel.modifyedFilters.tags) + selected: $viewModel.modifiedFilters.tags) } if viewModel.enabledFilterType.contains(.sortBy) { MultiSelector(label: "Sort by", options: viewModel.possibleSortBys, optionToString: { $0.localized }, - selected: $viewModel.modifyedFilters.sortBy) + selected: $viewModel.modifiedFilters.sortBy) } if viewModel.enabledFilterType.contains(.sortOrder) { - MultiSelector(label: "Sort Order", - options: viewModel.possibleSortOrders, - optionToString: { $0.localized }, - selected: $viewModel.modifyedFilters.sortOrder) + Picker(selection: $viewModel.modifiedFilters.sortOrder, label: Text("Order")) { + ForEach(viewModel.possibleSortOrders, id: \.self) { so in + Text("\(so.rawValue)").tag(so.rawValue) + } + } } } if viewModel.isLoading { @@ -69,7 +70,7 @@ struct LibraryFilterView: View { } ToolbarItemGroup(placement: .navigationBarTrailing) { Button { - self.filters = viewModel.modifyedFilters + self.filters = viewModel.modifiedFilters presentationMode.wrappedValue.dismiss() } label: { Text("Apply") diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index 62e0e0a8..11640305 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -558,6 +558,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe print("Local playback engine starting.") mediaPlayer.media = VLCMedia(url: playbackItem.videoUrl) mediaPlayer.play() + sendPlayReport() // 1 second = 10,000,000 ticks var startTicks: Int64 = 0; @@ -595,9 +596,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe // Wait for captions to load delegate?.showLoadingView(self) - while mediaPlayer.numberOfSubtitlesTracks != shouldHaveSubtitleTracks { - print("waiting \(String(mediaPlayer.numberOfSubtitlesTracks)) != \(String(shouldHaveSubtitleTracks))") - } + while mediaPlayer.numberOfSubtitlesTracks != shouldHaveSubtitleTracks {} // Select default track & resume playback mediaPlayer.currentVideoSubTitleIndex = selectedCaptionTrack @@ -643,9 +642,8 @@ extension PlayerViewController: GCKGenericChannelDelegate { } timeText.text = timeTextStr - let playbackProgress = Int64(remotePositionTicks) / manifest.runTimeTicks! - print(playbackProgress) - seekSlider.setValue(Float(playbackProgress), animated: true) + let playbackProgress = Float(remotePositionTicks) / Float(manifest.runTimeTicks!) + seekSlider.setValue(playbackProgress, animated: true) } } @@ -654,11 +652,14 @@ extension PlayerViewController: GCKGenericChannelDelegate { if let json = try? JSON(data: data) { let messageType = json["type"].string ?? "" if(messageType == "playbackprogress") { - if(hasSentRemoteSeek == false) { - hasSentRemoteSeek = true; - sendJellyfinCommand(command: "Seek", options: [ - "position": Int(Float(manifest.runTimeTicks! / 10_000_000) * mediaPlayer.position) - ]) + dump(json) + if(remotePositionTicks > 100) { + if(hasSentRemoteSeek == false) { + hasSentRemoteSeek = true; + sendJellyfinCommand(command: "Seek", options: [ + "position": Int(Float(manifest.runTimeTicks! / 10_000_000) * mediaPlayer.position) + ]) + } } paused = json["data"]["PlayState"]["IsPaused"].boolValue self.remotePositionTicks = json["data"]["PlayState"]["PositionTicks"].int ?? 0; @@ -687,6 +688,20 @@ extension PlayerViewController: GCKGenericChannelDelegate { let jsonData = JSON(payload) jellyfinCastChannel?.sendTextMessage(jsonData.rawString()!, error: nil) + + if(command == "Seek") { + remotePositionTicks = remotePositionTicks + ((options["position"] as! Int) * 10_000_000) + //Send playback report as Jellyfin Chromecast isn't smarter than a rock. + let progressInfo = PlaybackProgressInfo(canSeek: true, item: manifest, itemId: manifest.id, sessionId: playSessionId, mediaSourceId: manifest.id, audioStreamIndex: Int(selectedAudioTrack), subtitleStreamIndex: Int(selectedCaptionTrack), isPaused: paused, isMuted: false, positionTicks: Int64(remotePositionTicks), playbackStartTimeTicks: Int64(startTime), volumeLevel: 100, brightness: 100, aspectRatio: nil, playMethod: playbackItem.videoType, liveStreamId: nil, playSessionId: playSessionId, repeatMode: .repeatNone, nowPlayingQueue: [], playlistItemId: "playlistItem0") + + PlaystateAPI.reportPlaybackProgress(playbackProgressInfo: progressInfo) + .sink(receiveCompletion: { result in + print(result) + }, receiveValue: { _ in + print("Playback progress report sent!") + }) + .store(in: &cancellables) + } } } diff --git a/Shared/Typings/Typings.swift b/Shared/Typings/Typings.swift index d4a1ec06..fa220d70 100644 --- a/Shared/Typings/Typings.swift +++ b/Shared/Typings/Typings.swift @@ -34,14 +34,14 @@ extension SortBy { case .name: return "Title" case .dateAdded: - return "Date added" + return "Date Added" } } } extension ItemFilter { static var supportedTypes: [ItemFilter] { - [.isUnplayed, isPlayed, .isFavorite, .likes, .isFavoriteOrLikes] + [.isUnplayed, isPlayed, .isFavorite, .likes] } var localized: String { @@ -53,9 +53,7 @@ extension ItemFilter { case .isFavorite: return "Favorites" case .likes: - return "Liked" - case .isFavoriteOrLikes: - return "Favorites or Liked" + return "Liked Items" default: return "" } diff --git a/Shared/ViewModels/LibraryFilterViewModel.swift b/Shared/ViewModels/LibraryFilterViewModel.swift index fb2ae9f0..d15dd52f 100644 --- a/Shared/ViewModels/LibraryFilterViewModel.swift +++ b/Shared/ViewModels/LibraryFilterViewModel.swift @@ -21,7 +21,7 @@ enum FilterType { final class LibraryFilterViewModel: ViewModel { @Published - var modifyedFilters = LibraryFilters() + var modifiedFilters = LibraryFilters() @Published var possibleGenres = [NameGuidPair]() @@ -41,7 +41,7 @@ final class LibraryFilterViewModel: ViewModel { self.enabledFilterType = enabledFilterType super.init() if let filters = filters { - self.modifyedFilters = filters + self.modifiedFilters = filters } requestQueryFilters() } diff --git a/WidgetExtension/Info.plist b/WidgetExtension/Info.plist index 2f4d5aeb..a98e4afd 100644 --- a/WidgetExtension/Info.plist +++ b/WidgetExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 43 + $(CURRENT_PROJECT_VERSION) NSExtension NSExtensionPointIdentifier