From 3ee33461d34e47895df7e75f35965354175384af Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 17:02:24 +0900 Subject: [PATCH 01/13] add Defaults package replaced UserDefaults.default with Defaults add prefer language settings --- .../VideoPlayerViewController.swift | 4 +- JellyfinPlayer.xcodeproj/project.pbxproj | 55 ++++++++++++---- .../xcshareddata/swiftpm/Package.resolved | 9 +++ JellyfinPlayer/JellyfinPlayer.entitlements | 4 +- JellyfinPlayer/PersistenceController.swift | 2 +- JellyfinPlayer/SettingsView.swift | 62 +++++++++++-------- JellyfinPlayer/VideoPlayer.swift | 5 +- Shared/Extensions/DefaultsExtension.swift | 19 ++++++ Shared/Singleton/SessionManager.swift | 6 +- Shared/ViewModels/SettingsViewModel.swift | 7 +++ Shared/ViewModels/SplashViewModel.swift | 9 +-- WidgetExtension/WidgetExtension.entitlements | 4 +- 12 files changed, 126 insertions(+), 60 deletions(-) create mode 100644 Shared/Extensions/DefaultsExtension.swift diff --git a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift index afe48934..74e9262d 100644 --- a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift +++ b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift @@ -12,6 +12,7 @@ import TVVLCKit import MediaPlayer import JellyfinAPI import Combine +import Defaults protocol VideoPlayerSettingsDelegate: AnyObject { func selectNew(audioTrack id: Int32) @@ -149,8 +150,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, func fetchVideo() { // Fetch max bitrate from UserDefaults depending on current connection mode - let defaults = UserDefaults.standard - let maxBitrate = defaults.integer(forKey: "InNetworkBandwidth") + let maxBitrate = Defaults[.inNetworkBandwidth] // Build a device profile let builder = DeviceProfileBuilder() diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index 0b493e32..3963e0f1 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -133,6 +133,10 @@ 628B95382670CDAB0091AF3B /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */; }; 628B953A2670CE250091AF3B /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 628B95392670CE250091AF3B /* KeychainSwift */; }; 628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* StringExtensions.swift */; }; + 62CB3F462685BAF7003D0A6F /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 62CB3F452685BAF7003D0A6F /* Defaults */; }; + 62CB3F482685BB3B003D0A6F /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = 62CB3F472685BB3B003D0A6F /* Defaults */; }; + 62CB3F4B2685BB77003D0A6F /* DefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */; }; + 62CB3F4C2685BB77003D0A6F /* DefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */; }; 62E632DA267D2BC40063E547 /* LatestMediaViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */; }; 62E632DC267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; }; 62E632DD267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; }; @@ -304,6 +308,7 @@ 628B952A2670CABE0091AF3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 628B95362670CB800091AF3B /* JellyfinWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinWidget.swift; sourceTree = ""; }; 628B953B2670D1FC0091AF3B /* WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetExtension.entitlements; sourceTree = ""; }; + 62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsExtension.swift; sourceTree = ""; }; 62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestMediaViewModel.swift; sourceTree = ""; }; 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = ""; }; 62E632DF267D30CA0063E547 /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = ""; }; @@ -331,6 +336,7 @@ 53EC6E1E267E80AC006DD26A /* Pods_JellyfinPlayer_tvOS.framework in Frameworks */, 53A431BF266B0FFE0016769F /* JellyfinAPI in Frameworks */, 535870912669D7A800D05A09 /* Introspect in Frameworks */, + 62CB3F482685BB3B003D0A6F /* Defaults in Frameworks */, 5358708D2669D7A800D05A09 /* KeychainSwift in Frameworks */, 536D3D84267BEA550004248C /* ParallaxView in Frameworks */, 53ABFDDC267972BF00886593 /* TVServices.framework in Frameworks */, @@ -343,6 +349,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 62CB3F462685BAF7003D0A6F /* Defaults in Frameworks */, 5338F757263B7E2E0014BF09 /* KeychainSwift in Frameworks */, 53EC6E25267EB10F006DD26A /* SwiftyJSON in Frameworks */, 53EC6E21267E80B1006DD26A /* Pods_JellyfinPlayer_iOS.framework in Frameworks */, @@ -591,6 +598,7 @@ 6267B3D526710B8900A7371D /* CollectionExtensions.swift */, 6267B3D92671138200A7371D /* ImageExtensions.swift */, 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */, + 62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */, ); path = Extensions; sourceTree = ""; @@ -662,6 +670,7 @@ 53A431BE266B0FFE0016769F /* JellyfinAPI */, 53ABFDEC26799D7700886593 /* ActivityIndicator */, 536D3D83267BEA550004248C /* ParallaxView */, + 62CB3F472685BB3B003D0A6F /* Defaults */, ); productName = "JellyfinPlayer tvOS"; productReference = 535870602669D21600D05A09 /* JellyfinPlayer tvOS.app */; @@ -693,6 +702,7 @@ 53A431BC266B0FF20016769F /* JellyfinAPI */, 625CB5792678C4A400530A6E /* ActivityIndicator */, 53EC6E24267EB10F006DD26A /* SwiftyJSON */, + 62CB3F452685BAF7003D0A6F /* Defaults */, ); productName = JellyfinPlayer; productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer iOS.app */; @@ -761,6 +771,7 @@ 625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */, 536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */, 53EC6E23267EB10F006DD26A /* XCRemoteSwiftPackageReference "SwiftyJSON" */, + 62CB3F442685BAF7003D0A6F /* XCRemoteSwiftPackageReference "Defaults" */, ); productRefGroup = 5377CBF2263B596A003A4E83 /* Products */; projectDirPath = ""; @@ -944,6 +955,7 @@ 091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */, 53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */, 53ABFDEE26799DCD00886593 /* ImageView.swift in Sources */, + 62CB3F4C2685BB77003D0A6F /* DefaultsExtension.swift in Sources */, 62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */, 5358706C2669D21700D05A09 /* PersistenceController.swift in Sources */, 535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */, @@ -982,6 +994,7 @@ 6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */, 625CB5772678C34300530A6E /* ConnectToServerViewModel.swift in Sources */, 536D3D78267BD5C30004248C /* ViewModel.swift in Sources */, + 62CB3F4B2685BB77003D0A6F /* DefaultsExtension.swift in Sources */, 53DE4BD02670961400739748 /* EpisodeItemView.swift in Sources */, 53F8377D265FF67C00F456B3 /* VideoPlayerSettingsView.swift in Sources */, 53192D5D265AA78A008A4215 /* DeviceProfileBuilder.swift in Sources */, @@ -1068,7 +1081,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer tvOS/Preview Content\""; - DEVELOPMENT_TEAM = 9R8RREG67J; + DEVELOPMENT_TEAM = 4BHXT8RHFR; ENABLE_PREVIEWS = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "JellyfinPlayer tvOS/Info.plist"; @@ -1077,7 +1090,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; + PRODUCT_BUNDLE_IDENTIFIER = dev.kwangmin.swiftfin; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_VERSION = 5.0; @@ -1096,7 +1109,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer tvOS/Preview Content\""; - DEVELOPMENT_TEAM = 9R8RREG67J; + DEVELOPMENT_TEAM = 4BHXT8RHFR; ENABLE_PREVIEWS = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "JellyfinPlayer tvOS/Info.plist"; @@ -1105,7 +1118,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; + PRODUCT_BUNDLE_IDENTIFIER = dev.kwangmin.swiftfin; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_VERSION = 5.0; @@ -1245,7 +1258,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = 9R8RREG67J; + DEVELOPMENT_TEAM = 4BHXT8RHFR; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; EXCLUDED_ARCHS = ""; @@ -1257,7 +1270,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; + PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_MACCATALYST = NO; @@ -1280,7 +1293,7 @@ CURRENT_PROJECT_VERSION = 54; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = 9R8RREG67J; + DEVELOPMENT_TEAM = 4BHXT8RHFR; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; EXCLUDED_ARCHS = ""; @@ -1292,7 +1305,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; + PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_MACCATALYST = NO; @@ -1310,7 +1323,7 @@ CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; - DEVELOPMENT_TEAM = 9R8RREG67J; + DEVELOPMENT_TEAM = 4BHXT8RHFR; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; LD_RUNPATH_SEARCH_PATHS = ( @@ -1319,7 +1332,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin.widget; + PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin.Widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; @@ -1335,7 +1348,7 @@ CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; - DEVELOPMENT_TEAM = 9R8RREG67J; + DEVELOPMENT_TEAM = 4BHXT8RHFR; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; LD_RUNPATH_SEARCH_PATHS = ( @@ -1344,7 +1357,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin.widget; + PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin.Widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; @@ -1450,6 +1463,14 @@ minimumVersion = 1.1.0; }; }; + 62CB3F442685BAF7003D0A6F /* XCRemoteSwiftPackageReference "Defaults" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/sindresorhus/Defaults"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1533,6 +1554,16 @@ package = 5338F755263B7E2E0014BF09 /* XCRemoteSwiftPackageReference "keychain-swift" */; productName = KeychainSwift; }; + 62CB3F452685BAF7003D0A6F /* Defaults */ = { + isa = XCSwiftPackageProductDependency; + package = 62CB3F442685BAF7003D0A6F /* XCRemoteSwiftPackageReference "Defaults" */; + productName = Defaults; + }; + 62CB3F472685BB3B003D0A6F /* Defaults */ = { + isa = XCSwiftPackageProductDependency; + package = 62CB3F442685BAF7003D0A6F /* XCRemoteSwiftPackageReference "Defaults" */; + productName = Defaults; + }; /* End XCSwiftPackageProductDependency section */ /* Begin XCVersionGroup section */ diff --git a/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved b/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved index f56b4837..f98581b0 100644 --- a/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/JellyfinPlayer.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -19,6 +19,15 @@ "version": "0.6.0" } }, + { + "package": "Defaults", + "repositoryURL": "https://github.com/sindresorhus/Defaults", + "state": { + "branch": null, + "revision": "63d93f97ad545c8bceb125a8a36175ea705f7cf5", + "version": "5.0.0" + } + }, { "package": "Gifu", "repositoryURL": "https://github.com/kaishin/Gifu", diff --git a/JellyfinPlayer/JellyfinPlayer.entitlements b/JellyfinPlayer/JellyfinPlayer.entitlements index b6b038ce..58751d05 100644 --- a/JellyfinPlayer/JellyfinPlayer.entitlements +++ b/JellyfinPlayer/JellyfinPlayer.entitlements @@ -8,13 +8,13 @@ com.apple.security.application-groups - group.me.vigue.jellyfin.mobileclient + group.dev.pangmo5.swiftfin com.apple.security.network.client keychain-access-groups - $(AppIdentifierPrefix)me.vigue.jellyfin.sharedKeychain + $(AppIdentifierPrefix)dev.pangmo5.swiftfin.sharedKeychain diff --git a/JellyfinPlayer/PersistenceController.swift b/JellyfinPlayer/PersistenceController.swift index 5e7b23ae..3dc74491 100644 --- a/JellyfinPlayer/PersistenceController.swift +++ b/JellyfinPlayer/PersistenceController.swift @@ -30,7 +30,7 @@ struct PersistenceController { init(inMemory: Bool = false) { container = NSPersistentCloudKitContainer(name: "Model") container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: FileManager.default - .containerURL(forSecurityApplicationGroupIdentifier: "group.me.vigue.jellyfin.mobileclient")!.appendingPathComponent("\(container.name).sqlite"))] + .containerURL(forSecurityApplicationGroupIdentifier: "group.dev.pangmo5.swiftfin")!.appendingPathComponent("\(container.name).sqlite"))] if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/SettingsView.swift index 333bd721..c8c4fc1d 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/SettingsView.swift @@ -7,28 +7,30 @@ import CoreData import SwiftUI +import Defaults struct SettingsView: View { @Environment(\.managedObjectContext) private var viewContext - + @ObservedObject var viewModel: SettingsViewModel - + @Binding var close: Bool - @State private var inNetworkStreamBitrate: Int = 40_000_000 - @State private var outOfNetworkStreamBitrate: Int = 40_000_000 - @State private var autoSelectSubtitles: Bool = false - @State private var autoSelectSubtitlesLangcode: String = "none" + @Default(.inNetworkBandwidth) + var inNetworkStreamBitrate + @Default(.outOfNetworkBandwidth) + var outOfNetworkStreamBitrate + @Default(.isAutoSelectSubtitles) + var isAutoSelectSubtitles + @Default(.autoSelectSubtitlesLangCode) + var autoSelectSubtitlesLangcode + @Default(.autoSelectAudioLangCode) + var autoSelectAudioLangcode @State private var username: String = "" - + func onAppear() { - let defaults = UserDefaults.standard username = SessionManager.current.user.username ?? "" - inNetworkStreamBitrate = defaults.integer(forKey: "InNetworkBandwidth") - outOfNetworkStreamBitrate = defaults.integer(forKey: "OutOfNetworkBandwidth") - autoSelectSubtitles = defaults.bool(forKey: "AutoSelectSubtitles") - autoSelectSubtitlesLangcode = defaults.string(forKey: "AutoSelectSubtitlesLangcode") ?? "" } - + var body: some View { NavigationView { Form { @@ -37,29 +39,35 @@ struct SettingsView: View { ForEach(self.viewModel.bitrates, id: \.self) { bitrate in Text(bitrate.name).tag(bitrate.value) } - }.onChange(of: inNetworkStreamBitrate) { _ in - let defaults = UserDefaults.standard - defaults.setValue(_inNetworkStreamBitrate.wrappedValue, forKey: "InNetworkBandwidth") } - + Picker("Default remote quality", selection: $outOfNetworkStreamBitrate) { ForEach(self.viewModel.bitrates, id: \.self) { bitrate in Text(bitrate.name).tag(bitrate.value) } - }.onChange(of: outOfNetworkStreamBitrate) { _ in - let defaults = UserDefaults.standard - defaults.setValue(_outOfNetworkStreamBitrate.wrappedValue, forKey: "OutOfNetworkBandwidth") } } - + Section(header: Text("Accessibility")) { - Toggle("Automatically show subtitles", isOn: $autoSelectSubtitles).onChange(of: autoSelectSubtitles, perform: { _ in - let defaults = UserDefaults.standard - defaults.setValue(autoSelectSubtitles, forKey: "AutoSelectSubtitles") - }) - Picker("Language preferences", selection: $autoSelectSubtitlesLangcode) {} + Toggle("Automatically show subtitles", isOn: $isAutoSelectSubtitles) + Picker("Subtitles Language preferences", selection: $autoSelectSubtitlesLangcode) { + Text("Auto") + .tag("Auto") + ForEach(viewModel.isoLanguageCodesPair, id: \.1) { + Text($0.0) + .tag($0.1) + } + } + Picker("Audio Language preferences", selection: $autoSelectAudioLangcode) { + Text("Auto") + .tag("Auto") + ForEach(viewModel.isoLanguageCodesPair, id: \.1) { + Text($0.0) + .tag($0.1) + } + } } - + Section { HStack { Text("Signed in as \(username)").foregroundColor(.primary) diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index 24035f9d..f324b8a2 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -12,7 +12,7 @@ import MediaPlayer import Combine import GoogleCast import SwiftyJSON - +import Defaults enum PlayerDestination { case remote @@ -417,8 +417,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe mediaPlayer.drawable = videoContentView // Fetch max bitrate from UserDefaults depending on current connection mode - let defaults = UserDefaults.standard - let maxBitrate = defaults.integer(forKey: "InNetworkBandwidth") + let maxBitrate = Defaults[.inNetworkBandwidth] // Build a device profile let builder = DeviceProfileBuilder() diff --git a/Shared/Extensions/DefaultsExtension.swift b/Shared/Extensions/DefaultsExtension.swift new file mode 100644 index 00000000..ba24206d --- /dev/null +++ b/Shared/Extensions/DefaultsExtension.swift @@ -0,0 +1,19 @@ +// + /* + * 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 Defaults + +extension Defaults.Keys { + static let inNetworkBandwidth = Key("InNetworkBandwidth", default: 40_000_000) + static let outOfNetworkBandwidth = Key("OutOfNetworkBandwidth", default: 40_000_000) + static let isAutoSelectSubtitles = Key("isAutoSelectSubtitles", default: false) + static let autoSelectSubtitlesLangCode = Key("AutoSelectSubtitlesLangCode", default: "Auto") + static let autoSelectAudioLangCode = Key("AutoSelectAudioLangCode", default: "Auto") +} diff --git a/Shared/Singleton/SessionManager.swift b/Shared/Singleton/SessionManager.swift index f0f27de8..6e559752 100644 --- a/Shared/Singleton/SessionManager.swift +++ b/Shared/Singleton/SessionManager.swift @@ -81,7 +81,7 @@ final class SessionManager { fileprivate func getAuthToken(userID: String) -> String? { let keychain = KeychainSwift() - keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" + keychain.accessGroup = "4BHXT8RHFR.dev.pangmo5.swiftfin.sharedKeychain" return keychain.get("AccessToken_\(userID)") } @@ -134,7 +134,7 @@ final class SessionManager { _ = try? PersistenceController.shared.container.viewContext.save() let keychain = KeychainSwift() - keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" + keychain.accessGroup = "4BHXT8RHFR.dev.pangmo5.swiftfin.sharedKeychain" keychain.set(accessToken!, forKey: "AccessToken_\(user.user_id!)") generateAuthHeader(with: accessToken) @@ -151,7 +151,7 @@ final class SessionManager { nc.post(name: Notification.Name("didSignOut"), object: nil) let keychain = KeychainSwift() - keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" + keychain.accessGroup = "4BHXT8RHFR.dev.pangmo5.swiftfin.sharedKeychain" keychain.delete("AccessToken_\(user?.user_id ?? "")") generateAuthHeader(with: nil) diff --git a/Shared/ViewModels/SettingsViewModel.swift b/Shared/ViewModels/SettingsViewModel.swift index cf3fe59a..8885b541 100644 --- a/Shared/ViewModels/SettingsViewModel.swift +++ b/Shared/ViewModels/SettingsViewModel.swift @@ -24,7 +24,9 @@ struct Bitrates: Codable, Hashable { } final class SettingsViewModel: ObservableObject { + let currentLocale = Locale.current var bitrates: [Bitrates] = [] + var isoLanguageCodesPair = [(name: String, isoCode: String)]() init() { let url = Bundle.main.url(forResource: "bitrates", withExtension: "json")! @@ -39,5 +41,10 @@ final class SettingsViewModel: ObservableObject { } catch { print(error) } + + isoLanguageCodesPair = Locale.isoLanguageCodes.compactMap { + guard let name = currentLocale.localizedString(forLanguageCode: $0) else { return nil } + return (name, $0) + } } } diff --git a/Shared/ViewModels/SplashViewModel.swift b/Shared/ViewModels/SplashViewModel.swift index 28da5de6..7450f9de 100644 --- a/Shared/ViewModels/SplashViewModel.swift +++ b/Shared/ViewModels/SplashViewModel.swift @@ -10,6 +10,7 @@ import Foundation import Combine import Nuke +import Defaults #if !os(tvOS) import WidgetKit @@ -30,14 +31,6 @@ final class SplashViewModel: ViewModel { WidgetCenter.shared.reloadAllTimelines() #endif - let defaults = UserDefaults.standard - if defaults.integer(forKey: "InNetworkBandwidth") == 0 { - defaults.setValue(40_000_000, forKey: "InNetworkBandwidth") - } - if defaults.integer(forKey: "OutOfNetworkBandwidth") == 0 { - defaults.setValue(40_000_000, forKey: "OutOfNetworkBandwidth") - } - let nc = NotificationCenter.default nc.addObserver(self, selector: #selector(didLogIn), name: Notification.Name("didSignIn"), object: nil) nc.addObserver(self, selector: #selector(didLogOut), name: Notification.Name("didSignOut"), object: nil) diff --git a/WidgetExtension/WidgetExtension.entitlements b/WidgetExtension/WidgetExtension.entitlements index b164e1cb..b1737b11 100644 --- a/WidgetExtension/WidgetExtension.entitlements +++ b/WidgetExtension/WidgetExtension.entitlements @@ -4,11 +4,11 @@ com.apple.security.application-groups - group.me.vigue.jellyfin.mobileclient + group.dev.pangmo5.swiftfin keychain-access-groups - $(AppIdentifierPrefix)me.vigue.jellyfin.sharedKeychain + $(AppIdentifierPrefix)dev.pangmo5.swiftfin.sharedKeychain From f308219c34190dc7b7c371c78855b5bc2ed504bd Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 17:42:40 +0900 Subject: [PATCH 02/13] Apply prefer language settings to VideoPlayer --- JellyfinPlayer/VideoPlayer.swift | 41 +++++++++++++++++++---- Shared/ViewModels/SettingsViewModel.swift | 2 +- Shared/ViewModels/VideoPlayerModel.swift | 2 ++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index f324b8a2..345733a5 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -455,7 +455,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe item.videoType = .transcode item.videoUrl = streamURL! - let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "") + let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "", langCode: "") subtitleTrackArray.append(disableSubtitleTrack) // Loop through media streams and add to array @@ -467,7 +467,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } else { deliveryUrl = nil } - let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt") + let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt", langCode: stream.language ?? "") if subtitle.delivery != .encode { subtitleTrackArray.append(subtitle) @@ -475,7 +475,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } if stream.type == .audio { - let subtitle = AudioTrack(name: stream.displayTitle!, id: Int32(stream.index!)) + let subtitle = AudioTrack(name: stream.displayTitle!, langCode: stream.language ?? "", id: Int32(stream.index!)) if stream.isDefault! == true { selectedAudioTrack = Int32(stream.index!) } @@ -499,7 +499,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe item.videoUrl = streamURL item.videoType = .directPlay - let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "") + let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "", langCode: "") subtitleTrackArray.append(disableSubtitleTrack) // Loop through media streams and add to array @@ -511,7 +511,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } else { deliveryUrl = nil } - let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec!) + let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec!, langCode: stream.language ?? "") if subtitle.delivery != .encode { subtitleTrackArray.append(subtitle) @@ -519,7 +519,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } if stream.type == .audio { - let subtitle = AudioTrack(name: stream.displayTitle!, id: Int32(stream.index!)) + let subtitle = AudioTrack(name: stream.displayTitle!, langCode: stream.language ?? "", id: Int32(stream.index!)) if stream.isDefault! == true { selectedAudioTrack = Int32(stream.index!) } @@ -542,7 +542,33 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe .store(in: &cancellables) } } - + + func setupTracksForPreferLanguage() { + subtitleTrackArray.forEach { subtitle in + if Defaults[.isAutoSelectSubtitles] { + if Defaults[.autoSelectSubtitlesLangCode] == "Auto", + subtitle.langCode.contains(Locale.current.languageCode ?? "") { + selectedCaptionTrack = subtitle.id + mediaPlayer.currentVideoSubTitleIndex = subtitle.id + } else if subtitle.langCode.contains(Defaults[.autoSelectSubtitlesLangCode]) { + selectedCaptionTrack = subtitle.id + mediaPlayer.currentVideoSubTitleIndex = subtitle.id + } + } + } + + audioTrackArray.forEach { audio in + if Defaults[.autoSelectAudioLangCode] == "Auto", + audio.langCode.contains(Locale.current.languageCode ?? "") { + selectedAudioTrack = audio.id + mediaPlayer.currentAudioTrackIndex = audio.id + } else if audio.langCode.contains(Defaults[.autoSelectAudioLangCode]) { + selectedAudioTrack = audio.id + mediaPlayer.currentAudioTrackIndex = audio.id + } + } + } + func startLocalPlaybackEngine(_ fetchCaptions: Bool) { print("Local playback engine starting.") mediaPlayer.media = VLCMedia(url: playbackItem.videoUrl) @@ -594,6 +620,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe mediaPlayer.pause() mediaPlayer.play() + setupTracksForPreferLanguage() print("Local engine started.") } diff --git a/Shared/ViewModels/SettingsViewModel.swift b/Shared/ViewModels/SettingsViewModel.swift index 8885b541..9db50528 100644 --- a/Shared/ViewModels/SettingsViewModel.swift +++ b/Shared/ViewModels/SettingsViewModel.swift @@ -45,6 +45,6 @@ final class SettingsViewModel: ObservableObject { isoLanguageCodesPair = Locale.isoLanguageCodes.compactMap { guard let name = currentLocale.localizedString(forLanguageCode: $0) else { return nil } return (name, $0) - } + }.sorted(by: { $0.name < $1.name }) } } diff --git a/Shared/ViewModels/VideoPlayerModel.swift b/Shared/ViewModels/VideoPlayerModel.swift index cb219a0d..2598b3f8 100644 --- a/Shared/ViewModels/VideoPlayerModel.swift +++ b/Shared/ViewModels/VideoPlayerModel.swift @@ -16,10 +16,12 @@ struct Subtitle { var url: URL? var delivery: SubtitleDeliveryMethod var codec: String + var langCode: String } struct AudioTrack { var name: String + var langCode: String var id: Int32 } From c27ebe5ad2effaddfcb7711c4ad2d32d7d5e29e1 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 18:49:54 +0900 Subject: [PATCH 03/13] add SearchablePickerView --- JellyfinPlayer.xcodeproj/project.pbxproj | 6 ++ JellyfinPlayer/SettingsView.swift | 32 ++++----- Shared/Extensions/SearchablePickerView.swift | 73 ++++++++++++++++++++ Shared/ViewModels/SettingsViewModel.swift | 30 +++++--- 4 files changed, 114 insertions(+), 27 deletions(-) create mode 100644 Shared/Extensions/SearchablePickerView.swift diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index 3963e0f1..e586b302 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -108,6 +108,8 @@ 621C638026672A30004216EA /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 621C637F26672A30004216EA /* NukeUI */; }; 6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; }; 6228B1C22670EB010067FD35 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFD263B596B003A4E83 /* PersistenceController.swift */; }; + 624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; }; + 624C21762685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; }; 625CB5682678B6FB00530A6E /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5672678B6FB00530A6E /* SplashView.swift */; }; 625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5692678B71200530A6E /* SplashViewModel.swift */; }; 625CB56C2678C0FD00530A6E /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB56B2678C0FD00530A6E /* MainTabView.swift */; }; @@ -289,6 +291,7 @@ 621338922660107500A81A2A /* StringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; }; 621338B22660A07800A81A2A /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = ""; }; 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallaxHeader.swift; sourceTree = ""; }; + 624C21742685CF60007F1390 /* SearchablePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchablePickerView.swift; sourceTree = ""; }; 625CB5672678B6FB00530A6E /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = ""; }; 625CB5692678B71200530A6E /* SplashViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashViewModel.swift; sourceTree = ""; }; 625CB56B2678C0FD00530A6E /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = ""; }; @@ -599,6 +602,7 @@ 6267B3D92671138200A7371D /* ImageExtensions.swift */, 62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */, 62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */, + 624C21742685CF60007F1390 /* SearchablePickerView.swift */, ); path = Extensions; sourceTree = ""; @@ -952,6 +956,7 @@ 536D3D81267BDFC60004248C /* PortraitItemElement.swift in Sources */, 531690E5267ABD5C005D8AB9 /* MainTabView.swift in Sources */, 5310695B2684E7EE00CFFDBA /* AudioView.swift in Sources */, + 624C21762685CF60007F1390 /* SearchablePickerView.swift in Sources */, 091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */, 53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */, 53ABFDEE26799DCD00886593 /* ImageView.swift in Sources */, @@ -1021,6 +1026,7 @@ 621338B32660A07800A81A2A /* LazyView.swift in Sources */, 531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */, 62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */, + 624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */, 62EC352F267666A5000E9F2D /* SessionManager.swift in Sources */, 62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */, 091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */, diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/SettingsView.swift index c8c4fc1d..920fb24b 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/SettingsView.swift @@ -50,22 +50,22 @@ struct SettingsView: View { Section(header: Text("Accessibility")) { Toggle("Automatically show subtitles", isOn: $isAutoSelectSubtitles) - Picker("Subtitles Language preferences", selection: $autoSelectSubtitlesLangcode) { - Text("Auto") - .tag("Auto") - ForEach(viewModel.isoLanguageCodesPair, id: \.1) { - Text($0.0) - .tag($0.1) - } - } - Picker("Audio Language preferences", selection: $autoSelectAudioLangcode) { - Text("Auto") - .tag("Auto") - ForEach(viewModel.isoLanguageCodesPair, id: \.1) { - Text($0.0) - .tag($0.1) - } - } + SearchablePicker(label: "Subtitles Language preferences", + options: viewModel.langs, + optionToString: { $0.name }, + selected:Binding( + get: { viewModel.langs.first(where: { $0.isoCode == autoSelectSubtitlesLangcode }) ?? .auto }, + set: {autoSelectSubtitlesLangcode = $0.isoCode} + ) + ) + SearchablePicker(label: "Audio Language preferences", + options: viewModel.langs, + optionToString: { $0.name }, + selected: Binding( + get: { viewModel.langs.first(where: { $0.isoCode == autoSelectAudioLangcode }) ?? .auto }, + set: { autoSelectAudioLangcode = $0.isoCode} + ) + ) } Section { diff --git a/Shared/Extensions/SearchablePickerView.swift b/Shared/Extensions/SearchablePickerView.swift new file mode 100644 index 00000000..5a9f20b8 --- /dev/null +++ b/Shared/Extensions/SearchablePickerView.swift @@ -0,0 +1,73 @@ +// +/* + * 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 SwiftUI + +private struct SearchablePickerView: View { + @Environment(\.presentationMode) + var presentationMode + + let options: [Selectable] + let optionToString: (Selectable) -> String + let label: String + + @State var text = "" + @Binding var selected: Selectable + + var body: some View { + VStack { + SearchBar(text: $text) + List(options.filter { + guard !text.isEmpty else { return true } + return optionToString($0).lowercased().contains(text.lowercased()) + }, id: \.self) { selectable in + Button(action: { + selected = selectable + presentationMode.wrappedValue.dismiss() + }) { + HStack { + Text(optionToString(selectable)).foregroundColor(Color.primary) + Spacer() + if selected == selectable { + Image(systemName: "checkmark").foregroundColor(.accentColor) + } + } + } + }.listStyle(GroupedListStyle()) + } + } +} + +struct SearchablePicker: View { + let label: String + let options: [Selectable] + let optionToString: (Selectable) -> String + + @Binding var selected: Selectable + + var body: some View { + NavigationLink(destination: searchablePickerView()) { + HStack { + Text(label) + Spacer() + Text(optionToString(selected)) + .foregroundColor(.gray) + .multilineTextAlignment(.trailing) + } + } + } + + private func searchablePickerView() -> some View { + SearchablePickerView(options: options, + optionToString: optionToString, + label: label, + selected: $selected) + } +} diff --git a/Shared/ViewModels/SettingsViewModel.swift b/Shared/ViewModels/SettingsViewModel.swift index 9db50528..12d03232 100644 --- a/Shared/ViewModels/SettingsViewModel.swift +++ b/Shared/ViewModels/SettingsViewModel.swift @@ -1,11 +1,11 @@ // - /* - * 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 - */ +/* + * 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 @@ -23,10 +23,17 @@ struct Bitrates: Codable, Hashable { public var value: Int } +struct Lang: Hashable { + var name: String + var isoCode: String + + static let auto = Lang(name: "Auto", isoCode: "Auto") +} + final class SettingsViewModel: ObservableObject { let currentLocale = Locale.current var bitrates: [Bitrates] = [] - var isoLanguageCodesPair = [(name: String, isoCode: String)]() + var langs = [Lang]() init() { let url = Bundle.main.url(forResource: "bitrates", withExtension: "json")! @@ -41,10 +48,11 @@ final class SettingsViewModel: ObservableObject { } catch { print(error) } - - isoLanguageCodesPair = Locale.isoLanguageCodes.compactMap { + + self.langs = Locale.isoLanguageCodes.compactMap { guard let name = currentLocale.localizedString(forLanguageCode: $0) else { return nil } - return (name, $0) + return Lang(name: name, isoCode: $0) }.sorted(by: { $0.name < $1.name }) + self.langs.insert(.auto, at: 0) } } From 1ea6da0c2c8d69b51302865f8906703ad4a06247 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 19:07:46 +0900 Subject: [PATCH 04/13] rollback signing --- JellyfinPlayer.xcodeproj/project.pbxproj | 20 ++++++++++---------- JellyfinPlayer/JellyfinPlayer.entitlements | 4 ++-- JellyfinPlayer/PersistenceController.swift | 2 +- JellyfinPlayer/SettingsView.swift | 2 +- Shared/Singleton/SessionManager.swift | 6 +++--- WidgetExtension/WidgetExtension.entitlements | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index e586b302..336e8f0c 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -1087,7 +1087,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer tvOS/Preview Content\""; - DEVELOPMENT_TEAM = 4BHXT8RHFR; + DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_PREVIEWS = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "JellyfinPlayer tvOS/Info.plist"; @@ -1115,7 +1115,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer tvOS/Preview Content\""; - DEVELOPMENT_TEAM = 4BHXT8RHFR; + DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_PREVIEWS = YES; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = "JellyfinPlayer tvOS/Info.plist"; @@ -1264,7 +1264,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = 4BHXT8RHFR; + DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; EXCLUDED_ARCHS = ""; @@ -1276,7 +1276,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin; + PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_MACCATALYST = NO; @@ -1299,7 +1299,7 @@ CURRENT_PROJECT_VERSION = 54; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = 4BHXT8RHFR; + DEVELOPMENT_TEAM = 9R8RREG67J; ENABLE_BITCODE = NO; ENABLE_PREVIEWS = YES; EXCLUDED_ARCHS = ""; @@ -1311,7 +1311,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin; + PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTS_MACCATALYST = NO; @@ -1329,7 +1329,7 @@ CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; - DEVELOPMENT_TEAM = 4BHXT8RHFR; + DEVELOPMENT_TEAM = 9R8RREG67J; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; LD_RUNPATH_SEARCH_PATHS = ( @@ -1338,7 +1338,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin.Widget; + PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin.widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; @@ -1354,7 +1354,7 @@ CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 54; - DEVELOPMENT_TEAM = 4BHXT8RHFR; + DEVELOPMENT_TEAM = 9R8RREG67J; INFOPLIST_FILE = WidgetExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; LD_RUNPATH_SEARCH_PATHS = ( @@ -1363,7 +1363,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.pangmo5.swiftfin.Widget; + PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin.widget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; diff --git a/JellyfinPlayer/JellyfinPlayer.entitlements b/JellyfinPlayer/JellyfinPlayer.entitlements index 58751d05..b6b038ce 100644 --- a/JellyfinPlayer/JellyfinPlayer.entitlements +++ b/JellyfinPlayer/JellyfinPlayer.entitlements @@ -8,13 +8,13 @@ com.apple.security.application-groups - group.dev.pangmo5.swiftfin + group.me.vigue.jellyfin.mobileclient com.apple.security.network.client keychain-access-groups - $(AppIdentifierPrefix)dev.pangmo5.swiftfin.sharedKeychain + $(AppIdentifierPrefix)me.vigue.jellyfin.sharedKeychain diff --git a/JellyfinPlayer/PersistenceController.swift b/JellyfinPlayer/PersistenceController.swift index 3dc74491..5e7b23ae 100644 --- a/JellyfinPlayer/PersistenceController.swift +++ b/JellyfinPlayer/PersistenceController.swift @@ -30,7 +30,7 @@ struct PersistenceController { init(inMemory: Bool = false) { container = NSPersistentCloudKitContainer(name: "Model") container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: FileManager.default - .containerURL(forSecurityApplicationGroupIdentifier: "group.dev.pangmo5.swiftfin")!.appendingPathComponent("\(container.name).sqlite"))] + .containerURL(forSecurityApplicationGroupIdentifier: "group.me.vigue.jellyfin.mobileclient")!.appendingPathComponent("\(container.name).sqlite"))] if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/SettingsView.swift index 920fb24b..3e22665b 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/SettingsView.swift @@ -91,7 +91,7 @@ struct SettingsView: View { Button { close = false } label: { - Text("Back").font(.callout) + Image(systemName: "xmark") } } } diff --git a/Shared/Singleton/SessionManager.swift b/Shared/Singleton/SessionManager.swift index 6e559752..f0f27de8 100644 --- a/Shared/Singleton/SessionManager.swift +++ b/Shared/Singleton/SessionManager.swift @@ -81,7 +81,7 @@ final class SessionManager { fileprivate func getAuthToken(userID: String) -> String? { let keychain = KeychainSwift() - keychain.accessGroup = "4BHXT8RHFR.dev.pangmo5.swiftfin.sharedKeychain" + keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" return keychain.get("AccessToken_\(userID)") } @@ -134,7 +134,7 @@ final class SessionManager { _ = try? PersistenceController.shared.container.viewContext.save() let keychain = KeychainSwift() - keychain.accessGroup = "4BHXT8RHFR.dev.pangmo5.swiftfin.sharedKeychain" + keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" keychain.set(accessToken!, forKey: "AccessToken_\(user.user_id!)") generateAuthHeader(with: accessToken) @@ -151,7 +151,7 @@ final class SessionManager { nc.post(name: Notification.Name("didSignOut"), object: nil) let keychain = KeychainSwift() - keychain.accessGroup = "4BHXT8RHFR.dev.pangmo5.swiftfin.sharedKeychain" + keychain.accessGroup = "9R8RREG67J.me.vigue.jellyfin.sharedKeychain" keychain.delete("AccessToken_\(user?.user_id ?? "")") generateAuthHeader(with: nil) diff --git a/WidgetExtension/WidgetExtension.entitlements b/WidgetExtension/WidgetExtension.entitlements index b1737b11..b164e1cb 100644 --- a/WidgetExtension/WidgetExtension.entitlements +++ b/WidgetExtension/WidgetExtension.entitlements @@ -4,11 +4,11 @@ com.apple.security.application-groups - group.dev.pangmo5.swiftfin + group.me.vigue.jellyfin.mobileclient keychain-access-groups - $(AppIdentifierPrefix)dev.pangmo5.swiftfin.sharedKeychain + $(AppIdentifierPrefix)me.vigue.jellyfin.sharedKeychain From 28d8fc7c476c71dc54bb07a1beb46463d9160761 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 19:10:26 +0900 Subject: [PATCH 05/13] change "Auto" audioTrack logic --- JellyfinPlayer/VideoPlayer.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index 345733a5..295d05b5 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -558,11 +558,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } audioTrackArray.forEach { audio in - if Defaults[.autoSelectAudioLangCode] == "Auto", - audio.langCode.contains(Locale.current.languageCode ?? "") { - selectedAudioTrack = audio.id - mediaPlayer.currentAudioTrackIndex = audio.id - } else if audio.langCode.contains(Defaults[.autoSelectAudioLangCode]) { + if audio.langCode.contains(Defaults[.autoSelectAudioLangCode]) { selectedAudioTrack = audio.id mediaPlayer.currentAudioTrackIndex = audio.id } From 4eae19aa5364288f693685fb2a369a42e2d79802 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 19:12:04 +0900 Subject: [PATCH 06/13] fix str --- JellyfinPlayer/SettingsView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/SettingsView.swift index 3e22665b..ca6b3204 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/SettingsView.swift @@ -50,7 +50,7 @@ struct SettingsView: View { Section(header: Text("Accessibility")) { Toggle("Automatically show subtitles", isOn: $isAutoSelectSubtitles) - SearchablePicker(label: "Subtitles Language preferences", + SearchablePicker(label: "Subtitles language preferences", options: viewModel.langs, optionToString: { $0.name }, selected:Binding( @@ -58,7 +58,7 @@ struct SettingsView: View { set: {autoSelectSubtitlesLangcode = $0.isoCode} ) ) - SearchablePicker(label: "Audio Language preferences", + SearchablePicker(label: "Audio language preferences", options: viewModel.langs, optionToString: { $0.name }, selected: Binding( From 32e314d9e31b796cf7794b1496c2f06b08271eaa Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 19:13:35 +0900 Subject: [PATCH 07/13] rollback signing --- JellyfinPlayer.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index 336e8f0c..aefad28b 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -1096,7 +1096,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.kwangmin.swiftfin; + PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_VERSION = 5.0; @@ -1124,7 +1124,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0.0; - PRODUCT_BUNDLE_IDENTIFIER = dev.kwangmin.swiftfin; + PRODUCT_BUNDLE_IDENTIFIER = me.vigue.jellyfin; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_VERSION = 5.0; From 9dbcfb694e65d384e03625f6ea2d4dbb03bcf1ad Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Fri, 25 Jun 2021 19:28:37 +0900 Subject: [PATCH 08/13] fix tvOS build error --- .../VideoPlayer/VideoPlayerViewController.swift | 6 +++--- JellyfinPlayer.xcodeproj/project.pbxproj | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift index 74e9262d..da07fd6d 100644 --- a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift +++ b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift @@ -195,7 +195,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, item.videoUrl = streamURL - let disableSubtitleTrack = Subtitle(name: "None", id: -1, url: nil, delivery: .embed, codec: "") + let disableSubtitleTrack = Subtitle(name: "None", id: -1, url: nil, delivery: .embed, codec: "", langCode: "") subtitleTrackArray.append(disableSubtitleTrack) // Loop through media streams and add to array @@ -208,7 +208,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, deliveryUrl = URL(string: "\(ServerEnvironment.current.server.baseURI!)\(stream.deliveryUrl!)")! } - let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt") + let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt", langCode: stream.language ?? "") if stream.isDefault == true{ selectedCaptionTrack = Int32(stream.index!) @@ -220,7 +220,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, } if stream.type == .audio { - let track = AudioTrack(name: stream.displayTitle!, id: Int32(stream.index!)) + let track = AudioTrack(name: stream.displayTitle!, langCode: stream.language ?? "", id: Int32(stream.index!)) if stream.isDefault! == true { selectedAudioTrack = Int32(stream.index!) diff --git a/JellyfinPlayer.xcodeproj/project.pbxproj b/JellyfinPlayer.xcodeproj/project.pbxproj index aefad28b..a1ad7550 100644 --- a/JellyfinPlayer.xcodeproj/project.pbxproj +++ b/JellyfinPlayer.xcodeproj/project.pbxproj @@ -109,7 +109,6 @@ 6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; }; 6228B1C22670EB010067FD35 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFD263B596B003A4E83 /* PersistenceController.swift */; }; 624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; }; - 624C21762685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; }; 625CB5682678B6FB00530A6E /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5672678B6FB00530A6E /* SplashView.swift */; }; 625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5692678B71200530A6E /* SplashViewModel.swift */; }; 625CB56C2678C0FD00530A6E /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB56B2678C0FD00530A6E /* MainTabView.swift */; }; @@ -956,7 +955,6 @@ 536D3D81267BDFC60004248C /* PortraitItemElement.swift in Sources */, 531690E5267ABD5C005D8AB9 /* MainTabView.swift in Sources */, 5310695B2684E7EE00CFFDBA /* AudioView.swift in Sources */, - 624C21762685CF60007F1390 /* SearchablePickerView.swift in Sources */, 091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */, 53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */, 53ABFDEE26799DCD00886593 /* ImageView.swift in Sources */, From 5a27ddf714963ac094eed2b02e33e03c92f8d300 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Sat, 26 Jun 2021 02:32:41 +0900 Subject: [PATCH 09/13] fix requested changes --- JellyfinPlayer/SettingsView.swift | 19 +++++++------------ JellyfinPlayer/VideoPlayer.swift | 4 ++-- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/SettingsView.swift index ca6b3204..a2b44fd3 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/SettingsView.swift @@ -15,16 +15,11 @@ struct SettingsView: View { @ObservedObject var viewModel: SettingsViewModel @Binding var close: Bool - @Default(.inNetworkBandwidth) - var inNetworkStreamBitrate - @Default(.outOfNetworkBandwidth) - var outOfNetworkStreamBitrate - @Default(.isAutoSelectSubtitles) - var isAutoSelectSubtitles - @Default(.autoSelectSubtitlesLangCode) - var autoSelectSubtitlesLangcode - @Default(.autoSelectAudioLangCode) - var autoSelectAudioLangcode + @Default(.inNetworkBandwidth) var inNetworkStreamBitrate + @Default(.outOfNetworkBandwidth) var outOfNetworkStreamBitrate + @Default(.isAutoSelectSubtitles) var isAutoSelectSubtitles + @Default(.autoSelectSubtitlesLangCode) var autoSelectSubtitlesLangcode + @Default(.autoSelectAudioLangCode) var autoSelectAudioLangcode @State private var username: String = "" func onAppear() { @@ -50,7 +45,7 @@ struct SettingsView: View { Section(header: Text("Accessibility")) { Toggle("Automatically show subtitles", isOn: $isAutoSelectSubtitles) - SearchablePicker(label: "Subtitles language preferences", + SearchablePicker(label: "Preferred subtitle language", options: viewModel.langs, optionToString: { $0.name }, selected:Binding( @@ -58,7 +53,7 @@ struct SettingsView: View { set: {autoSelectSubtitlesLangcode = $0.isoCode} ) ) - SearchablePicker(label: "Audio language preferences", + SearchablePicker(label: "Preferred audio language", options: viewModel.langs, optionToString: { $0.name }, selected: Binding( diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index 295d05b5..4890aeec 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -543,7 +543,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } } - func setupTracksForPreferLanguage() { + func setupTracksForPreferredDefaults() { subtitleTrackArray.forEach { subtitle in if Defaults[.isAutoSelectSubtitles] { if Defaults[.autoSelectSubtitlesLangCode] == "Auto", @@ -616,7 +616,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe mediaPlayer.pause() mediaPlayer.play() - setupTracksForPreferLanguage() + setupTracksForPreferredDefaults() print("Local engine started.") } From 9e27114cf07421f17b5dcc2c88d37f7b14fa7d1e Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Sat, 26 Jun 2021 02:40:10 +0900 Subject: [PATCH 10/13] Remove unused import Fix formatting --- Shared/Extensions/SearchablePickerView.swift | 3 +-- Shared/ViewModels/SplashViewModel.swift | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Shared/Extensions/SearchablePickerView.swift b/Shared/Extensions/SearchablePickerView.swift index 5a9f20b8..91550271 100644 --- a/Shared/Extensions/SearchablePickerView.swift +++ b/Shared/Extensions/SearchablePickerView.swift @@ -11,8 +11,7 @@ import Foundation import SwiftUI private struct SearchablePickerView: View { - @Environment(\.presentationMode) - var presentationMode + @Environment(\.presentationMode) var presentationMode let options: [Selectable] let optionToString: (Selectable) -> String diff --git a/Shared/ViewModels/SplashViewModel.swift b/Shared/ViewModels/SplashViewModel.swift index 7450f9de..57776ab6 100644 --- a/Shared/ViewModels/SplashViewModel.swift +++ b/Shared/ViewModels/SplashViewModel.swift @@ -10,7 +10,6 @@ import Foundation import Combine import Nuke -import Defaults #if !os(tvOS) import WidgetKit From fe5f41838c3877704911ce50998999f1745a5e05 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Sat, 26 Jun 2021 03:05:05 +0900 Subject: [PATCH 11/13] fix naming --- .../VideoPlayer/VideoPlayerViewController.swift | 6 +++--- Shared/ViewModels/SettingsViewModel.swift | 8 ++++---- Shared/ViewModels/VideoPlayerModel.swift | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift index da07fd6d..12d8a4af 100644 --- a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift +++ b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift @@ -195,7 +195,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, item.videoUrl = streamURL - let disableSubtitleTrack = Subtitle(name: "None", id: -1, url: nil, delivery: .embed, codec: "", langCode: "") + let disableSubtitleTrack = Subtitle(name: "None", id: -1, url: nil, delivery: .embed, codec: "", languageCode: "") subtitleTrackArray.append(disableSubtitleTrack) // Loop through media streams and add to array @@ -208,7 +208,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, deliveryUrl = URL(string: "\(ServerEnvironment.current.server.baseURI!)\(stream.deliveryUrl!)")! } - let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt", langCode: stream.language ?? "") + let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt", languageCode: stream.language ?? "") if stream.isDefault == true{ selectedCaptionTrack = Int32(stream.index!) @@ -220,7 +220,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, } if stream.type == .audio { - let track = AudioTrack(name: stream.displayTitle!, langCode: stream.language ?? "", id: Int32(stream.index!)) + let track = AudioTrack(name: stream.displayTitle!, languageCode: stream.language ?? "", id: Int32(stream.index!)) if stream.isDefault! == true { selectedAudioTrack = Int32(stream.index!) diff --git a/Shared/ViewModels/SettingsViewModel.swift b/Shared/ViewModels/SettingsViewModel.swift index 12d03232..eba576d6 100644 --- a/Shared/ViewModels/SettingsViewModel.swift +++ b/Shared/ViewModels/SettingsViewModel.swift @@ -23,17 +23,17 @@ struct Bitrates: Codable, Hashable { public var value: Int } -struct Lang: Hashable { +struct TrackLanguage: Hashable { var name: String var isoCode: String - static let auto = Lang(name: "Auto", isoCode: "Auto") + static let auto = TrackLanguage(name: "Auto", isoCode: "Auto") } final class SettingsViewModel: ObservableObject { let currentLocale = Locale.current var bitrates: [Bitrates] = [] - var langs = [Lang]() + var langs = [TrackLanguage]() init() { let url = Bundle.main.url(forResource: "bitrates", withExtension: "json")! @@ -51,7 +51,7 @@ final class SettingsViewModel: ObservableObject { self.langs = Locale.isoLanguageCodes.compactMap { guard let name = currentLocale.localizedString(forLanguageCode: $0) else { return nil } - return Lang(name: name, isoCode: $0) + return TrackLanguage(name: name, isoCode: $0) }.sorted(by: { $0.name < $1.name }) self.langs.insert(.auto, at: 0) } diff --git a/Shared/ViewModels/VideoPlayerModel.swift b/Shared/ViewModels/VideoPlayerModel.swift index 2598b3f8..117c22bb 100644 --- a/Shared/ViewModels/VideoPlayerModel.swift +++ b/Shared/ViewModels/VideoPlayerModel.swift @@ -16,12 +16,12 @@ struct Subtitle { var url: URL? var delivery: SubtitleDeliveryMethod var codec: String - var langCode: String + var languageCode: String } struct AudioTrack { var name: String - var langCode: String + var languageCode: String var id: Int32 } From 3d2e12462fddf3855571d7b69efde0840b7faaee Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Sat, 26 Jun 2021 03:14:58 +0900 Subject: [PATCH 12/13] fix build error --- JellyfinPlayer/VideoPlayer.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index 4890aeec..198dd4cd 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -455,7 +455,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe item.videoType = .transcode item.videoUrl = streamURL! - let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "", langCode: "") + let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "", languageCode: "") subtitleTrackArray.append(disableSubtitleTrack) // Loop through media streams and add to array @@ -467,7 +467,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } else { deliveryUrl = nil } - let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt", langCode: stream.language ?? "") + let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec ?? "webvtt", languageCode: stream.language ?? "") if subtitle.delivery != .encode { subtitleTrackArray.append(subtitle) @@ -475,7 +475,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } if stream.type == .audio { - let subtitle = AudioTrack(name: stream.displayTitle!, langCode: stream.language ?? "", id: Int32(stream.index!)) + let subtitle = AudioTrack(name: stream.displayTitle!, languageCode: stream.language ?? "", id: Int32(stream.index!)) if stream.isDefault! == true { selectedAudioTrack = Int32(stream.index!) } @@ -499,7 +499,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe item.videoUrl = streamURL item.videoType = .directPlay - let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "", langCode: "") + let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: nil, delivery: .embed, codec: "", languageCode: "") subtitleTrackArray.append(disableSubtitleTrack) // Loop through media streams and add to array @@ -511,7 +511,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } else { deliveryUrl = nil } - let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec!, langCode: stream.language ?? "") + let subtitle = Subtitle(name: stream.displayTitle ?? "Unknown", id: Int32(stream.index!), url: deliveryUrl, delivery: stream.deliveryMethod!, codec: stream.codec!, languageCode: stream.language ?? "") if subtitle.delivery != .encode { subtitleTrackArray.append(subtitle) @@ -519,7 +519,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } if stream.type == .audio { - let subtitle = AudioTrack(name: stream.displayTitle!, langCode: stream.language ?? "", id: Int32(stream.index!)) + let subtitle = AudioTrack(name: stream.displayTitle!, languageCode: stream.language ?? "", id: Int32(stream.index!)) if stream.isDefault! == true { selectedAudioTrack = Int32(stream.index!) } @@ -547,10 +547,10 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe subtitleTrackArray.forEach { subtitle in if Defaults[.isAutoSelectSubtitles] { if Defaults[.autoSelectSubtitlesLangCode] == "Auto", - subtitle.langCode.contains(Locale.current.languageCode ?? "") { + subtitle.languageCode.contains(Locale.current.languageCode ?? "") { selectedCaptionTrack = subtitle.id mediaPlayer.currentVideoSubTitleIndex = subtitle.id - } else if subtitle.langCode.contains(Defaults[.autoSelectSubtitlesLangCode]) { + } else if subtitle.languageCode.contains(Defaults[.autoSelectSubtitlesLangCode]) { selectedCaptionTrack = subtitle.id mediaPlayer.currentVideoSubTitleIndex = subtitle.id } @@ -558,7 +558,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } audioTrackArray.forEach { audio in - if audio.langCode.contains(Defaults[.autoSelectAudioLangCode]) { + if audio.languageCode.contains(Defaults[.autoSelectAudioLangCode]) { selectedAudioTrack = audio.id mediaPlayer.currentAudioTrackIndex = audio.id } From 7fadbdfe7cd9581bf4509b8eb52685551f123d08 Mon Sep 17 00:00:00 2001 From: PangMo5 Date: Sat, 26 Jun 2021 03:34:19 +0900 Subject: [PATCH 13/13] fix build error --- JellyfinPlayer/SettingsView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/JellyfinPlayer/SettingsView.swift b/JellyfinPlayer/SettingsView.swift index a2b44fd3..9c15655f 100644 --- a/JellyfinPlayer/SettingsView.swift +++ b/JellyfinPlayer/SettingsView.swift @@ -48,7 +48,7 @@ struct SettingsView: View { SearchablePicker(label: "Preferred subtitle language", options: viewModel.langs, optionToString: { $0.name }, - selected:Binding( + selected:Binding( get: { viewModel.langs.first(where: { $0.isoCode == autoSelectSubtitlesLangcode }) ?? .auto }, set: {autoSelectSubtitlesLangcode = $0.isoCode} ) @@ -56,7 +56,7 @@ struct SettingsView: View { SearchablePicker(label: "Preferred audio language", options: viewModel.langs, optionToString: { $0.name }, - selected: Binding( + selected: Binding( get: { viewModel.langs.first(where: { $0.isoCode == autoSelectAudioLangcode }) ?? .auto }, set: { autoSelectAudioLangcode = $0.isoCode} )