it all works
This commit is contained in:
parent
ea6b9a6326
commit
583f4a7509
|
@ -3,11 +3,13 @@
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>FILEHEADER</key>
|
<key>FILEHEADER</key>
|
||||||
<string>/* SwiftFin is subject to the terms of the Mozilla Public
|
<string>
|
||||||
* 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/.
|
* SwiftFin is subject to the terms of the Mozilla Public
|
||||||
*
|
* License, v2.0. If a copy of the MPL was not distributed with this
|
||||||
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/</string>
|
*
|
||||||
|
* Copyright 2021 Aiden Vigue & Jellyfin Contributors
|
||||||
|
*/</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct ConnectToServerView: View {
|
||||||
@State private var serverSkipped: Bool = false;
|
@State private var serverSkipped: Bool = false;
|
||||||
@State private var serverSkippedAlert: Bool = false;
|
@State private var serverSkippedAlert: Bool = false;
|
||||||
@State private var skip_server_bool: Bool = false;
|
@State private var skip_server_bool: Bool = false;
|
||||||
@State private var skip_server_obj: Server = Server();
|
@State private var skip_server_obj: Server!;
|
||||||
|
|
||||||
@Binding var rootIsActive: Bool
|
@Binding var rootIsActive: Bool
|
||||||
|
|
||||||
|
@ -297,9 +297,6 @@ struct ConnectToServerView: View {
|
||||||
.frame(width: 60, height: 60)
|
.frame(width: 60, height: 60)
|
||||||
.cornerRadius(30.0)
|
.cornerRadius(30.0)
|
||||||
.shadow(radius: 6)
|
.shadow(radius: 6)
|
||||||
.onAppear(perform: {
|
|
||||||
print("\(uri)/Users/\(publicUser.id!)/Images/Primary?width=200&quality=80&tag=\(publicUser.primaryImageTag!)")
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Image(systemName: "person.fill")
|
Image(systemName: "person.fill")
|
||||||
.foregroundColor(Color(red: 1, green: 1, blue: 1).opacity(0.8))
|
.foregroundColor(Color(red: 1, green: 1, blue: 1).opacity(0.8))
|
||||||
|
|
|
@ -37,7 +37,7 @@ struct ContinueWatchingView: View {
|
||||||
@State private var items: [BaseItemDto] = []
|
@State private var items: [BaseItemDto] = []
|
||||||
|
|
||||||
func onAppear() {
|
func onAppear() {
|
||||||
ItemsAPI.getResumeItems(userId: globalData.user.user_id ?? "", limit: 12, fields: [.primaryImageAspectRatio], mediaTypes: ["Video"], imageTypeLimit: 1, enableImageTypes: [.primary,.backdrop,.thumb])
|
ItemsAPI.getResumeItems(userId: globalData.user.user_id ?? "", limit: 12, fields: [.primaryImageAspectRatio,.seriesPrimaryImage,.seasonUserData,.overview,.genres,.people], mediaTypes: ["Video"], imageTypeLimit: 1, enableImageTypes: [.primary,.backdrop,.thumb])
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
|
|
|
@ -16,22 +16,25 @@ struct EpisodeItemView: View {
|
||||||
|
|
||||||
var item: BaseItemDto
|
var item: BaseItemDto
|
||||||
|
|
||||||
|
@State private var settingState: Bool = true
|
||||||
@State private var watched: Bool = false {
|
@State private var watched: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if watched == true {
|
if !settingState {
|
||||||
PlaystateAPI.markPlayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
if watched == true {
|
||||||
.sink(receiveCompletion: { completion in
|
PlaystateAPI.markPlayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
} else {
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
PlaystateAPI.markUnplayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
} else {
|
||||||
.sink(receiveCompletion: { completion in
|
PlaystateAPI.markUnplayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,20 +42,22 @@ struct EpisodeItemView: View {
|
||||||
@State
|
@State
|
||||||
private var favorite: Bool = false {
|
private var favorite: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if favorite == true {
|
if !settingState {
|
||||||
UserLibraryAPI.markFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
if favorite == true {
|
||||||
.sink(receiveCompletion: { completion in
|
UserLibraryAPI.markFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
} else {
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
UserLibraryAPI.unmarkFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
} else {
|
||||||
.sink(receiveCompletion: { completion in
|
UserLibraryAPI.unmarkFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +104,7 @@ struct EpisodeItemView: View {
|
||||||
.fontWeight(.medium)
|
.fontWeight(.medium)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
if item.officialRating != "" {
|
if item.officialRating != nil {
|
||||||
Text(item.officialRating!).font(.subheadline)
|
Text(item.officialRating!).font(.subheadline)
|
||||||
.fontWeight(.semibold)
|
.fontWeight(.semibold)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
@ -454,8 +459,9 @@ struct EpisodeItemView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear(perform: {
|
.onAppear(perform: {
|
||||||
favorite = item.userData?.isFavorite ?? false
|
favorite = item.userData!.isFavorite!
|
||||||
watched = item.userData?.played ?? false
|
watched = item.userData!.played!
|
||||||
|
settingState = false
|
||||||
})
|
})
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationTitle("\(item.seriesName ?? "") - S\(String(item.parentIndexNumber ?? 0)):E\(String(item.indexNumber ?? 0))")
|
.navigationTitle("\(item.seriesName ?? "") - S\(String(item.parentIndexNumber ?? 0)):E\(String(item.indexNumber ?? 0))")
|
||||||
|
|
|
@ -2,6 +2,14 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>NSBonjourServices</key>
|
||||||
|
<array>
|
||||||
|
<string>_googlecast._tcp</string>
|
||||||
|
<string>_F007D354._googlecast._tcp</string>
|
||||||
|
</array>
|
||||||
|
<key>NSLocalNetworkUsageDescription</key>
|
||||||
|
<string>${PRODUCT_NAME} uses the local network to connect to your Jellyfin server & discover Cast-enabled devices on your WiFi
|
||||||
|
network.</string>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
|
|
|
@ -9,8 +9,6 @@ import SwiftUI
|
||||||
import Introspect
|
import Introspect
|
||||||
import JellyfinAPI
|
import JellyfinAPI
|
||||||
|
|
||||||
//good lord the environmental modifiers ;P
|
|
||||||
|
|
||||||
class VideoPlayerItem: ObservableObject {
|
class VideoPlayerItem: ObservableObject {
|
||||||
@Published var shouldShowPlayer: Bool = false;
|
@Published var shouldShowPlayer: Bool = false;
|
||||||
@Published var itemToPlay: BaseItemDto = BaseItemDto();
|
@Published var itemToPlay: BaseItemDto = BaseItemDto();
|
||||||
|
@ -18,8 +16,6 @@ class VideoPlayerItem: ObservableObject {
|
||||||
|
|
||||||
struct ItemView: View {
|
struct ItemView: View {
|
||||||
@EnvironmentObject private var globalData: GlobalData
|
@EnvironmentObject private var globalData: GlobalData
|
||||||
|
|
||||||
@State private var fullItem: BaseItemDto = BaseItemDto();
|
|
||||||
private var item: BaseItemDto;
|
private var item: BaseItemDto;
|
||||||
|
|
||||||
@StateObject private var videoPlayerItem: VideoPlayerItem = VideoPlayerItem()
|
@StateObject private var videoPlayerItem: VideoPlayerItem = VideoPlayerItem()
|
||||||
|
@ -31,23 +27,6 @@ struct ItemView: View {
|
||||||
self.item = item
|
self.item = item
|
||||||
}
|
}
|
||||||
|
|
||||||
func onAppear() {
|
|
||||||
if(viewDidLoad) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoading = true;
|
|
||||||
UserLibraryAPI.getItem(userId: globalData.user.user_id!, itemId: item.id!)
|
|
||||||
.sink(receiveCompletion: { completion in
|
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
|
||||||
}, receiveValue: { response in
|
|
||||||
isLoading = false
|
|
||||||
viewDidLoad = true
|
|
||||||
fullItem = response
|
|
||||||
})
|
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
if(videoPlayerItem.shouldShowPlayer) {
|
if(videoPlayerItem.shouldShowPlayer) {
|
||||||
|
@ -62,37 +41,32 @@ struct ItemView: View {
|
||||||
.overrideViewPreference(.unspecified)
|
.overrideViewPreference(.unspecified)
|
||||||
.supportedOrientations(.landscape)
|
.supportedOrientations(.landscape)
|
||||||
} else {
|
} else {
|
||||||
if(isLoading) {
|
VStack {
|
||||||
ProgressView()
|
if(item.type == "Movie") {
|
||||||
} else {
|
MovieItemView(item: item)
|
||||||
VStack {
|
} else if(item.type == "Season") {
|
||||||
if(fullItem.type == "Movie") {
|
SeasonItemView(item: item)
|
||||||
MovieItemView(item: fullItem)
|
} else if(item.type == "Series") {
|
||||||
} else if(fullItem.type == "Season") {
|
SeriesItemView(item: item)
|
||||||
SeasonItemView(item: fullItem)
|
} else if(item.type == "Episode") {
|
||||||
} else if(fullItem.type == "Series") {
|
EpisodeItemView(item: item)
|
||||||
SeriesItemView(item: fullItem)
|
} else {
|
||||||
} else if(fullItem.type == "Episode") {
|
Text("Type: \(item.type ?? "") not implemented yet :(")
|
||||||
EpisodeItemView(item: fullItem)
|
|
||||||
} else {
|
|
||||||
Text("Type: \(fullItem.type ?? "") not implemented yet :(")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.introspectTabBarController { (UITabBarController) in
|
|
||||||
UITabBarController.tabBar.isHidden = false
|
|
||||||
}
|
|
||||||
.navigationBarHidden(false)
|
|
||||||
.navigationBarBackButtonHidden(false)
|
|
||||||
.statusBar(hidden: false)
|
|
||||||
.prefersHomeIndicatorAutoHidden(false)
|
|
||||||
.preferredColorScheme(.none)
|
|
||||||
.edgesIgnoringSafeArea([])
|
|
||||||
.overrideViewPreference(.unspecified)
|
|
||||||
.supportedOrientations(.allButUpsideDown)
|
|
||||||
.environmentObject(videoPlayerItem)
|
|
||||||
}
|
}
|
||||||
|
.introspectTabBarController { (UITabBarController) in
|
||||||
|
UITabBarController.tabBar.isHidden = false
|
||||||
|
}
|
||||||
|
.navigationBarHidden(false)
|
||||||
|
.navigationBarBackButtonHidden(false)
|
||||||
|
.statusBar(hidden: false)
|
||||||
|
.prefersHomeIndicatorAutoHidden(false)
|
||||||
|
.preferredColorScheme(.none)
|
||||||
|
.edgesIgnoringSafeArea([])
|
||||||
|
.overrideViewPreference(.unspecified)
|
||||||
|
.supportedOrientations(.allButUpsideDown)
|
||||||
|
.environmentObject(videoPlayerItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear(perform: onAppear)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ struct LatestMediaView: View {
|
||||||
}
|
}
|
||||||
viewDidLoad = true;
|
viewDidLoad = true;
|
||||||
|
|
||||||
UserLibraryAPI.getLatestMedia(userId: globalData.user.user_id!, parentId: library_id, fields: [.primaryImageAspectRatio,.seriesPrimaryImage], enableUserData: true, limit: 12)
|
UserLibraryAPI.getLatestMedia(userId: globalData.user.user_id!, parentId: library_id, fields: [.primaryImageAspectRatio,.seriesPrimaryImage,.seasonUserData,.overview,.genres,.people], enableUserData: true, limit: 12)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
|
|
|
@ -31,7 +31,7 @@ struct LibrarySearchView: View {
|
||||||
func requestSearch(query: String) {
|
func requestSearch(query: String) {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
print(usingParentID)
|
print(usingParentID)
|
||||||
ItemsAPI.getItemsByUserId(userId: globalData.user.user_id!, limit: 60, recursive: true, searchTerm: query, sortOrder: [.ascending], parentId: (usingParentID != "" ? usingParentID : nil), fields: [.parentId,.primaryImageAspectRatio,.basicSyncInfo], includeItemTypes: ["Movie","Series"], sortBy: ["SortName"], enableUserData: true, enableImages: true)
|
ItemsAPI.getItemsByUserId(userId: globalData.user.user_id!, limit: 60, recursive: true, searchTerm: query, sortOrder: [.ascending], parentId: (usingParentID != "" ? usingParentID : nil), fields: [.primaryImageAspectRatio,.seriesPrimaryImage,.seasonUserData,.overview,.genres,.people], includeItemTypes: ["Movie","Series"], sortBy: ["SortName"], enableUserData: true, enableImages: true)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
|
@ -110,3 +110,5 @@ struct LibrarySearchView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//stream NM5 by nicki!
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct LibraryView: View {
|
||||||
isLoading = true
|
isLoading = true
|
||||||
items = []
|
items = []
|
||||||
|
|
||||||
ItemsAPI.getItemsByUserId(userId: globalData.user.user_id!, startIndex: currentPage * 100, limit: 100, recursive: true, searchTerm: nil, sortOrder: filters.sortOrder, parentId: (usingParentID != "" ? usingParentID : nil), fields: [.parentId,.primaryImageAspectRatio,.basicSyncInfo], includeItemTypes: ["Movie","Series"], filters: filters.filters, sortBy: filters.sortBy, enableUserData: true, personIds: (personId == "" ? nil : [personId]), studioIds: (studio == "" ? nil : [studio]), genreIds: (genre == "" ? nil : [genre]), enableImages: true)
|
ItemsAPI.getItemsByUserId(userId: globalData.user.user_id!, startIndex: currentPage * 100, limit: 100, recursive: true, searchTerm: nil, sortOrder: filters.sortOrder, parentId: (usingParentID != "" ? usingParentID : nil), fields: [.primaryImageAspectRatio,.seriesPrimaryImage,.seasonUserData,.overview,.genres,.people], includeItemTypes: ["Movie","Series"], filters: filters.filters, sortBy: filters.sortBy, enableUserData: true, personIds: (personId == "" ? nil : [personId]), studioIds: (studio == "" ? nil : [studio]), genreIds: (genre == "" ? nil : [genre]), enableImages: true)
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
isLoading = false
|
isLoading = false
|
||||||
|
@ -184,3 +184,5 @@ struct LibraryView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//stream BM^S by nicki!
|
||||||
|
|
|
@ -16,22 +16,25 @@ struct MovieItemView: View {
|
||||||
|
|
||||||
var item: BaseItemDto
|
var item: BaseItemDto
|
||||||
|
|
||||||
|
@State private var settingState: Bool = true
|
||||||
@State private var watched: Bool = false {
|
@State private var watched: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if watched == true {
|
if !settingState {
|
||||||
PlaystateAPI.markPlayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
if watched == true {
|
||||||
.sink(receiveCompletion: { completion in
|
PlaystateAPI.markPlayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
} else {
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
PlaystateAPI.markUnplayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
} else {
|
||||||
.sink(receiveCompletion: { completion in
|
PlaystateAPI.markUnplayedItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,20 +42,22 @@ struct MovieItemView: View {
|
||||||
@State
|
@State
|
||||||
private var favorite: Bool = false {
|
private var favorite: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if favorite == true {
|
if !settingState {
|
||||||
UserLibraryAPI.markFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
if favorite == true {
|
||||||
.sink(receiveCompletion: { completion in
|
UserLibraryAPI.markFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
} else {
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
UserLibraryAPI.unmarkFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
} else {
|
||||||
.sink(receiveCompletion: { completion in
|
UserLibraryAPI.unmarkFavoriteItem(userId: globalData.user.user_id!, itemId: item.id!)
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
.sink(receiveCompletion: { completion in
|
||||||
}, receiveValue: { _ in
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
})
|
}, receiveValue: { _ in
|
||||||
.store(in: &globalData.pendingAPIRequests)
|
})
|
||||||
|
.store(in: &globalData.pendingAPIRequests)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,8 +459,9 @@ struct MovieItemView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear(perform: {
|
.onAppear(perform: {
|
||||||
favorite = item.userData?.isFavorite ?? false
|
favorite = item.userData!.isFavorite!
|
||||||
watched = item.userData?.played ?? false
|
watched = item.userData!.played!
|
||||||
|
settingState = false
|
||||||
})
|
})
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.navigationTitle(item.name!)
|
.navigationTitle(item.name!)
|
||||||
|
|
|
@ -21,7 +21,7 @@ struct NextUpView: View {
|
||||||
}
|
}
|
||||||
viewDidLoad = true;
|
viewDidLoad = true;
|
||||||
|
|
||||||
TvShowsAPI.getNextUp(userId: globalData.user.user_id!, limit: 12)
|
TvShowsAPI.getNextUp(userId: globalData.user.user_id!, limit: 12, fields: [.primaryImageAspectRatio,.seriesPrimaryImage,.seasonUserData,.overview,.genres,.people])
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
|
|
|
@ -14,8 +14,8 @@ struct SeasonItemView: View {
|
||||||
@EnvironmentObject var orientationInfo: OrientationInfo
|
@EnvironmentObject var orientationInfo: OrientationInfo
|
||||||
|
|
||||||
var item: BaseItemDto = BaseItemDto()
|
var item: BaseItemDto = BaseItemDto()
|
||||||
|
|
||||||
@State private var episodes: [BaseItemDto] = []
|
@State private var episodes: [BaseItemDto] = []
|
||||||
|
|
||||||
@State private var isLoading: Bool = true
|
@State private var isLoading: Bool = true
|
||||||
@State private var viewDidLoad: Bool = false
|
@State private var viewDidLoad: Bool = false
|
||||||
|
|
||||||
|
@ -28,9 +28,7 @@ struct SeasonItemView: View {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dump(item)
|
TvShowsAPI.getEpisodes(seriesId: item.seriesId!, userId: globalData.user.user_id!, fields: [.primaryImageAspectRatio,.seriesPrimaryImage,.seasonUserData,.overview,.genres,.people], seasonId: item.id!)
|
||||||
|
|
||||||
TvShowsAPI.getEpisodes(seriesId: item.seriesId!, userId: globalData.user.user_id!, fields: [.primaryImageAspectRatio, .seasonUserData, .itemCounts, .overview], seasonId: item.id!)
|
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
isLoading = false
|
isLoading = false
|
||||||
|
|
|
@ -24,9 +24,9 @@ struct SeriesItemView: View {
|
||||||
if(viewDidLoad) {
|
if(viewDidLoad) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isLoading = true
|
|
||||||
|
|
||||||
TvShowsAPI.getSeasons(seriesId: item.id ?? "")
|
isLoading = true
|
||||||
|
TvShowsAPI.getSeasons(seriesId: item.id ?? "", fields: [.primaryImageAspectRatio,.seriesPrimaryImage,.seasonUserData,.overview,.genres,.people])
|
||||||
.sink(receiveCompletion: { completion in
|
.sink(receiveCompletion: { completion in
|
||||||
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
HandleAPIRequestCompletion(globalData: globalData, completion: completion)
|
||||||
}, receiveValue: { response in
|
}, receiveValue: { response in
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import MobileVLCKit
|
import MobileVLCKit
|
||||||
import JellyfinAPI
|
import JellyfinAPI
|
||||||
|
import MediaPlayer
|
||||||
|
|
||||||
struct Subtitle {
|
struct Subtitle {
|
||||||
var name: String;
|
var name: String;
|
||||||
|
@ -185,9 +186,78 @@ class PlayerViewController: UIViewController, VLCMediaDelegate, VLCMediaPlayerDe
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupNowPlayingCC() {
|
||||||
|
let commandCenter = MPRemoteCommandCenter.shared()
|
||||||
|
commandCenter.playCommand.isEnabled = true;
|
||||||
|
commandCenter.pauseCommand.isEnabled = true;
|
||||||
|
commandCenter.seekForwardCommand.isEnabled = true;
|
||||||
|
commandCenter.seekBackwardCommand.isEnabled = true;
|
||||||
|
commandCenter.changePlaybackPositionCommand.isEnabled = true
|
||||||
|
|
||||||
|
// Add handler for Pause Command
|
||||||
|
commandCenter.pauseCommand.addTarget{ event in
|
||||||
|
self.mediaPlayer.pause()
|
||||||
|
self.sendProgressReport(eventName: "pause")
|
||||||
|
return .success
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add handler for Play command
|
||||||
|
commandCenter.playCommand.addTarget{ event in
|
||||||
|
self.mediaPlayer.play()
|
||||||
|
self.sendProgressReport(eventName: "unpause")
|
||||||
|
return .success
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add handler for FF command
|
||||||
|
commandCenter.seekForwardCommand.addTarget{ event in
|
||||||
|
self.mediaPlayer.jumpForward(30)
|
||||||
|
self.sendProgressReport(eventName: "timeupdate")
|
||||||
|
return .success
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add handler for RW command
|
||||||
|
commandCenter.seekBackwardCommand.addTarget{ event in
|
||||||
|
self.mediaPlayer.jumpBackward(15)
|
||||||
|
self.sendProgressReport(eventName: "timeupdate")
|
||||||
|
return .success
|
||||||
|
}
|
||||||
|
|
||||||
|
//Scrubber
|
||||||
|
commandCenter.changePlaybackPositionCommand.addTarget { [weak self](remoteEvent) -> MPRemoteCommandHandlerStatus in
|
||||||
|
guard let self = self else {return .commandFailed}
|
||||||
|
|
||||||
|
if let event = remoteEvent as? MPChangePlaybackPositionCommandEvent {
|
||||||
|
let targetSeconds = event.positionTime
|
||||||
|
|
||||||
|
let videoPosition = Double(self.mediaPlayer.time.intValue)
|
||||||
|
let offset = targetSeconds - videoPosition;
|
||||||
|
if(offset > 0) {
|
||||||
|
self.mediaPlayer.jumpForward(Int32(offset)/1000);
|
||||||
|
} else {
|
||||||
|
self.mediaPlayer.jumpBackward(Int32(abs(offset))/1000);
|
||||||
|
}
|
||||||
|
self.sendProgressReport(eventName: "unpause")
|
||||||
|
|
||||||
|
return .success
|
||||||
|
} else {
|
||||||
|
return .commandFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var nowPlayingInfo = [String : Any]()
|
||||||
|
nowPlayingInfo[MPMediaItemPropertyTitle] = manifest.name ?? ""
|
||||||
|
|
||||||
|
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
|
||||||
|
|
||||||
|
UIApplication.shared.beginReceivingRemoteControlEvents()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func remoteControlReceived(with event: UIEvent?) {
|
||||||
|
dump(event)
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
//View has loaded.
|
//View has loaded.
|
||||||
|
|
||||||
//Rotate to landscape only if necessary
|
//Rotate to landscape only if necessary
|
||||||
|
@ -200,7 +270,11 @@ class PlayerViewController: UIViewController, VLCMediaDelegate, VLCMediaPlayerDe
|
||||||
mediaPlayer.delegate = self
|
mediaPlayer.delegate = self
|
||||||
mediaPlayer.drawable = videoContentView
|
mediaPlayer.drawable = videoContentView
|
||||||
|
|
||||||
titleLabel.text = manifest.name
|
if(manifest.type == "Movie") {
|
||||||
|
titleLabel.text = manifest.name
|
||||||
|
} else {
|
||||||
|
titleLabel.text = "S\(String(manifest.parentIndexNumber!)):E\(String(manifest.indexNumber!)) “\(manifest.name!)”"
|
||||||
|
}
|
||||||
|
|
||||||
//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 defaults = UserDefaults.standard
|
||||||
|
@ -292,9 +366,12 @@ class PlayerViewController: UIViewController, VLCMediaDelegate, VLCMediaPlayerDe
|
||||||
playbackItem = item;
|
playbackItem = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.setupNowPlayingCC()
|
||||||
|
|
||||||
DispatchQueue.global(qos: .background).async {
|
DispatchQueue.global(qos: .background).async {
|
||||||
mediaPlayer.media = VLCMedia(url: playbackItem.videoUrl)
|
mediaPlayer.media = VLCMedia(url: playbackItem.videoUrl)
|
||||||
mediaPlayer.play()
|
mediaPlayer.play()
|
||||||
|
print(manifest.userData?.playbackPositionTicks ?? 0)
|
||||||
mediaPlayer.jumpForward(Int32(manifest.userData?.playbackPositionTicks ?? 0/10000000))
|
mediaPlayer.jumpForward(Int32(manifest.userData?.playbackPositionTicks ?? 0/10000000))
|
||||||
mediaPlayer.pause()
|
mediaPlayer.pause()
|
||||||
subtitleTrackArray.forEach() { sub in
|
subtitleTrackArray.forEach() { sub in
|
||||||
|
|
|
@ -27,9 +27,9 @@ class justSignedIn: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
class GlobalData: ObservableObject {
|
class GlobalData: ObservableObject {
|
||||||
@Published var user: SignedInUser = SignedInUser()
|
@Published var user: SignedInUser!
|
||||||
@Published var authToken: String = ""
|
@Published var authToken: String = ""
|
||||||
@Published var server: Server = Server()
|
@Published var server: Server!
|
||||||
@Published var authHeader: String = ""
|
@Published var authHeader: String = ""
|
||||||
@Published var isInNetwork: Bool = true;
|
@Published var isInNetwork: Bool = true;
|
||||||
@Published var networkError: Bool = false;
|
@Published var networkError: Bool = false;
|
||||||
|
|
Loading…
Reference in New Issue