Merge pull request #89 from PangMo5/PangMo5/settings
Prefer language settings #87
This commit is contained in:
commit
75e7081cd6
|
@ -12,6 +12,7 @@ import TVVLCKit
|
||||||
import MediaPlayer
|
import MediaPlayer
|
||||||
import JellyfinAPI
|
import JellyfinAPI
|
||||||
import Combine
|
import Combine
|
||||||
|
import Defaults
|
||||||
|
|
||||||
protocol VideoPlayerSettingsDelegate: AnyObject {
|
protocol VideoPlayerSettingsDelegate: AnyObject {
|
||||||
func selectNew(audioTrack id: Int32)
|
func selectNew(audioTrack id: Int32)
|
||||||
|
@ -149,8 +150,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
||||||
|
|
||||||
func fetchVideo() {
|
func fetchVideo() {
|
||||||
// Fetch max bitrate from UserDefaults depending on current connection mode
|
// Fetch max bitrate from UserDefaults depending on current connection mode
|
||||||
let defaults = UserDefaults.standard
|
let maxBitrate = Defaults[.inNetworkBandwidth]
|
||||||
let maxBitrate = defaults.integer(forKey: "InNetworkBandwidth")
|
|
||||||
|
|
||||||
// Build a device profile
|
// Build a device profile
|
||||||
let builder = DeviceProfileBuilder()
|
let builder = DeviceProfileBuilder()
|
||||||
|
@ -195,7 +195,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
||||||
|
|
||||||
item.videoUrl = streamURL
|
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: "", languageCode: "")
|
||||||
subtitleTrackArray.append(disableSubtitleTrack)
|
subtitleTrackArray.append(disableSubtitleTrack)
|
||||||
|
|
||||||
// Loop through media streams and add to array
|
// 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!)")!
|
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", languageCode: stream.language ?? "")
|
||||||
|
|
||||||
if stream.isDefault == true{
|
if stream.isDefault == true{
|
||||||
selectedCaptionTrack = Int32(stream.index!)
|
selectedCaptionTrack = Int32(stream.index!)
|
||||||
|
@ -220,7 +220,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate,
|
||||||
}
|
}
|
||||||
|
|
||||||
if stream.type == .audio {
|
if stream.type == .audio {
|
||||||
let track = AudioTrack(name: stream.displayTitle!, id: Int32(stream.index!))
|
let track = AudioTrack(name: stream.displayTitle!, languageCode: stream.language ?? "", id: Int32(stream.index!))
|
||||||
|
|
||||||
if stream.isDefault! == true {
|
if stream.isDefault! == true {
|
||||||
selectedAudioTrack = Int32(stream.index!)
|
selectedAudioTrack = Int32(stream.index!)
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
621C638026672A30004216EA /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 621C637F26672A30004216EA /* NukeUI */; };
|
621C638026672A30004216EA /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 621C637F26672A30004216EA /* NukeUI */; };
|
||||||
6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; };
|
6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */; };
|
||||||
6228B1C22670EB010067FD35 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFD263B596B003A4E83 /* PersistenceController.swift */; };
|
6228B1C22670EB010067FD35 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFD263B596B003A4E83 /* PersistenceController.swift */; };
|
||||||
|
624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 624C21742685CF60007F1390 /* SearchablePickerView.swift */; };
|
||||||
625CB5682678B6FB00530A6E /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5672678B6FB00530A6E /* SplashView.swift */; };
|
625CB5682678B6FB00530A6E /* SplashView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5672678B6FB00530A6E /* SplashView.swift */; };
|
||||||
625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5692678B71200530A6E /* SplashViewModel.swift */; };
|
625CB56A2678B71200530A6E /* SplashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB5692678B71200530A6E /* SplashViewModel.swift */; };
|
||||||
625CB56C2678C0FD00530A6E /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB56B2678C0FD00530A6E /* MainTabView.swift */; };
|
625CB56C2678C0FD00530A6E /* MainTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 625CB56B2678C0FD00530A6E /* MainTabView.swift */; };
|
||||||
|
@ -133,6 +134,10 @@
|
||||||
628B95382670CDAB0091AF3B /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */; };
|
628B95382670CDAB0091AF3B /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 5377CBFF263B596B003A4E83 /* Model.xcdatamodeld */; };
|
||||||
628B953A2670CE250091AF3B /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 628B95392670CE250091AF3B /* KeychainSwift */; };
|
628B953A2670CE250091AF3B /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 628B95392670CE250091AF3B /* KeychainSwift */; };
|
||||||
628B953C2670D2430091AF3B /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621338922660107500A81A2A /* StringExtensions.swift */; };
|
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 */; };
|
62E632DA267D2BC40063E547 /* LatestMediaViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */; };
|
||||||
62E632DC267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; };
|
62E632DC267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; };
|
||||||
62E632DD267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; };
|
62E632DD267D2E130063E547 /* LibrarySearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */; };
|
||||||
|
@ -285,6 +290,7 @@
|
||||||
621338922660107500A81A2A /* StringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = "<group>"; };
|
621338922660107500A81A2A /* StringExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = "<group>"; };
|
||||||
621338B22660A07800A81A2A /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
621338B22660A07800A81A2A /* LazyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
||||||
6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallaxHeader.swift; sourceTree = "<group>"; };
|
6225FCCA2663841E00E067F6 /* ParallaxHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallaxHeader.swift; sourceTree = "<group>"; };
|
||||||
|
624C21742685CF60007F1390 /* SearchablePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchablePickerView.swift; sourceTree = "<group>"; };
|
||||||
625CB5672678B6FB00530A6E /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = "<group>"; };
|
625CB5672678B6FB00530A6E /* SplashView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashView.swift; sourceTree = "<group>"; };
|
||||||
625CB5692678B71200530A6E /* SplashViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashViewModel.swift; sourceTree = "<group>"; };
|
625CB5692678B71200530A6E /* SplashViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashViewModel.swift; sourceTree = "<group>"; };
|
||||||
625CB56B2678C0FD00530A6E /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
|
625CB56B2678C0FD00530A6E /* MainTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -304,6 +310,7 @@
|
||||||
628B952A2670CABE0091AF3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
628B952A2670CABE0091AF3B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
628B95362670CB800091AF3B /* JellyfinWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinWidget.swift; sourceTree = "<group>"; };
|
628B95362670CB800091AF3B /* JellyfinWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JellyfinWidget.swift; sourceTree = "<group>"; };
|
||||||
628B953B2670D1FC0091AF3B /* WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetExtension.entitlements; sourceTree = "<group>"; };
|
628B953B2670D1FC0091AF3B /* WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||||
|
62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsExtension.swift; sourceTree = "<group>"; };
|
||||||
62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestMediaViewModel.swift; sourceTree = "<group>"; };
|
62E632D9267D2BC40063E547 /* LatestMediaViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestMediaViewModel.swift; sourceTree = "<group>"; };
|
||||||
62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = "<group>"; };
|
62E632DB267D2E130063E547 /* LibrarySearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibrarySearchViewModel.swift; sourceTree = "<group>"; };
|
||||||
62E632DF267D30CA0063E547 /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = "<group>"; };
|
62E632DF267D30CA0063E547 /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = "<group>"; };
|
||||||
|
@ -331,6 +338,7 @@
|
||||||
53EC6E1E267E80AC006DD26A /* Pods_JellyfinPlayer_tvOS.framework in Frameworks */,
|
53EC6E1E267E80AC006DD26A /* Pods_JellyfinPlayer_tvOS.framework in Frameworks */,
|
||||||
53A431BF266B0FFE0016769F /* JellyfinAPI in Frameworks */,
|
53A431BF266B0FFE0016769F /* JellyfinAPI in Frameworks */,
|
||||||
535870912669D7A800D05A09 /* Introspect in Frameworks */,
|
535870912669D7A800D05A09 /* Introspect in Frameworks */,
|
||||||
|
62CB3F482685BB3B003D0A6F /* Defaults in Frameworks */,
|
||||||
5358708D2669D7A800D05A09 /* KeychainSwift in Frameworks */,
|
5358708D2669D7A800D05A09 /* KeychainSwift in Frameworks */,
|
||||||
536D3D84267BEA550004248C /* ParallaxView in Frameworks */,
|
536D3D84267BEA550004248C /* ParallaxView in Frameworks */,
|
||||||
53ABFDDC267972BF00886593 /* TVServices.framework in Frameworks */,
|
53ABFDDC267972BF00886593 /* TVServices.framework in Frameworks */,
|
||||||
|
@ -343,6 +351,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
62CB3F462685BAF7003D0A6F /* Defaults in Frameworks */,
|
||||||
5338F757263B7E2E0014BF09 /* KeychainSwift in Frameworks */,
|
5338F757263B7E2E0014BF09 /* KeychainSwift in Frameworks */,
|
||||||
53EC6E25267EB10F006DD26A /* SwiftyJSON in Frameworks */,
|
53EC6E25267EB10F006DD26A /* SwiftyJSON in Frameworks */,
|
||||||
53EC6E21267E80B1006DD26A /* Pods_JellyfinPlayer_iOS.framework in Frameworks */,
|
53EC6E21267E80B1006DD26A /* Pods_JellyfinPlayer_iOS.framework in Frameworks */,
|
||||||
|
@ -591,6 +600,8 @@
|
||||||
6267B3D526710B8900A7371D /* CollectionExtensions.swift */,
|
6267B3D526710B8900A7371D /* CollectionExtensions.swift */,
|
||||||
6267B3D92671138200A7371D /* ImageExtensions.swift */,
|
6267B3D92671138200A7371D /* ImageExtensions.swift */,
|
||||||
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */,
|
62EC353326766B03000E9F2D /* DeviceRotationViewModifier.swift */,
|
||||||
|
62CB3F4A2685BB77003D0A6F /* DefaultsExtension.swift */,
|
||||||
|
624C21742685CF60007F1390 /* SearchablePickerView.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -662,6 +673,7 @@
|
||||||
53A431BE266B0FFE0016769F /* JellyfinAPI */,
|
53A431BE266B0FFE0016769F /* JellyfinAPI */,
|
||||||
53ABFDEC26799D7700886593 /* ActivityIndicator */,
|
53ABFDEC26799D7700886593 /* ActivityIndicator */,
|
||||||
536D3D83267BEA550004248C /* ParallaxView */,
|
536D3D83267BEA550004248C /* ParallaxView */,
|
||||||
|
62CB3F472685BB3B003D0A6F /* Defaults */,
|
||||||
);
|
);
|
||||||
productName = "JellyfinPlayer tvOS";
|
productName = "JellyfinPlayer tvOS";
|
||||||
productReference = 535870602669D21600D05A09 /* JellyfinPlayer tvOS.app */;
|
productReference = 535870602669D21600D05A09 /* JellyfinPlayer tvOS.app */;
|
||||||
|
@ -693,6 +705,7 @@
|
||||||
53A431BC266B0FF20016769F /* JellyfinAPI */,
|
53A431BC266B0FF20016769F /* JellyfinAPI */,
|
||||||
625CB5792678C4A400530A6E /* ActivityIndicator */,
|
625CB5792678C4A400530A6E /* ActivityIndicator */,
|
||||||
53EC6E24267EB10F006DD26A /* SwiftyJSON */,
|
53EC6E24267EB10F006DD26A /* SwiftyJSON */,
|
||||||
|
62CB3F452685BAF7003D0A6F /* Defaults */,
|
||||||
);
|
);
|
||||||
productName = JellyfinPlayer;
|
productName = JellyfinPlayer;
|
||||||
productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer iOS.app */;
|
productReference = 5377CBF1263B596A003A4E83 /* JellyfinPlayer iOS.app */;
|
||||||
|
@ -761,6 +774,7 @@
|
||||||
625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */,
|
625CB5782678C4A400530A6E /* XCRemoteSwiftPackageReference "ActivityIndicator" */,
|
||||||
536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */,
|
536D3D82267BEA550004248C /* XCRemoteSwiftPackageReference "ParallaxView" */,
|
||||||
53EC6E23267EB10F006DD26A /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
53EC6E23267EB10F006DD26A /* XCRemoteSwiftPackageReference "SwiftyJSON" */,
|
||||||
|
62CB3F442685BAF7003D0A6F /* XCRemoteSwiftPackageReference "Defaults" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
|
productRefGroup = 5377CBF2263B596A003A4E83 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
@ -944,6 +958,7 @@
|
||||||
091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */,
|
091B5A8D268315D400D78B61 /* ServerDiscovery.swift in Sources */,
|
||||||
53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */,
|
53ABFDE7267974EF00886593 /* ConnectToServerViewModel.swift in Sources */,
|
||||||
53ABFDEE26799DCD00886593 /* ImageView.swift in Sources */,
|
53ABFDEE26799DCD00886593 /* ImageView.swift in Sources */,
|
||||||
|
62CB3F4C2685BB77003D0A6F /* DefaultsExtension.swift in Sources */,
|
||||||
62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
62E632E4267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||||
5358706C2669D21700D05A09 /* PersistenceController.swift in Sources */,
|
5358706C2669D21700D05A09 /* PersistenceController.swift in Sources */,
|
||||||
535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */,
|
535870AA2669D8AE00D05A09 /* BlurHashDecode.swift in Sources */,
|
||||||
|
@ -982,6 +997,7 @@
|
||||||
6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */,
|
6225FCCB2663841E00E067F6 /* ParallaxHeader.swift in Sources */,
|
||||||
625CB5772678C34300530A6E /* ConnectToServerViewModel.swift in Sources */,
|
625CB5772678C34300530A6E /* ConnectToServerViewModel.swift in Sources */,
|
||||||
536D3D78267BD5C30004248C /* ViewModel.swift in Sources */,
|
536D3D78267BD5C30004248C /* ViewModel.swift in Sources */,
|
||||||
|
62CB3F4B2685BB77003D0A6F /* DefaultsExtension.swift in Sources */,
|
||||||
53DE4BD02670961400739748 /* EpisodeItemView.swift in Sources */,
|
53DE4BD02670961400739748 /* EpisodeItemView.swift in Sources */,
|
||||||
53F8377D265FF67C00F456B3 /* VideoPlayerSettingsView.swift in Sources */,
|
53F8377D265FF67C00F456B3 /* VideoPlayerSettingsView.swift in Sources */,
|
||||||
53192D5D265AA78A008A4215 /* DeviceProfileBuilder.swift in Sources */,
|
53192D5D265AA78A008A4215 /* DeviceProfileBuilder.swift in Sources */,
|
||||||
|
@ -1008,6 +1024,7 @@
|
||||||
621338B32660A07800A81A2A /* LazyView.swift in Sources */,
|
621338B32660A07800A81A2A /* LazyView.swift in Sources */,
|
||||||
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */,
|
531AC8BF26750DE20091C7EB /* ImageView.swift in Sources */,
|
||||||
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
62E632E0267D30CA0063E547 /* LibraryViewModel.swift in Sources */,
|
||||||
|
624C21752685CF60007F1390 /* SearchablePickerView.swift in Sources */,
|
||||||
62EC352F267666A5000E9F2D /* SessionManager.swift in Sources */,
|
62EC352F267666A5000E9F2D /* SessionManager.swift in Sources */,
|
||||||
62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
62E632E3267D3BA60063E547 /* MovieItemViewModel.swift in Sources */,
|
||||||
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
|
091B5A8A2683142E00D78B61 /* ServerDiscovery.swift in Sources */,
|
||||||
|
@ -1450,6 +1467,14 @@
|
||||||
minimumVersion = 1.1.0;
|
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 */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
@ -1533,6 +1558,16 @@
|
||||||
package = 5338F755263B7E2E0014BF09 /* XCRemoteSwiftPackageReference "keychain-swift" */;
|
package = 5338F755263B7E2E0014BF09 /* XCRemoteSwiftPackageReference "keychain-swift" */;
|
||||||
productName = KeychainSwift;
|
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 */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
|
|
||||||
/* Begin XCVersionGroup section */
|
/* Begin XCVersionGroup section */
|
||||||
|
|
|
@ -19,6 +19,15 @@
|
||||||
"version": "0.6.0"
|
"version": "0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"package": "Defaults",
|
||||||
|
"repositoryURL": "https://github.com/sindresorhus/Defaults",
|
||||||
|
"state": {
|
||||||
|
"branch": null,
|
||||||
|
"revision": "63d93f97ad545c8bceb125a8a36175ea705f7cf5",
|
||||||
|
"version": "5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"package": "Gifu",
|
"package": "Gifu",
|
||||||
"repositoryURL": "https://github.com/kaishin/Gifu",
|
"repositoryURL": "https://github.com/kaishin/Gifu",
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import CoreData
|
import CoreData
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Defaults
|
||||||
|
|
||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
@Environment(\.managedObjectContext) private var viewContext
|
@Environment(\.managedObjectContext) private var viewContext
|
||||||
|
@ -14,19 +15,15 @@ struct SettingsView: View {
|
||||||
@ObservedObject var viewModel: SettingsViewModel
|
@ObservedObject var viewModel: SettingsViewModel
|
||||||
|
|
||||||
@Binding var close: Bool
|
@Binding var close: Bool
|
||||||
@State private var inNetworkStreamBitrate: Int = 40_000_000
|
@Default(.inNetworkBandwidth) var inNetworkStreamBitrate
|
||||||
@State private var outOfNetworkStreamBitrate: Int = 40_000_000
|
@Default(.outOfNetworkBandwidth) var outOfNetworkStreamBitrate
|
||||||
@State private var autoSelectSubtitles: Bool = false
|
@Default(.isAutoSelectSubtitles) var isAutoSelectSubtitles
|
||||||
@State private var autoSelectSubtitlesLangcode: String = "none"
|
@Default(.autoSelectSubtitlesLangCode) var autoSelectSubtitlesLangcode
|
||||||
|
@Default(.autoSelectAudioLangCode) var autoSelectAudioLangcode
|
||||||
@State private var username: String = ""
|
@State private var username: String = ""
|
||||||
|
|
||||||
func onAppear() {
|
func onAppear() {
|
||||||
let defaults = UserDefaults.standard
|
|
||||||
username = SessionManager.current.user.username ?? ""
|
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 {
|
var body: some View {
|
||||||
|
@ -37,27 +34,33 @@ struct SettingsView: View {
|
||||||
ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
||||||
Text(bitrate.name).tag(bitrate.value)
|
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) {
|
Picker("Default remote quality", selection: $outOfNetworkStreamBitrate) {
|
||||||
ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
ForEach(self.viewModel.bitrates, id: \.self) { bitrate in
|
||||||
Text(bitrate.name).tag(bitrate.value)
|
Text(bitrate.name).tag(bitrate.value)
|
||||||
}
|
}
|
||||||
}.onChange(of: outOfNetworkStreamBitrate) { _ in
|
|
||||||
let defaults = UserDefaults.standard
|
|
||||||
defaults.setValue(_outOfNetworkStreamBitrate.wrappedValue, forKey: "OutOfNetworkBandwidth")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section(header: Text("Accessibility")) {
|
Section(header: Text("Accessibility")) {
|
||||||
Toggle("Automatically show subtitles", isOn: $autoSelectSubtitles).onChange(of: autoSelectSubtitles, perform: { _ in
|
Toggle("Automatically show subtitles", isOn: $isAutoSelectSubtitles)
|
||||||
let defaults = UserDefaults.standard
|
SearchablePicker(label: "Preferred subtitle language",
|
||||||
defaults.setValue(autoSelectSubtitles, forKey: "AutoSelectSubtitles")
|
options: viewModel.langs,
|
||||||
})
|
optionToString: { $0.name },
|
||||||
Picker("Language preferences", selection: $autoSelectSubtitlesLangcode) {}
|
selected:Binding<TrackLanguage>(
|
||||||
|
get: { viewModel.langs.first(where: { $0.isoCode == autoSelectSubtitlesLangcode }) ?? .auto },
|
||||||
|
set: {autoSelectSubtitlesLangcode = $0.isoCode}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SearchablePicker(label: "Preferred audio language",
|
||||||
|
options: viewModel.langs,
|
||||||
|
optionToString: { $0.name },
|
||||||
|
selected: Binding<TrackLanguage>(
|
||||||
|
get: { viewModel.langs.first(where: { $0.isoCode == autoSelectAudioLangcode }) ?? .auto },
|
||||||
|
set: { autoSelectAudioLangcode = $0.isoCode}
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
|
@ -83,7 +86,7 @@ struct SettingsView: View {
|
||||||
Button {
|
Button {
|
||||||
close = false
|
close = false
|
||||||
} label: {
|
} label: {
|
||||||
Text("Back").font(.callout)
|
Image(systemName: "xmark")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import MediaPlayer
|
||||||
import Combine
|
import Combine
|
||||||
import GoogleCast
|
import GoogleCast
|
||||||
import SwiftyJSON
|
import SwiftyJSON
|
||||||
|
import Defaults
|
||||||
|
|
||||||
enum PlayerDestination {
|
enum PlayerDestination {
|
||||||
case remote
|
case remote
|
||||||
|
@ -417,8 +417,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
mediaPlayer.drawable = videoContentView
|
mediaPlayer.drawable = videoContentView
|
||||||
|
|
||||||
// Fetch max bitrate from UserDefaults depending on current connection mode
|
// Fetch max bitrate from UserDefaults depending on current connection mode
|
||||||
let defaults = UserDefaults.standard
|
let maxBitrate = Defaults[.inNetworkBandwidth]
|
||||||
let maxBitrate = defaults.integer(forKey: "InNetworkBandwidth")
|
|
||||||
|
|
||||||
// Build a device profile
|
// Build a device profile
|
||||||
let builder = DeviceProfileBuilder()
|
let builder = DeviceProfileBuilder()
|
||||||
|
@ -456,7 +455,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
item.videoType = .transcode
|
item.videoType = .transcode
|
||||||
item.videoUrl = streamURL!
|
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: "", languageCode: "")
|
||||||
subtitleTrackArray.append(disableSubtitleTrack)
|
subtitleTrackArray.append(disableSubtitleTrack)
|
||||||
|
|
||||||
// Loop through media streams and add to array
|
// Loop through media streams and add to array
|
||||||
|
@ -468,7 +467,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
} else {
|
} else {
|
||||||
deliveryUrl = nil
|
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", languageCode: stream.language ?? "")
|
||||||
|
|
||||||
if subtitle.delivery != .encode {
|
if subtitle.delivery != .encode {
|
||||||
subtitleTrackArray.append(subtitle)
|
subtitleTrackArray.append(subtitle)
|
||||||
|
@ -476,7 +475,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
}
|
}
|
||||||
|
|
||||||
if stream.type == .audio {
|
if stream.type == .audio {
|
||||||
let subtitle = AudioTrack(name: stream.displayTitle!, id: Int32(stream.index!))
|
let subtitle = AudioTrack(name: stream.displayTitle!, languageCode: stream.language ?? "", id: Int32(stream.index!))
|
||||||
if stream.isDefault! == true {
|
if stream.isDefault! == true {
|
||||||
selectedAudioTrack = Int32(stream.index!)
|
selectedAudioTrack = Int32(stream.index!)
|
||||||
}
|
}
|
||||||
|
@ -500,7 +499,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
item.videoUrl = streamURL
|
item.videoUrl = streamURL
|
||||||
item.videoType = .directPlay
|
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: "", languageCode: "")
|
||||||
subtitleTrackArray.append(disableSubtitleTrack)
|
subtitleTrackArray.append(disableSubtitleTrack)
|
||||||
|
|
||||||
// Loop through media streams and add to array
|
// Loop through media streams and add to array
|
||||||
|
@ -512,7 +511,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
} else {
|
} else {
|
||||||
deliveryUrl = nil
|
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!, languageCode: stream.language ?? "")
|
||||||
|
|
||||||
if subtitle.delivery != .encode {
|
if subtitle.delivery != .encode {
|
||||||
subtitleTrackArray.append(subtitle)
|
subtitleTrackArray.append(subtitle)
|
||||||
|
@ -520,7 +519,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
}
|
}
|
||||||
|
|
||||||
if stream.type == .audio {
|
if stream.type == .audio {
|
||||||
let subtitle = AudioTrack(name: stream.displayTitle!, id: Int32(stream.index!))
|
let subtitle = AudioTrack(name: stream.displayTitle!, languageCode: stream.language ?? "", id: Int32(stream.index!))
|
||||||
if stream.isDefault! == true {
|
if stream.isDefault! == true {
|
||||||
selectedAudioTrack = Int32(stream.index!)
|
selectedAudioTrack = Int32(stream.index!)
|
||||||
}
|
}
|
||||||
|
@ -544,6 +543,28 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupTracksForPreferredDefaults() {
|
||||||
|
subtitleTrackArray.forEach { subtitle in
|
||||||
|
if Defaults[.isAutoSelectSubtitles] {
|
||||||
|
if Defaults[.autoSelectSubtitlesLangCode] == "Auto",
|
||||||
|
subtitle.languageCode.contains(Locale.current.languageCode ?? "") {
|
||||||
|
selectedCaptionTrack = subtitle.id
|
||||||
|
mediaPlayer.currentVideoSubTitleIndex = subtitle.id
|
||||||
|
} else if subtitle.languageCode.contains(Defaults[.autoSelectSubtitlesLangCode]) {
|
||||||
|
selectedCaptionTrack = subtitle.id
|
||||||
|
mediaPlayer.currentVideoSubTitleIndex = subtitle.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
audioTrackArray.forEach { audio in
|
||||||
|
if audio.languageCode.contains(Defaults[.autoSelectAudioLangCode]) {
|
||||||
|
selectedAudioTrack = audio.id
|
||||||
|
mediaPlayer.currentAudioTrackIndex = audio.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func startLocalPlaybackEngine(_ fetchCaptions: Bool) {
|
func startLocalPlaybackEngine(_ fetchCaptions: Bool) {
|
||||||
print("Local playback engine starting.")
|
print("Local playback engine starting.")
|
||||||
mediaPlayer.media = VLCMedia(url: playbackItem.videoUrl)
|
mediaPlayer.media = VLCMedia(url: playbackItem.videoUrl)
|
||||||
|
@ -595,6 +616,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe
|
||||||
|
|
||||||
mediaPlayer.pause()
|
mediaPlayer.pause()
|
||||||
mediaPlayer.play()
|
mediaPlayer.play()
|
||||||
|
setupTracksForPreferredDefaults()
|
||||||
|
|
||||||
print("Local engine started.")
|
print("Local engine started.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<Int>("InNetworkBandwidth", default: 40_000_000)
|
||||||
|
static let outOfNetworkBandwidth = Key<Int>("OutOfNetworkBandwidth", default: 40_000_000)
|
||||||
|
static let isAutoSelectSubtitles = Key<Bool>("isAutoSelectSubtitles", default: false)
|
||||||
|
static let autoSelectSubtitlesLangCode = Key<String>("AutoSelectSubtitlesLangCode", default: "Auto")
|
||||||
|
static let autoSelectAudioLangCode = Key<String>("AutoSelectAudioLangCode", default: "Auto")
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
//
|
||||||
|
/*
|
||||||
|
* 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<Selectable: Hashable>: 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<Selectable: Hashable>: 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,8 +23,17 @@ struct Bitrates: Codable, Hashable {
|
||||||
public var value: Int
|
public var value: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TrackLanguage: Hashable {
|
||||||
|
var name: String
|
||||||
|
var isoCode: String
|
||||||
|
|
||||||
|
static let auto = TrackLanguage(name: "Auto", isoCode: "Auto")
|
||||||
|
}
|
||||||
|
|
||||||
final class SettingsViewModel: ObservableObject {
|
final class SettingsViewModel: ObservableObject {
|
||||||
|
let currentLocale = Locale.current
|
||||||
var bitrates: [Bitrates] = []
|
var bitrates: [Bitrates] = []
|
||||||
|
var langs = [TrackLanguage]()
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let url = Bundle.main.url(forResource: "bitrates", withExtension: "json")!
|
let url = Bundle.main.url(forResource: "bitrates", withExtension: "json")!
|
||||||
|
@ -39,5 +48,11 @@ final class SettingsViewModel: ObservableObject {
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.langs = Locale.isoLanguageCodes.compactMap {
|
||||||
|
guard let name = currentLocale.localizedString(forLanguageCode: $0) else { return nil }
|
||||||
|
return TrackLanguage(name: name, isoCode: $0)
|
||||||
|
}.sorted(by: { $0.name < $1.name })
|
||||||
|
self.langs.insert(.auto, at: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,6 @@ final class SplashViewModel: ViewModel {
|
||||||
WidgetCenter.shared.reloadAllTimelines()
|
WidgetCenter.shared.reloadAllTimelines()
|
||||||
#endif
|
#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
|
let nc = NotificationCenter.default
|
||||||
nc.addObserver(self, selector: #selector(didLogIn), name: Notification.Name("didSignIn"), object: nil)
|
nc.addObserver(self, selector: #selector(didLogIn), name: Notification.Name("didSignIn"), object: nil)
|
||||||
nc.addObserver(self, selector: #selector(didLogOut), name: Notification.Name("didSignOut"), object: nil)
|
nc.addObserver(self, selector: #selector(didLogOut), name: Notification.Name("didSignOut"), object: nil)
|
||||||
|
|
|
@ -16,10 +16,12 @@ struct Subtitle {
|
||||||
var url: URL?
|
var url: URL?
|
||||||
var delivery: SubtitleDeliveryMethod
|
var delivery: SubtitleDeliveryMethod
|
||||||
var codec: String
|
var codec: String
|
||||||
|
var languageCode: String
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AudioTrack {
|
struct AudioTrack {
|
||||||
var name: String
|
var name: String
|
||||||
|
var languageCode: String
|
||||||
var id: Int32
|
var id: Int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue