cleanup
This commit is contained in:
parent
41669a949d
commit
fdea0d4573
|
@ -470,7 +470,7 @@
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 9;
|
CURRENT_PROJECT_VERSION = 10;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = 9R8RREG67J;
|
DEVELOPMENT_TEAM = 9R8RREG67J;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
|
@ -499,7 +499,7 @@
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 9;
|
CURRENT_PROJECT_VERSION = 10;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"JellyfinPlayer/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = 9R8RREG67J;
|
DEVELOPMENT_TEAM = 9R8RREG67J;
|
||||||
|
|
|
@ -16,6 +16,7 @@ import Sentry
|
||||||
|
|
||||||
struct ConnectToServerView: View {
|
struct ConnectToServerView: View {
|
||||||
@Environment(\.managedObjectContext) private var viewContext
|
@Environment(\.managedObjectContext) private var viewContext
|
||||||
|
@EnvironmentObject var globalData: GlobalData
|
||||||
@EnvironmentObject var jsi: justSignedIn
|
@EnvironmentObject var jsi: justSignedIn
|
||||||
@State private var uri = "";
|
@State private var uri = "";
|
||||||
@State private var isWorking = false;
|
@State private var isWorking = false;
|
||||||
|
@ -80,12 +81,9 @@ struct ConnectToServerView: View {
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let response):
|
case .success(let response):
|
||||||
let server = response.body
|
let server = response.body
|
||||||
print("Found server: " + server.ServerName)
|
|
||||||
_serverName.wrappedValue = server.ServerName
|
_serverName.wrappedValue = server.ServerName
|
||||||
_server_id.wrappedValue = server.Id
|
_server_id.wrappedValue = server.Id
|
||||||
if(!server.StartupWizardCompleted) {
|
if(server.StartupWizardCompleted) {
|
||||||
print("Server needs configured")
|
|
||||||
} else {
|
|
||||||
_isConnected.wrappedValue = true;
|
_isConnected.wrappedValue = true;
|
||||||
}
|
}
|
||||||
case .failure(_):
|
case .failure(_):
|
||||||
|
@ -97,7 +95,7 @@ struct ConnectToServerView: View {
|
||||||
HStack {
|
HStack {
|
||||||
Text("Connect")
|
Text("Connect")
|
||||||
Spacer()
|
Spacer()
|
||||||
ProgressView().isHidden(!isWorking)
|
ProgressView().isHidden(!isWorking)
|
||||||
}
|
}
|
||||||
}.disabled(isWorking || uri.isEmpty)
|
}.disabled(isWorking || uri.isEmpty)
|
||||||
}.alert(isPresented: $isErrored) {
|
}.alert(isPresented: $isErrored) {
|
||||||
|
@ -108,14 +106,13 @@ struct ConnectToServerView: View {
|
||||||
TextField("Username", text: $username)
|
TextField("Username", text: $username)
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
SecureField("Password", text: $password)
|
SecureField("Password (optional)", text: $password)
|
||||||
.disableAutocorrection(true)
|
.disableAutocorrection(true)
|
||||||
.autocapitalization(.none)
|
.autocapitalization(.none)
|
||||||
Button {
|
Button {
|
||||||
_isWorking.wrappedValue = true
|
_isWorking.wrappedValue = true
|
||||||
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String;
|
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String;
|
||||||
let authHeader = "MediaBrowser Client=\"SwiftFin\", Device=\"\(UIDevice.current.name)\", DeviceId=\"\(serverSkipped ? reauthDeviceID : userUUID.uuidString)\", Version=\"\(appVersion ?? "0.0.1")\"";
|
let authHeader = "MediaBrowser Client=\"SwiftFin\", Device=\"\(UIDevice.current.name)\", DeviceId=\"\(serverSkipped ? reauthDeviceID : userUUID.uuidString)\", Version=\"\(appVersion ?? "0.0.1")\"";
|
||||||
print(authHeader)
|
|
||||||
let authJson: [String: Any] = ["Username": _username.wrappedValue, "Pw": _password.wrappedValue]
|
let authJson: [String: Any] = ["Username": _username.wrappedValue, "Pw": _password.wrappedValue]
|
||||||
let request = RestRequest(method: .post, url: uri + "/Users/authenticatebyname")
|
let request = RestRequest(method: .post, url: uri + "/Users/authenticatebyname")
|
||||||
request.headerParameters["X-Emby-Authorization"] = authHeader
|
request.headerParameters["X-Emby-Authorization"] = authHeader
|
||||||
|
@ -128,8 +125,6 @@ struct ConnectToServerView: View {
|
||||||
case .success(let response):
|
case .success(let response):
|
||||||
do {
|
do {
|
||||||
let json = try JSON(data: response.body)
|
let json = try JSON(data: response.body)
|
||||||
dump(json)
|
|
||||||
|
|
||||||
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Server")
|
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Server")
|
||||||
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
|
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
|
||||||
|
|
||||||
|
@ -158,21 +153,18 @@ struct ConnectToServerView: View {
|
||||||
newUser.username = _username.wrappedValue
|
newUser.username = _username.wrappedValue
|
||||||
newUser.user_id = json["User"]["Id"].string ?? ""
|
newUser.user_id = json["User"]["Id"].string ?? ""
|
||||||
|
|
||||||
|
globalData.authHeader = authHeader
|
||||||
|
|
||||||
let keychain = KeychainSwift()
|
let keychain = KeychainSwift()
|
||||||
keychain.set(json["AccessToken"].string ?? "", forKey: "AccessToken_\(json["User"]["Id"].string ?? "")")
|
keychain.set(json["AccessToken"].string ?? "", forKey: "AccessToken_\(json["User"]["Id"].string ?? "")")
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try viewContext.save()
|
try viewContext.save()
|
||||||
print("Saved to Core Data Store")
|
|
||||||
_rootIsActive.wrappedValue = false
|
|
||||||
DispatchQueue.main.async { [self] in
|
DispatchQueue.main.async { [self] in
|
||||||
jsi.did = true
|
jsi.did = true
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
SentrySDK.capture(error: error)
|
||||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
|
||||||
let nsError = error as NSError
|
|
||||||
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
||||||
|
@ -196,14 +188,9 @@ struct ConnectToServerView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.navigationTitle("Connect to Server")
|
}.navigationTitle("Connect to Server")
|
||||||
.navigationViewStyle(StackNavigationViewStyle())
|
|
||||||
.navigationBarBackButtonHidden(true)
|
|
||||||
.alert(isPresented: $serverSkippedAlert) {
|
.alert(isPresented: $serverSkippedAlert) {
|
||||||
Alert(title: Text("Error"), message: Text("Credentials have expired"), dismissButton: .default(Text("Sign in again")))
|
Alert(title: Text("Error"), message: Text("Credentials have expired"), dismissButton: .default(Text("Sign in again")))
|
||||||
}
|
}
|
||||||
.onAppear(perform: start)
|
.onAppear(perform: start)
|
||||||
.introspectTabBarController { (UITabBarController) in
|
|
||||||
UITabBarController.tabBar.isHidden = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,12 +345,6 @@ struct ContentView: View {
|
||||||
TabView(selection: $tabSelection) {
|
TabView(selection: $tabSelection) {
|
||||||
NavigationView() {
|
NavigationView() {
|
||||||
VStack {
|
VStack {
|
||||||
NavigationLink(destination: ConnectToServerView(isActive: $needsToSelectServer), isActive: $needsToSelectServer) {
|
|
||||||
EmptyView()
|
|
||||||
}.isDetailLink(false)
|
|
||||||
NavigationLink(destination: ConnectToServerView(skip_server: true, skip_server_prefill: globalData.server, reauth_deviceId: globalData.user?.device_uuid ?? "", isActive: $isSignInErrored), isActive: $isSignInErrored) {
|
|
||||||
EmptyView()
|
|
||||||
}.isDetailLink(false)
|
|
||||||
if(!needsToSelectServer && !isSignInErrored) {
|
if(!needsToSelectServer && !isSignInErrored) {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
ScrollView() {
|
ScrollView() {
|
||||||
|
@ -362,7 +356,7 @@ struct ContentView: View {
|
||||||
HStack() {
|
HStack() {
|
||||||
Text("Latest \(library_names[library_id] ?? "")").font(.title2).fontWeight(.bold).padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16))
|
Text("Latest \(library_names[library_id] ?? "")").font(.title2).fontWeight(.bold).padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 16))
|
||||||
Spacer()
|
Spacer()
|
||||||
NavigationLink(destination: LibraryView(prefill: library_id, names: library_names, libraries: libraries, filter: "&SortBy=DateCreated&SortOrder=Descending")) {
|
NavigationLink(destination: LibraryView(prefill: library_id, names: [library_id: library_names[library_id] ?? ""], libraries: [library_id], filter: "&SortBy=DateCreated&SortOrder=Descending")) {
|
||||||
Text("See All").font(.subheadline).fontWeight(.bold)
|
Text("See All").font(.subheadline).fontWeight(.bold)
|
||||||
}
|
}
|
||||||
}.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
|
}.padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
|
||||||
|
@ -400,9 +394,8 @@ struct ContentView: View {
|
||||||
})
|
})
|
||||||
.tag("All Media")
|
.tag("All Media")
|
||||||
|
|
||||||
}.edgesIgnoringSafeArea(isPortrait ? [] : [.leading,.trailing])
|
}
|
||||||
}.environmentObject(globalData)
|
}.environmentObject(globalData)
|
||||||
.edgesIgnoringSafeArea(isPortrait ? [] : [.leading,.trailing])
|
|
||||||
.onAppear(perform: startup)
|
.onAppear(perform: startup)
|
||||||
.navigationViewStyle(StackNavigationViewStyle())
|
.navigationViewStyle(StackNavigationViewStyle())
|
||||||
.alert(isPresented: $isNetworkErrored) {
|
.alert(isPresented: $isNetworkErrored) {
|
||||||
|
|
|
@ -21,6 +21,8 @@ struct EpisodeItemView: View {
|
||||||
@State private var playing: Bool = false;
|
@State private var playing: Bool = false;
|
||||||
@State private var vc: PreferenceUIHostingController? = nil;
|
@State private var vc: PreferenceUIHostingController? = nil;
|
||||||
@State private var progressString: String = "";
|
@State private var progressString: String = "";
|
||||||
|
@State private var viewDidLoad: Bool = false;
|
||||||
|
|
||||||
@State private var watched: Bool = false {
|
@State private var watched: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if(watched == true) {
|
if(watched == true) {
|
||||||
|
@ -83,17 +85,20 @@ struct EpisodeItemView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadData() {
|
func unlockOrientations() {
|
||||||
if(UIDevice.current.orientation.isLandscape) {
|
|
||||||
orientationInfo.orientation = .landscape;
|
|
||||||
} else {
|
|
||||||
orientationInfo.orientation = .portrait;
|
|
||||||
}
|
|
||||||
if(_vc.wrappedValue != nil) {
|
if(_vc.wrappedValue != nil) {
|
||||||
_vc.wrappedValue?._prefersHomeIndicatorAutoHidden = false;
|
_vc.wrappedValue?._prefersHomeIndicatorAutoHidden = false;
|
||||||
_vc.wrappedValue?._orientations = .allButUpsideDown;
|
_vc.wrappedValue?._orientations = .allButUpsideDown;
|
||||||
_vc.wrappedValue?._viewPreference = .unspecified;
|
_vc.wrappedValue?._viewPreference = .unspecified;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadData() {
|
||||||
|
unlockOrientations();
|
||||||
|
if(_viewDidLoad.wrappedValue == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_viewDidLoad.wrappedValue = true;
|
||||||
let url = "/Users/\(globalData.user?.user_id ?? "")/Items/\(item.Id)"
|
let url = "/Users/\(globalData.user?.user_id ?? "")/Items/\(item.Id)"
|
||||||
|
|
||||||
let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + url)
|
let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + url)
|
||||||
|
@ -202,14 +207,6 @@ struct EpisodeItemView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
|
|
||||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
|
|
||||||
|
|
||||||
var isPortrait: Bool {
|
|
||||||
let result = verticalSizeClass == .regular && horizontalSizeClass == .compact
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if(playing) {
|
if(playing) {
|
||||||
PlayerDemo(item: fullItem, playing: $playing).onAppear(perform: lockOrientations)
|
PlayerDemo(item: fullItem, playing: $playing).onAppear(perform: lockOrientations)
|
||||||
|
@ -586,16 +583,11 @@ struct EpisodeItemView: View {
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationTitle("\(fullItem.Name) - S\(String(fullItem.ParentIndexNumber ?? 0)):E\(String(fullItem.IndexNumber ?? 0)) - \(fullItem.SeriesName ?? "")")
|
.navigationTitle("\(fullItem.Name) - S\(String(fullItem.ParentIndexNumber ?? 0)):E\(String(fullItem.IndexNumber ?? 0)) - \(fullItem.SeriesName ?? "")")
|
||||||
.supportedOrientations(.allButUpsideDown)
|
|
||||||
.prefersHomeIndicatorAutoHidden(false)
|
|
||||||
.withHostingWindow() { window in
|
.withHostingWindow() { window in
|
||||||
let rootVC = window?.rootViewController;
|
let rootVC = window?.rootViewController;
|
||||||
let UIHostingcontroller: PreferenceUIHostingController = rootVC as! PreferenceUIHostingController;
|
let UIHostingcontroller: PreferenceUIHostingController = rootVC as! PreferenceUIHostingController;
|
||||||
vc = UIHostingcontroller;
|
vc = UIHostingcontroller;
|
||||||
}
|
}
|
||||||
.introspectTabBarController { (UITabBarController) in
|
|
||||||
UITabBarController.tabBar.isHidden = false
|
|
||||||
}
|
|
||||||
}.onAppear(perform: loadData)
|
}.onAppear(perform: loadData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>$(MARKETING_VERSION)</string>
|
<string>$(MARKETING_VERSION)</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>9</string>
|
<string>10</string>
|
||||||
<key>DTXApplicationID</key>
|
<key>DTXApplicationID</key>
|
||||||
<string>8c1f6941-ec78-480c-b589-b41aca29a52e</string>
|
<string>8c1f6941-ec78-480c-b589-b41aca29a52e</string>
|
||||||
<key>DTXBeaconURL</key>
|
<key>DTXBeaconURL</key>
|
||||||
|
|
|
@ -24,29 +24,20 @@ class OrientationInfo: ObservableObject {
|
||||||
case landscape
|
case landscape
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var orientation: Orientation
|
@Published var orientation: Orientation = .portrait;
|
||||||
|
|
||||||
private var _observer: NSObjectProtocol?
|
private var _observer: NSObjectProtocol?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
// fairly arbitrary starting value for 'flat' orientations
|
_observer = NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: nil) { [weak self] note in
|
||||||
if UIDevice.current.orientation.isLandscape {
|
|
||||||
self.orientation = .landscape
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.orientation = .portrait
|
|
||||||
}
|
|
||||||
|
|
||||||
// unowned self because we unregister before self becomes invalid
|
|
||||||
_observer = NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: nil) { [unowned self] note in
|
|
||||||
guard let device = note.object as? UIDevice else {
|
guard let device = note.object as? UIDevice else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if device.orientation.isPortrait {
|
if device.orientation.isPortrait {
|
||||||
self.orientation = .portrait
|
self?.orientation = .portrait
|
||||||
}
|
}
|
||||||
else if device.orientation.isLandscape {
|
else if device.orientation.isLandscape {
|
||||||
self.orientation = .landscape
|
self?.orientation = .landscape
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ struct MovieItemView: View {
|
||||||
@State private var playing: Bool = false;
|
@State private var playing: Bool = false;
|
||||||
@State private var vc: PreferenceUIHostingController? = nil;
|
@State private var vc: PreferenceUIHostingController? = nil;
|
||||||
@State private var progressString: String = "";
|
@State private var progressString: String = "";
|
||||||
|
@State private var viewDidLoad: Bool = false;
|
||||||
|
|
||||||
@State private var watched: Bool = false {
|
@State private var watched: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if(watched == true) {
|
if(watched == true) {
|
||||||
|
@ -130,12 +132,20 @@ struct MovieItemView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadData() {
|
func unlockOrientations() {
|
||||||
if(_vc.wrappedValue != nil) {
|
if(_vc.wrappedValue != nil) {
|
||||||
_vc.wrappedValue?._prefersHomeIndicatorAutoHidden = false;
|
_vc.wrappedValue?._prefersHomeIndicatorAutoHidden = false;
|
||||||
_vc.wrappedValue?._orientations = .allButUpsideDown;
|
_vc.wrappedValue?._orientations = .allButUpsideDown;
|
||||||
_vc.wrappedValue?._viewPreference = .unspecified;
|
_vc.wrappedValue?._viewPreference = .unspecified;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadData() {
|
||||||
|
unlockOrientations()
|
||||||
|
if(_viewDidLoad.wrappedValue == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_viewDidLoad.wrappedValue = true;
|
||||||
let url = "/Users/\(globalData.user?.user_id ?? "")/Items/\(item.Id)"
|
let url = "/Users/\(globalData.user?.user_id ?? "")/Items/\(item.Id)"
|
||||||
|
|
||||||
let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + url)
|
let request = RestRequest(method: .get, url: (globalData.server?.baseURI ?? "") + url)
|
||||||
|
@ -243,14 +253,6 @@ struct MovieItemView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
|
|
||||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
|
|
||||||
|
|
||||||
var isPortrait: Bool {
|
|
||||||
let result = verticalSizeClass == .regular && horizontalSizeClass == .compact
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
if(playing) {
|
if(playing) {
|
||||||
PlayerDemo(item: fullItem, playing: $playing).onAppear(perform: lockOrientations)
|
PlayerDemo(item: fullItem, playing: $playing).onAppear(perform: lockOrientations)
|
||||||
|
@ -626,16 +628,11 @@ struct MovieItemView: View {
|
||||||
}
|
}
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationTitle(fullItem.Name)
|
.navigationTitle(fullItem.Name)
|
||||||
.supportedOrientations(.allButUpsideDown)
|
|
||||||
.prefersHomeIndicatorAutoHidden(false)
|
|
||||||
.withHostingWindow() { window in
|
.withHostingWindow() { window in
|
||||||
let rootVC = window?.rootViewController;
|
let rootVC = window?.rootViewController;
|
||||||
let UIHostingcontroller: PreferenceUIHostingController = rootVC as! PreferenceUIHostingController;
|
let UIHostingcontroller: PreferenceUIHostingController = rootVC as! PreferenceUIHostingController;
|
||||||
vc = UIHostingcontroller;
|
vc = UIHostingcontroller;
|
||||||
}
|
}
|
||||||
.introspectTabBarController { (UITabBarController) in
|
|
||||||
UITabBarController.tabBar.isHidden = false
|
|
||||||
}
|
|
||||||
}.onAppear(perform: loadData)
|
}.onAppear(perform: loadData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,10 @@ extension String {
|
||||||
}
|
}
|
||||||
struct PlayerDemo: View {
|
struct PlayerDemo: View {
|
||||||
@EnvironmentObject var globalData: GlobalData
|
@EnvironmentObject var globalData: GlobalData
|
||||||
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
|
|
||||||
var item: DetailItem;
|
var item: DetailItem;
|
||||||
@State private var pbitem: PlaybackItem = PlaybackItem(videoType: VideoType.direct, videoUrl: URL(string: "https://example.com")!, subtitles: []);
|
@State private var pbitem: PlaybackItem = PlaybackItem(videoType: VideoType.direct, videoUrl: URL(string: "https://example.com")!, subtitles: []);
|
||||||
@State private var streamLoading = false;
|
@State private var streamLoading = false;
|
||||||
@State private var vlcplayer: VLCMediaPlayer = VLCMediaPlayer(options: ["-vv", "--sub-margin=-50"]);
|
@State private var vlcplayer: VLCMediaPlayer = VLCMediaPlayer(options: ["--sub-margin=-50"]);
|
||||||
@State private var isPlaying = false;
|
@State private var isPlaying = false;
|
||||||
@State private var subtitles: [Subtitle] = [];
|
@State private var subtitles: [Subtitle] = [];
|
||||||
@State private var inactivity: Bool = true;
|
@State private var inactivity: Bool = true;
|
||||||
|
@ -206,7 +205,7 @@ struct PlayerDemo: View {
|
||||||
|
|
||||||
func startStream() {
|
func startStream() {
|
||||||
_streamLoading.wrappedValue = true;
|
_streamLoading.wrappedValue = true;
|
||||||
let request = RestRequest(method: .post, url: (globalData.server?.baseURI ?? "") + "/Items/\(item.Id)/PlaybackInfo?UserId=\(globalData.user?.user_id ?? "")&StartTimeTicks=0&IsPlayback=true&AutoOpenLiveStream=true&MaxStreamingBitrate=70000000")
|
let request = RestRequest(method: .post, url: (globalData.server?.baseURI ?? "") + "/Items/\(item.Id)/PlaybackInfo?UserId=\(globalData.user?.user_id ?? "")&StartTimeTicks=\(item.Progress)&IsPlayback=true&AutoOpenLiveStream=true&MaxStreamingBitrate=70000000")
|
||||||
request.headerParameters["X-Emby-Authorization"] = globalData.authHeader
|
request.headerParameters["X-Emby-Authorization"] = globalData.authHeader
|
||||||
request.contentType = "application/json"
|
request.contentType = "application/json"
|
||||||
request.acceptType = "application/json"
|
request.acceptType = "application/json"
|
||||||
|
@ -220,14 +219,7 @@ struct PlayerDemo: View {
|
||||||
let json = try JSON(data: body)
|
let json = try JSON(data: body)
|
||||||
_playSessionId.wrappedValue = json["PlaySessionId"].string ?? "";
|
_playSessionId.wrappedValue = json["PlaySessionId"].string ?? "";
|
||||||
if(json["MediaSources"][0]["TranscodingUrl"].string != nil) {
|
if(json["MediaSources"][0]["TranscodingUrl"].string != nil) {
|
||||||
//Video is transcoded due to TranscodingReason - also may just be remuxed
|
|
||||||
for (_,stream):(String, JSON) in json["MediaSources"][0]["MediaStreams"] {
|
|
||||||
if(stream["Type"].string == "Subtitle") {
|
|
||||||
print("Found subtitle track: \(stream["DeliveryUrl"].string ?? "")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let streamURL: URL = URL(string: "\(globalData.server?.baseURI ?? "")\((json["MediaSources"][0]["TranscodingUrl"].string ?? "").replacingOccurrences(of: "master.m3u8", with: "main.m3u8"))")!
|
let streamURL: URL = URL(string: "\(globalData.server?.baseURI ?? "")\((json["MediaSources"][0]["TranscodingUrl"].string ?? "").replacingOccurrences(of: "master.m3u8", with: "main.m3u8"))")!
|
||||||
print(streamURL);
|
|
||||||
let item = PlaybackItem(videoType: VideoType.hls, videoUrl: streamURL, subtitles: [])
|
let item = PlaybackItem(videoType: VideoType.hls, videoUrl: streamURL, subtitles: [])
|
||||||
let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: URL(string: "https://example.com")!, delivery: "Embed")
|
let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: URL(string: "https://example.com")!, delivery: "Embed")
|
||||||
_subtitles.wrappedValue.append(disableSubtitleTrack);
|
_subtitles.wrappedValue.append(disableSubtitleTrack);
|
||||||
|
@ -243,14 +235,12 @@ struct PlayerDemo: View {
|
||||||
pbitem.subtitles = subtitles;
|
pbitem.subtitles = subtitles;
|
||||||
_isPlaying.wrappedValue = true;
|
_isPlaying.wrappedValue = true;
|
||||||
} else {
|
} else {
|
||||||
print("Direct play of item \(item.Name)")
|
|
||||||
let streamURL: URL = URL(string: "\(globalData.server?.baseURI ?? "")/Videos/\(item.Id)/stream?Static=true&mediaSourceId=\(item.Id)&deviceId=\(globalData.user?.device_uuid ?? "")&api_key=\(globalData.authToken)&Tag=\(json["MediaSources"][0]["ETag"])")!;
|
let streamURL: URL = URL(string: "\(globalData.server?.baseURI ?? "")/Videos/\(item.Id)/stream?Static=true&mediaSourceId=\(item.Id)&deviceId=\(globalData.user?.device_uuid ?? "")&api_key=\(globalData.authToken)&Tag=\(json["MediaSources"][0]["ETag"])")!;
|
||||||
let item = PlaybackItem(videoType: VideoType.direct, videoUrl: streamURL, subtitles: [])
|
let item = PlaybackItem(videoType: VideoType.direct, videoUrl: streamURL, subtitles: [])
|
||||||
let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: URL(string: "https://example.com")!, delivery: "Embed")
|
let disableSubtitleTrack = Subtitle(name: "Disabled", id: -1, url: URL(string: "https://example.com")!, delivery: "Embed")
|
||||||
_subtitles.wrappedValue.append(disableSubtitleTrack);
|
_subtitles.wrappedValue.append(disableSubtitleTrack);
|
||||||
for (_,stream):(String, JSON) in json["MediaSources"][0]["MediaStreams"] {
|
for (_,stream):(String, JSON) in json["MediaSources"][0]["MediaStreams"] {
|
||||||
if(stream["Type"].string == "Subtitle") {
|
if(stream["Type"].string == "Subtitle") {
|
||||||
print("Found subtitle track with title \(stream["DisplayTitle"].string ?? "") Delivery method: \(stream["DeliveryMethod"].string ?? "")")
|
|
||||||
let deliveryUrl = URL(string: "\(globalData.server?.baseURI ?? "")\(stream["DeliveryUrl"].string ?? "")")!
|
let deliveryUrl = URL(string: "\(globalData.server?.baseURI ?? "")\(stream["DeliveryUrl"].string ?? "")")!
|
||||||
let subtitle = Subtitle(name: stream["DisplayTitle"].string ?? "", id: Int32(stream["Index"].int ?? 0), url: deliveryUrl, delivery: stream["DeliveryMethod"].string ?? "")
|
let subtitle = Subtitle(name: stream["DisplayTitle"].string ?? "", id: Int32(stream["Index"].int ?? 0), url: deliveryUrl, delivery: stream["DeliveryMethod"].string ?? "")
|
||||||
_subtitles.wrappedValue.append(subtitle);
|
_subtitles.wrappedValue.append(subtitle);
|
||||||
|
@ -260,7 +250,8 @@ struct PlayerDemo: View {
|
||||||
pbitem.subtitles = subtitles;
|
pbitem.subtitles = subtitles;
|
||||||
_isPlaying.wrappedValue = true;
|
_isPlaying.wrappedValue = true;
|
||||||
}
|
}
|
||||||
DispatchQueue.global(qos: .userInitiated).async { [self] in
|
|
||||||
|
DispatchQueue.global(qos: .userInteractive).async { [self] in
|
||||||
self.keepUpWithPlayerState()
|
self.keepUpWithPlayerState()
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -280,8 +271,7 @@ struct PlayerDemo: View {
|
||||||
while(vlcplayer.state == VLCMediaPlayerState.paused) {
|
while(vlcplayer.state == VLCMediaPlayerState.paused) {
|
||||||
let secondsScrubbedTo = round(_scrub.wrappedValue * videoDuration);
|
let secondsScrubbedTo = round(_scrub.wrappedValue * videoDuration);
|
||||||
let scrubRemaining = videoDuration - secondsScrubbedTo;
|
let scrubRemaining = videoDuration - secondsScrubbedTo;
|
||||||
usleep(10000)
|
usleep(50000)
|
||||||
|
|
||||||
let remainingTime = scrubRemaining;
|
let remainingTime = scrubRemaining;
|
||||||
let hours = floor(remainingTime / 3600);
|
let hours = floor(remainingTime / 3600);
|
||||||
let minutes = (remainingTime.truncatingRemainder(dividingBy: 3600)) / 60;
|
let minutes = (remainingTime.truncatingRemainder(dividingBy: 3600)) / 60;
|
||||||
|
@ -401,14 +391,8 @@ struct PlayerDemo: View {
|
||||||
.navigationBarHidden(true)
|
.navigationBarHidden(true)
|
||||||
.navigationBarBackButtonHidden(true)
|
.navigationBarBackButtonHidden(true)
|
||||||
.statusBar(hidden: true)
|
.statusBar(hidden: true)
|
||||||
.introspectTabBarController { (UITabBarController) in
|
|
||||||
UITabBarController.tabBar.isHidden = true
|
|
||||||
}
|
|
||||||
.prefersHomeIndicatorAutoHidden(true)
|
|
||||||
.supportedOrientations(.landscapeRight)
|
|
||||||
.edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
.onTapGesture(perform: resetTimer)
|
.onTapGesture(perform: resetTimer)
|
||||||
.overrideViewPreference(.dark)
|
|
||||||
.fullScreenCover(isPresented: self.$captionConfiguration) {
|
.fullScreenCover(isPresented: self.$captionConfiguration) {
|
||||||
NavigationView() {
|
NavigationView() {
|
||||||
VStack() {
|
VStack() {
|
||||||
|
|
|
@ -22,15 +22,6 @@ platform :ios do
|
||||||
gym(output_name: "JellyfinPlayer.ipa")
|
gym(output_name: "JellyfinPlayer.ipa")
|
||||||
identifier_v = get_version_number(xcodeproj: "JellyfinPlayer.xcodeproj")
|
identifier_v = get_version_number(xcodeproj: "JellyfinPlayer.xcodeproj")
|
||||||
identifier_s = get_info_plist_value(path: "JellyfinPlayer/Info.plist", key: "CFBundleVersion")
|
identifier_s = get_info_plist_value(path: "JellyfinPlayer/Info.plist", key: "CFBundleVersion")
|
||||||
dynatrace_process_symbols(
|
|
||||||
appId: "8c1f6941-ec78-480c-b589-b41aca29a52e",
|
|
||||||
os: "ios",
|
|
||||||
bundleId: "me.vigue.jellyfin",
|
|
||||||
versionStr: identifier_v,
|
|
||||||
version: identifier_s,
|
|
||||||
server: "https://ofa89490.live.dynatrace.com",
|
|
||||||
symbolsfile: "JellyfinPlayer.app.dSYM.zip"
|
|
||||||
)
|
|
||||||
upload_symbols_to_sentry(
|
upload_symbols_to_sentry(
|
||||||
org_slug: 'aidenvigue',
|
org_slug: 'aidenvigue',
|
||||||
project_slug: 'jellyfin-swift-ios',
|
project_slug: 'jellyfin-swift-ios',
|
||||||
|
@ -45,5 +36,14 @@ platform :ios do
|
||||||
upload_assets: ["JellyfinPlayer.ipa"]
|
upload_assets: ["JellyfinPlayer.ipa"]
|
||||||
)
|
)
|
||||||
upload_to_testflight
|
upload_to_testflight
|
||||||
|
dynatrace_process_symbols(
|
||||||
|
appId: "8c1f6941-ec78-480c-b589-b41aca29a52e",
|
||||||
|
os: "ios",
|
||||||
|
bundleId: "me.vigue.jellyfin",
|
||||||
|
versionStr: identifier_v,
|
||||||
|
version: identifier_s,
|
||||||
|
server: "https://ofa89490.live.dynatrace.com",
|
||||||
|
symbolsfile: "JellyfinPlayer.app.dSYM.zip"
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue