From 12e4af65cd266082f09fb01559ea9c708525cffe Mon Sep 17 00:00:00 2001 From: acvigue Date: Fri, 2 Jul 2021 19:14:16 +0000 Subject: [PATCH] [create-pull-request] automated change --- .../Components/LandscapeItemElement.swift | 2 +- .../Components/MediaViewActionButton.swift | 6 +- .../Components/PortraitItemElement.swift | 5 +- JellyfinPlayer tvOS/EpisodeItemView.swift | 38 +++++----- JellyfinPlayer tvOS/LibraryView.swift | 4 +- JellyfinPlayer tvOS/MovieItemView.swift | 48 ++++++------- JellyfinPlayer tvOS/SeasonItemView.swift | 18 ++--- JellyfinPlayer tvOS/SeriesItemView.swift | 58 +++++++-------- .../VideoPlayer/AudioView.swift | 2 +- .../InfoTabBarViewController.swift | 7 +- .../VideoPlayer/MediaInfoView.swift | 6 +- .../VideoPlayerViewController.swift | 38 +++++----- .../Components/PortraitItemView.swift | 11 ++- JellyfinPlayer/LibraryListView.swift | 4 +- JellyfinPlayer/LibraryView.swift | 2 +- JellyfinPlayer/SeasonItemView.swift | 3 +- JellyfinPlayer/VideoPlayer.swift | 71 +++++++++---------- JellyfinPlayer/VideoPlayerSettingsView.swift | 7 +- JellyfinPlayer/VideoUpNextView.swift | 10 +-- Shared/Extensions/APIExtensions.swift | 4 +- Shared/Singleton/SessionManager.swift | 16 ++--- Shared/ViewModels/DetailItemViewModel.swift | 6 +- .../ViewModels/LibraryFilterViewModel.swift | 2 +- Shared/ViewModels/LibraryViewModel.swift | 4 +- Shared/ViewModels/SeasonItemViewModel.swift | 4 +- Shared/ViewModels/SeriesItemViewModel.swift | 24 +++---- 26 files changed, 197 insertions(+), 203 deletions(-) diff --git a/JellyfinPlayer tvOS/Components/LandscapeItemElement.swift b/JellyfinPlayer tvOS/Components/LandscapeItemElement.swift index 91c60847..191545fa 100644 --- a/JellyfinPlayer tvOS/Components/LandscapeItemElement.swift +++ b/JellyfinPlayer tvOS/Components/LandscapeItemElement.swift @@ -91,7 +91,7 @@ struct LandscapeItemElement: View { .shadow(radius: focused ? 10.0 : 0, y: focused ? 10.0 : 0) .shadow(radius: focused ? 10.0 : 0, y: focused ? 10.0 : 0) if focused { - if(inSeasonView ?? false) { + if inSeasonView ?? false { Text("\(item.getEpisodeLocator()) • \(item.name ?? "")") .font(.callout) .fontWeight(.semibold) diff --git a/JellyfinPlayer tvOS/Components/MediaViewActionButton.swift b/JellyfinPlayer tvOS/Components/MediaViewActionButton.swift index 3dac0d68..a8f6135d 100644 --- a/JellyfinPlayer tvOS/Components/MediaViewActionButton.swift +++ b/JellyfinPlayer tvOS/Components/MediaViewActionButton.swift @@ -15,18 +15,18 @@ struct MediaViewActionButton: View { var icon: String var scrollView: Binding? var iconColor: Color? - + var body: some View { Image(systemName: icon) .foregroundColor(focused ? .black : iconColor ?? .white) .onChange(of: envFocused) { envFocus in - if(envFocus == true) { + if envFocus == true { scrollView?.wrappedValue?.scrollToTop() DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { scrollView?.wrappedValue?.scrollToTop() } } - + withAnimation(.linear(duration: 0.15)) { self.focused = envFocus } diff --git a/JellyfinPlayer tvOS/Components/PortraitItemElement.swift b/JellyfinPlayer tvOS/Components/PortraitItemElement.swift index 774b8a13..ecc4dd49 100644 --- a/JellyfinPlayer tvOS/Components/PortraitItemElement.swift +++ b/JellyfinPlayer tvOS/Components/PortraitItemElement.swift @@ -36,8 +36,7 @@ struct PortraitItemElement: View { } } .padding(2) - .opacity(1) - , alignment: .bottomLeading) + .opacity(1), alignment: .bottomLeading) .overlay( ZStack { if item.userData?.played ?? false { @@ -46,7 +45,7 @@ struct PortraitItemElement: View { Image(systemName: "checkmark.circle.fill") .foregroundColor(Color(.systemBlue)) } else { - if(item.userData?.unplayedItemCount != nil) { + if item.userData?.unplayedItemCount != nil { Image(systemName: "circle.fill") .foregroundColor(Color(.systemBlue)) Text(String(item.userData!.unplayedItemCount ?? 0)) diff --git a/JellyfinPlayer tvOS/EpisodeItemView.swift b/JellyfinPlayer tvOS/EpisodeItemView.swift index 1f17810a..2ab53dbe 100644 --- a/JellyfinPlayer tvOS/EpisodeItemView.swift +++ b/JellyfinPlayer tvOS/EpisodeItemView.swift @@ -13,30 +13,30 @@ import JellyfinAPI struct EpisodeItemView: View { @ObservedObject var viewModel: EpisodeItemViewModel - @State var actors: [BaseItemPerson] = []; - @State var studio: String? = nil; - @State var director: String? = nil; - + @State var actors: [BaseItemPerson] = [] + @State var studio: String? + @State var director: String? + func onAppear() { actors = [] director = nil studio = nil - var actor_index = 0; + var actor_index = 0 viewModel.item.people?.forEach { person in - if(person.type == "Actor") { - if(actor_index < 4) { + if person.type == "Actor" { + if actor_index < 4 { actors.append(person) } - actor_index = actor_index + 1; + actor_index = actor_index + 1 } - if(person.type == "Director") { + if person.type == "Director" { director = person.name ?? "" } } - + studio = viewModel.item.studios?.first?.name ?? nil } - + var body: some View { ZStack { ImageView(src: viewModel.item.getBackdropImage(maxWidth: 1920), bh: viewModel.item.getBackdropImageBlurHash()) @@ -71,10 +71,10 @@ struct EpisodeItemView: View { } Spacer() }.padding(.top, -15) - + HStack(alignment: .top) { VStack(alignment: .trailing) { - if(studio != nil) { + if studio != nil { Text("STUDIO") .font(.body) .fontWeight(.semibold) @@ -85,8 +85,8 @@ struct EpisodeItemView: View { .foregroundColor(.secondary) .padding(.bottom, 40) } - - if(director != nil) { + + if director != nil { Text("DIRECTOR") .font(.body) .fontWeight(.semibold) @@ -97,8 +97,8 @@ struct EpisodeItemView: View { .foregroundColor(.secondary) .padding(.bottom, 40) } - - if(!actors.isEmpty) { + + if !actors.isEmpty { Text("CAST") .font(.body) .fontWeight(.semibold) @@ -117,7 +117,7 @@ struct EpisodeItemView: View { .font(.body) .fontWeight(.medium) .foregroundColor(.primary) - + HStack { VStack { Button { @@ -150,7 +150,7 @@ struct EpisodeItemView: View { } }.padding(.top, 50) - if(!viewModel.similarItems.isEmpty) { + if !viewModel.similarItems.isEmpty { Text("More Like This") .font(.headline) .fontWeight(.semibold) diff --git a/JellyfinPlayer tvOS/LibraryView.swift b/JellyfinPlayer tvOS/LibraryView.swift index bcc3188e..f347c744 100644 --- a/JellyfinPlayer tvOS/LibraryView.swift +++ b/JellyfinPlayer tvOS/LibraryView.swift @@ -28,11 +28,11 @@ struct LibraryView: View { ScrollView(.vertical) { LazyVGrid(columns: tracks) { ForEach(viewModel.items, id: \.id) { item in - if(item.type != "Folder") { + if item.type != "Folder" { NavigationLink(destination: LazyView { ItemView(item: item) }) { PortraitItemElement(item: item) }.buttonStyle(PlainNavigationLinkButtonStyle()) - .onAppear() { + .onAppear { if item == viewModel.items.last && viewModel.hasNextPage { print("Last item visible, load more items.") viewModel.requestNextPageAsync() diff --git a/JellyfinPlayer tvOS/MovieItemView.swift b/JellyfinPlayer tvOS/MovieItemView.swift index 6251df29..f163cac8 100644 --- a/JellyfinPlayer tvOS/MovieItemView.swift +++ b/JellyfinPlayer tvOS/MovieItemView.swift @@ -14,36 +14,36 @@ import SwiftUIFocusGuide struct MovieItemView: View { @ObservedObject var viewModel: MovieItemViewModel - @State var actors: [BaseItemPerson] = []; - @State var studio: String? = nil; - @State var director: String? = nil; - - @State var wrappedScrollView: UIScrollView?; - + @State var actors: [BaseItemPerson] = [] + @State var studio: String? + @State var director: String? + + @State var wrappedScrollView: UIScrollView? + @StateObject var focusBag = SwiftUIFocusBag() - + @Namespace private var namespace - + func onAppear() { actors = [] director = nil studio = nil - var actor_index = 0; + var actor_index = 0 viewModel.item.people?.forEach { person in - if(person.type == "Actor") { - if(actor_index < 4) { + if person.type == "Actor" { + if actor_index < 4 { actors.append(person) } - actor_index = actor_index + 1; + actor_index = actor_index + 1 } - if(person.type == "Director") { + if person.type == "Director" { director = person.name ?? "" } } - + studio = viewModel.item.studios?.first?.name ?? nil } - + var body: some View { ZStack { ImageView(src: viewModel.item.getBackdropImage(maxWidth: 1920), bh: viewModel.item.getBackdropImageBlurHash()) @@ -75,10 +75,10 @@ struct MovieItemView: View { .stroke(Color.secondary, lineWidth: 1)) } } - + HStack { VStack(alignment: .trailing) { - if(studio != nil) { + if studio != nil { Text("STUDIO") .font(.body) .fontWeight(.semibold) @@ -89,8 +89,8 @@ struct MovieItemView: View { .foregroundColor(.secondary) .padding(.bottom, 40) } - - if(director != nil) { + + if director != nil { Text("DIRECTOR") .font(.body) .fontWeight(.semibold) @@ -101,8 +101,8 @@ struct MovieItemView: View { .foregroundColor(.secondary) .padding(.bottom, 40) } - - if(!actors.isEmpty) { + + if !actors.isEmpty { Text("CAST") .font(.body) .fontWeight(.semibold) @@ -117,7 +117,7 @@ struct MovieItemView: View { Spacer() } VStack(alignment: .leading) { - if(!(viewModel.item.taglines ?? []).isEmpty) { + if !(viewModel.item.taglines ?? []).isEmpty { Text(viewModel.item.taglines?.first ?? "") .font(.body) .italic() @@ -128,7 +128,7 @@ struct MovieItemView: View { .font(.body) .fontWeight(.medium) .foregroundColor(.primary) - + HStack { VStack { Button { @@ -162,7 +162,7 @@ struct MovieItemView: View { } }.padding(.top, 50) - if(!viewModel.similarItems.isEmpty) { + if !viewModel.similarItems.isEmpty { Text("More Like This") .font(.headline) .fontWeight(.semibold) diff --git a/JellyfinPlayer tvOS/SeasonItemView.swift b/JellyfinPlayer tvOS/SeasonItemView.swift index 52b9640d..795e2ac4 100644 --- a/JellyfinPlayer tvOS/SeasonItemView.swift +++ b/JellyfinPlayer tvOS/SeasonItemView.swift @@ -13,13 +13,13 @@ import SwiftUIFocusGuide struct SeasonItemView: View { @ObservedObject var viewModel: SeasonItemViewModel - @State var wrappedScrollView: UIScrollView?; - + @State var wrappedScrollView: UIScrollView? + @StateObject var focusBag = SwiftUIFocusBag() - + @Environment(\.resetFocus) var resetFocus @Namespace private var namespace - + var body: some View { ZStack { ImageView(src: viewModel.item.getSeriesBackdropImage(maxWidth: 1920), bh: viewModel.item.getSeriesBackdropImageBlurHash()) @@ -31,7 +31,7 @@ struct SeasonItemView: View { .fontWeight(.bold) .foregroundColor(.primary) HStack { - if(viewModel.item.productionYear != nil) { + if viewModel.item.productionYear != nil { Text(String(viewModel.item.productionYear!)).font(.subheadline) .fontWeight(.medium) .foregroundColor(.secondary) @@ -58,9 +58,9 @@ struct SeasonItemView: View { } } } - + VStack(alignment: .leading) { - if(!(viewModel.item.taglines ?? []).isEmpty) { + if !(viewModel.item.taglines ?? []).isEmpty { Text(viewModel.item.taglines?.first ?? "") .font(.body) .italic() @@ -71,7 +71,7 @@ struct SeasonItemView: View { .font(.body) .fontWeight(.medium) .foregroundColor(.primary) - + HStack { VStack { Button { @@ -96,7 +96,7 @@ struct SeasonItemView: View { Spacer() }.padding(.top, 50) - if(!viewModel.episodes.isEmpty) { + if !viewModel.episodes.isEmpty { Text("Episodes") .font(.headline) .fontWeight(.semibold) diff --git a/JellyfinPlayer tvOS/SeriesItemView.swift b/JellyfinPlayer tvOS/SeriesItemView.swift index 5234f676..cab03c10 100644 --- a/JellyfinPlayer tvOS/SeriesItemView.swift +++ b/JellyfinPlayer tvOS/SeriesItemView.swift @@ -14,14 +14,14 @@ import SwiftUIFocusGuide struct SeriesItemView: View { @ObservedObject var viewModel: SeriesItemViewModel - @State var actors: [BaseItemPerson] = []; - @State var studio: String? = nil; - @State var director: String? = nil; - - @State var wrappedScrollView: UIScrollView?; - + @State var actors: [BaseItemPerson] = [] + @State var studio: String? + @State var director: String? + + @State var wrappedScrollView: UIScrollView? + @StateObject var focusBag = SwiftUIFocusBag() - + @Environment(\.resetFocus) var resetFocus @Namespace private var namespace @@ -29,22 +29,22 @@ struct SeriesItemView: View { actors = [] director = nil studio = nil - var actor_index = 0; + var actor_index = 0 viewModel.item.people?.forEach { person in - if(person.type == "Actor") { - if(actor_index < 4) { + if person.type == "Actor" { + if actor_index < 4 { actors.append(person) } - actor_index = actor_index + 1; + actor_index = actor_index + 1 } - if(person.type == "Director") { + if person.type == "Director" { director = person.name ?? "" } } - + studio = viewModel.item.studios?.first?.name ?? nil } - + var body: some View { ZStack { ImageView(src: viewModel.item.getBackdropImage(maxWidth: 1920), bh: viewModel.item.getBackdropImageBlurHash()) @@ -81,10 +81,10 @@ struct SeriesItemView: View { } } } - + HStack { VStack(alignment: .trailing) { - if(studio != nil) { + if studio != nil { Text("STUDIO") .font(.body) .fontWeight(.semibold) @@ -95,8 +95,8 @@ struct SeriesItemView: View { .foregroundColor(.secondary) .padding(.bottom, 40) } - - if(director != nil) { + + if director != nil { Text("DIRECTOR") .font(.body) .fontWeight(.semibold) @@ -107,8 +107,8 @@ struct SeriesItemView: View { .foregroundColor(.secondary) .padding(.bottom, 40) } - - if(!actors.isEmpty) { + + if !actors.isEmpty { Text("CAST") .font(.body) .fontWeight(.semibold) @@ -123,7 +123,7 @@ struct SeriesItemView: View { Spacer() } VStack(alignment: .leading) { - if(!(viewModel.item.taglines ?? []).isEmpty) { + if !(viewModel.item.taglines ?? []).isEmpty { Text(viewModel.item.taglines?.first ?? "") .font(.body) .italic() @@ -134,7 +134,7 @@ struct SeriesItemView: View { .font(.body) .fontWeight(.medium) .foregroundColor(.primary) - + HStack { VStack { Button { @@ -145,7 +145,7 @@ struct SeriesItemView: View { Text(viewModel.isFavorited ? "Unfavorite" : "Favorite") .font(.caption) } - if(viewModel.nextUpItem != nil) { + if viewModel.nextUpItem != nil { VStack { NavigationLink(destination: VideoPlayerView(item: viewModel.nextUpItem!)) { MediaViewActionButton(icon: "play.fill", scrollView: $wrappedScrollView) @@ -167,8 +167,8 @@ struct SeriesItemView: View { Spacer() } }.padding(.top, 50) - - if(viewModel.nextUpItem != nil) { + + if viewModel.nextUpItem != nil { Text("Next Up") .font(.headline) .fontWeight(.semibold) @@ -176,8 +176,8 @@ struct SeriesItemView: View { LandscapeItemElement(item: viewModel.nextUpItem!) }.buttonStyle(PlainNavigationLinkButtonStyle()).padding(.bottom, 1) } - - if(!viewModel.seasons.isEmpty) { + + if !viewModel.seasons.isEmpty { Text("Seasons") .font(.headline) .fontWeight(.semibold) @@ -194,8 +194,8 @@ struct SeriesItemView: View { }.padding(EdgeInsets(top: -30, leading: -90, bottom: 0, trailing: -90)) .frame(height: 360) } - - if(!viewModel.similarItems.isEmpty) { + + if !viewModel.similarItems.isEmpty { Text("More Like This") .font(.headline) .fontWeight(.semibold) diff --git a/JellyfinPlayer tvOS/VideoPlayer/AudioView.swift b/JellyfinPlayer tvOS/VideoPlayer/AudioView.swift index da404b99..9b198f94 100644 --- a/JellyfinPlayer tvOS/VideoPlayer/AudioView.swift +++ b/JellyfinPlayer tvOS/VideoPlayer/AudioView.swift @@ -10,7 +10,7 @@ import SwiftUI class AudioViewController: InfoTabViewController { - + override func viewDidLoad() { super.viewDidLoad() diff --git a/JellyfinPlayer tvOS/VideoPlayer/InfoTabBarViewController.swift b/JellyfinPlayer tvOS/VideoPlayer/InfoTabBarViewController.swift index 431852c6..e7f13ebd 100644 --- a/JellyfinPlayer tvOS/VideoPlayer/InfoTabBarViewController.swift +++ b/JellyfinPlayer tvOS/VideoPlayer/InfoTabBarViewController.swift @@ -11,10 +11,9 @@ import TVUIKit import JellyfinAPI class InfoTabViewController: UIViewController { - var height : CGFloat = 420 + var height: CGFloat = 420 } - class InfoTabBarViewController: UITabBarController, UIGestureRecognizerDelegate { var videoPlayer: VideoPlayerViewController? @@ -39,11 +38,11 @@ class InfoTabBarViewController: UITabBarController, UIGestureRecognizerDelegate audioViewController?.prepareAudioView(audioTracks: audioTracks, selectedTrack: selectedAudioTrack, delegate: delegate) subtitleViewController?.prepareSubtitleView(subtitleTracks: subtitleTracks, selectedTrack: selectedSubtitleTrack, delegate: delegate) - + } override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) { - + if let index = tabBar.items?.firstIndex(of: item), let tabViewController = viewControllers?[index] as? InfoTabViewController, let width = videoPlayer?.infoPanelContainerView.frame.width { diff --git a/JellyfinPlayer tvOS/VideoPlayer/MediaInfoView.swift b/JellyfinPlayer tvOS/VideoPlayer/MediaInfoView.swift index ab2d5dec..4be09ea5 100644 --- a/JellyfinPlayer tvOS/VideoPlayer/MediaInfoView.swift +++ b/JellyfinPlayer tvOS/VideoPlayer/MediaInfoView.swift @@ -50,11 +50,11 @@ struct MediaInfoView: View { if item.type == "Episode" { Text(item.seriesName ?? "Series") .fontWeight(.bold) - + HStack { Text(item.name ?? "Episode") .foregroundColor(.secondary) - + Text(item.getEpisodeLocator()) if let date = item.premiereDate { @@ -67,7 +67,7 @@ struct MediaInfoView: View { } HStack(spacing: 10) { - if(item.type != "Episode") { + if item.type != "Episode" { if let year = item.productionYear { Text(String(year)) } diff --git a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift index 0dd87206..96cfe7dd 100644 --- a/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift +++ b/JellyfinPlayer tvOS/VideoPlayer/VideoPlayerViewController.swift @@ -227,7 +227,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, if let rawStartTicks = manifest.userData?.playbackPositionTicks { mediaPlayer.jumpForward(Int32(rawStartTicks / 10_000_000)) } - + subtitleTrackArray.forEach { sub in if sub.id != -1 && sub.delivery == .external { mediaPlayer.addPlaybackSlave(sub.url!, type: .subtitle, enforce: false) @@ -247,13 +247,13 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, let commandCenter = MPRemoteCommandCenter.shared() commandCenter.playCommand.isEnabled = true commandCenter.pauseCommand.isEnabled = true - + commandCenter.skipBackwardCommand.isEnabled = true commandCenter.skipBackwardCommand.preferredIntervals = [15] - + commandCenter.skipForwardCommand.isEnabled = true commandCenter.skipForwardCommand.preferredIntervals = [30] - + commandCenter.changePlaybackPositionCommand.isEnabled = true commandCenter.enableLanguageOptionCommand.isEnabled = true @@ -275,14 +275,14 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, } // Add handler for FF command - commandCenter.skipForwardCommand.addTarget { skipEvent in + commandCenter.skipForwardCommand.addTarget { _ in self.mediaPlayer.jumpForward(30) self.sendProgressReport(eventName: "timeupdate") return .success } // Add handler for RW command - commandCenter.skipBackwardCommand.addTarget { skipEvent in + commandCenter.skipBackwardCommand.addTarget { _ in self.mediaPlayer.jumpBackward(15) self.sendProgressReport(eventName: "timeupdate") return .success @@ -324,7 +324,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, var nowPlayingInfo = [String: Any]() nowPlayingInfo[MPMediaItemPropertyTitle] = manifest.name ?? "Jellyfin Video" - if(manifest.type == "Episode") { + if manifest.type == "Episode" { nowPlayingInfo[MPMediaItemPropertyArtist] = "\(manifest.seriesName ?? manifest.name ?? "") • \(manifest.getEpisodeLocator())" } nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 0.0 @@ -421,26 +421,26 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, UIView.animate(withDuration: 0.4, delay: 0, options: .curveEaseOut) { [self] in let size = infoPanelContainerView.frame.size - let y : CGFloat = showingInfoPanel ? 87 : -size.height - + let y: CGFloat = showingInfoPanel ? 87 : -size.height + infoPanelContainerView.frame = CGRect(x: 88, y: y, width: size.width, height: size.height) } } - + // MARK: Gestures override func pressesBegan(_ presses: Set, with event: UIPressesEvent?) { for item in presses { - if(item.type == .select) { + if item.type == .select { selectButtonTapped() } } } - + func setupGestures() { self.becomeFirstResponder() - - //vlc crap + + // vlc crap videoContentView.gestureRecognizers?.forEach { gr in videoContentView.removeGestureRecognizer(gr) } @@ -449,17 +449,17 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, sv.removeGestureRecognizer(gr) } } - + let playPauseGesture = UITapGestureRecognizer(target: self, action: #selector(self.selectButtonTapped)) let playPauseType = UIPress.PressType.playPause playPauseGesture.allowedPressTypes = [NSNumber(value: playPauseType.rawValue)] view.addGestureRecognizer(playPauseGesture) - + let backTapGesture = UITapGestureRecognizer(target: self, action: #selector(self.backButtonPressed(tap:))) let backPress = UIPress.PressType.menu backTapGesture.allowedPressTypes = [NSNumber(value: backPress.rawValue)] view.addGestureRecognizer(backTapGesture) - + let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.userPanned(panGestureRecognizer:))) view.addGestureRecognizer(panGestureRecognizer) } @@ -497,7 +497,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, let translation = panGestureRecognizer.translation(in: view) let velocity = panGestureRecognizer.velocity(in: view) - + // Swiped up - Handle dismissing info panel if translation.y < -200 && (focusedOnTabBar && showingInfoPanel) { toggleInfoContainer() @@ -580,7 +580,7 @@ class VideoPlayerViewController: UIViewController, VideoPlayerSettingsDelegate, // MARK: Jellyfin Playstate updates func sendProgressReport(eventName: String) { updateNowPlayingCenter(time: nil, playing: mediaPlayer.state == .playing) - + if (eventName == "timeupdate" && mediaPlayer.state == .playing) || eventName != "timeupdate" { let progressInfo = PlaybackProgressInfo(canSeek: true, item: manifest, itemId: manifest.id, sessionId: playSessionId, mediaSourceId: manifest.id, audioStreamIndex: Int(selectedAudioTrack), subtitleStreamIndex: Int(selectedCaptionTrack), isPaused: (!playing), isMuted: false, positionTicks: Int64(mediaPlayer.position * Float(manifest.runTimeTicks!)), playbackStartTimeTicks: Int64(startTime), volumeLevel: 100, brightness: 100, aspectRatio: nil, playMethod: playbackItem.videoType, liveStreamId: nil, playSessionId: playSessionId, repeatMode: .repeatNone, nowPlayingQueue: [], playlistItemId: "playlistItem0") diff --git a/JellyfinPlayer/Components/PortraitItemView.swift b/JellyfinPlayer/Components/PortraitItemView.swift index 37bc2045..fcc261a2 100644 --- a/JellyfinPlayer/Components/PortraitItemView.swift +++ b/JellyfinPlayer/Components/PortraitItemView.swift @@ -11,7 +11,7 @@ import SwiftUI import JellyfinAPI struct PortraitItemView: View { var item: BaseItemDto - + var body: some View { NavigationLink(destination: LazyView { ItemView(item: item) }) { VStack(alignment: .leading) { @@ -39,8 +39,7 @@ struct PortraitItemView: View { } .padding(.leading, 2) .padding(.bottom, item.userData?.playedPercentage == nil ? 2 : 9) - .opacity(1) - , alignment: .bottomLeading) + .opacity(1), alignment: .bottomLeading) .overlay( ZStack { if item.userData?.played ?? false { @@ -49,7 +48,7 @@ struct PortraitItemView: View { Image(systemName: "checkmark.circle.fill") .foregroundColor(Color(.systemBlue)) } else { - if(item.userData?.unplayedItemCount != nil) { + if item.userData?.unplayedItemCount != nil { Image(systemName: "circle.fill") .foregroundColor(Color(.systemBlue)) Text(String(item.userData!.unplayedItemCount ?? 0)) @@ -64,12 +63,12 @@ struct PortraitItemView: View { .fontWeight(.semibold) .foregroundColor(.primary) .lineLimit(1) - if(item.type == "Movie" || item.type == "Series") { + if item.type == "Movie" || item.type == "Series" { Text("\(String(item.productionYear ?? 0)) • \(item.officialRating ?? "N/A")") .foregroundColor(.secondary) .font(.caption) .fontWeight(.medium) - } else if(item.type == "Season") { + } else if item.type == "Season" { Text("\(item.name ?? "") • \(String(item.productionYear ?? 0))") .foregroundColor(.secondary) .font(.caption) diff --git a/JellyfinPlayer/LibraryListView.swift b/JellyfinPlayer/LibraryListView.swift index f3b833aa..2d6669df 100644 --- a/JellyfinPlayer/LibraryListView.swift +++ b/JellyfinPlayer/LibraryListView.swift @@ -56,7 +56,7 @@ struct LibraryListView: View { .shadow(radius: 5) .padding(.bottom, 15) - if(!viewModel.isLoading) { + if !viewModel.isLoading { ForEach(viewModel.libraries, id: \.id) { library in if library.collectionType ?? "" == "movies" || library.collectionType ?? "" == "tvshows" { NavigationLink(destination: LazyView { @@ -67,7 +67,7 @@ struct LibraryListView: View { .opacity(0.4) HStack { Spacer() - VStack() { + VStack { Text(library.name ?? "") .foregroundColor(.white) .font(.title2) diff --git a/JellyfinPlayer/LibraryView.swift b/JellyfinPlayer/LibraryView.swift index 4cfd2385..ee6b6a48 100644 --- a/JellyfinPlayer/LibraryView.swift +++ b/JellyfinPlayer/LibraryView.swift @@ -34,7 +34,7 @@ struct LibraryView: View { Spacer().frame(height: 16) LazyVGrid(columns: tracks) { ForEach(viewModel.items, id: \.id) { item in - if(item.type != "Folder") { + if item.type != "Folder" { PortraitItemView(item: item) } } diff --git a/JellyfinPlayer/SeasonItemView.swift b/JellyfinPlayer/SeasonItemView.swift index 9b1c817c..6d3758be 100644 --- a/JellyfinPlayer/SeasonItemView.swift +++ b/JellyfinPlayer/SeasonItemView.swift @@ -89,8 +89,7 @@ struct SeasonItemView: View { } .padding(.leading, 2) .padding(.bottom, episode.userData?.playedPercentage == nil ? 2 : 9) - .opacity(1) - , alignment: .bottomLeading) + .opacity(1), alignment: .bottomLeading) .overlay( ZStack { if episode.userData?.played ?? false { diff --git a/JellyfinPlayer/VideoPlayer.swift b/JellyfinPlayer/VideoPlayer.swift index fc5b5258..f486c24c 100644 --- a/JellyfinPlayer/VideoPlayer.swift +++ b/JellyfinPlayer/VideoPlayer.swift @@ -68,21 +68,21 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } var hasSentRemoteSeek: Bool = false - var selectedPlaybackSpeedIndex : Int = 3 + var selectedPlaybackSpeedIndex: Int = 3 var selectedAudioTrack: Int32 = -1 var selectedCaptionTrack: Int32 = -1 var playSessionId: String = "" var lastProgressReportTime: Double = 0 var subtitleTrackArray: [Subtitle] = [] var audioTrackArray: [AudioTrack] = [] - let playbackSpeeds : [Float] = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] + let playbackSpeeds: [Float] = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] var manifest: BaseItemDto = BaseItemDto() var playbackItem = PlaybackItem() var remoteTimeUpdateTimer: Timer? var upNextViewModel: UpNextViewModel = UpNextViewModel() var lastOri: UIDeviceOrientation! - + // MARK: IBActions @IBAction func seekSliderStart(_ sender: Any) { if playerDestination == .local { @@ -348,34 +348,34 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe } } - var nowPlayingInfo = [String : Any]() - + var nowPlayingInfo = [String: Any]() + var runTicks = 0 var playbackTicks = 0 - + if let ticks = manifest.runTimeTicks { runTicks = Int(ticks / 10_000_000) } - + if let ticks = manifest.userData?.playbackPositionTicks { playbackTicks = Int(ticks / 10_000_000) } - + nowPlayingInfo[MPMediaItemPropertyTitle] = manifest.name ?? "Jellyfin Video" nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0 nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = AVMediaType.video nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = runTicks nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = playbackTicks - + if let imageData = NSData(contentsOf: manifest.getPrimaryImage(maxWidth: 200)) { if let artworkImage = UIImage(data: imageData as Data) { - let artwork = MPMediaItemArtwork.init(boundsSize: artworkImage.size, requestHandler: { (size) -> UIImage in + let artwork = MPMediaItemArtwork.init(boundsSize: artworkImage.size, requestHandler: { (_) -> UIImage in return artworkImage }) nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork } } - + MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo UIApplication.shared.beginReceivingRemoteControlEvents() @@ -387,11 +387,11 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe titleLabel.text = manifest.name ?? "" } else { titleLabel.text = "S\(String(manifest.parentIndexNumber ?? 0)):E\(String(manifest.indexNumber ?? 0)) “\(manifest.name ?? "")”" - + setupNextUpView() upNextViewModel.delegate = self } - + lastOri = UIDevice.current.orientation if !UIDevice.current.orientation.isLandscape || UIDevice.current.orientation.isFlat { @@ -454,12 +454,12 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe mediaPlayer.delegate = self mediaPlayer.drawable = videoContentView - + setupMediaPlayer() } - + func setupMediaPlayer() { - + // Fetch max bitrate from UserDefaults depending on current connection mode let maxBitrate = Defaults[.inNetworkBandwidth] print(maxBitrate) @@ -580,8 +580,8 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe self.sendPlayReport() playbackItem = item - - //self.setupNowPlayingCC() + + // self.setupNowPlayingCC() } startLocalPlaybackEngine(true) @@ -678,21 +678,21 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe selectedAudioTrack = newTrackID mediaPlayer.currentAudioTrackIndex = newTrackID } - + func playbackSpeedChanged(index: Int) { selectedPlaybackSpeedIndex = index mediaPlayer.rate = playbackSpeeds[index] } - + func smallNextUpView() { UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseIn) { [self] in upNextViewModel.largeView = false } } - + func setupNextUpView() { getNextEpisode() - + // Create the swiftUI view let contentView = UIHostingController(rootView: VideoUpNextView(viewModel: upNextViewModel)) self.upNextView.addSubview(contentView.view) @@ -703,7 +703,7 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe contentView.view.leftAnchor.constraint(equalTo: upNextView.leftAnchor).isActive = true contentView.view.rightAnchor.constraint(equalTo: upNextView.rightAnchor).isActive = true } - + func getNextEpisode() { TvShowsAPI.getEpisodes(seriesId: manifest.seriesId!, userId: SessionManager.current.user.user_id!, startItemId: manifest.id, limit: 2) .sink(receiveCompletion: { completion in @@ -717,22 +717,21 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe }) .store(in: &cancellables) } - + func setPlayerToNextUp() { mediaPlayer.stop() - + ssTargetValueOffset = 0 ssStartValue = 0 - + paused = true lastTime = 0.0 startTime = 0 controlsAppearTime = 0 isSeeking = false - remotePositionTicks = 0 - + selectedPlaybackSpeedIndex = 3 selectedAudioTrack = -1 selectedCaptionTrack = -1 @@ -740,22 +739,22 @@ class PlayerViewController: UIViewController, GCKDiscoveryManagerListener, GCKRe lastProgressReportTime = 0 subtitleTrackArray = [] audioTrackArray = [] - + manifest = upNextViewModel.item! playbackItem = PlaybackItem() - + upNextViewModel.item = nil - + upNextView.isHidden = true shouldShowLoadingScreen = true videoControlsView.isHidden = true titleLabel.text = "S\(String(manifest.parentIndexNumber ?? 0)):E\(String(manifest.indexNumber ?? 0)) “\(manifest.name ?? "")”" - + setupMediaPlayer() getNextEpisode() } - + } // MARK: - GCKGenericChannelDelegate @@ -951,8 +950,8 @@ extension PlayerViewController: VLCMediaPlayerDelegate { mainActionButton.setImage(UIImage(systemName: "pause"), for: .normal) seekSlider.setValue(mediaPlayer.position, animated: true) delegate?.hideLoadingView(self) - - if manifest.type == "Episode" && upNextViewModel.item != nil{ + + if manifest.type == "Episode" && upNextViewModel.item != nil { if time > 0.96 { upNextView.isHidden = false self.jumpForwardButton.isHidden = true @@ -961,7 +960,7 @@ extension PlayerViewController: VLCMediaPlayerDelegate { self.jumpForwardButton.isHidden = false } } - + timeText.text = String(mediaPlayer.remainingTime.stringValue.dropFirst()) if CACurrentMediaTime() - controlsAppearTime > 5 { diff --git a/JellyfinPlayer/VideoPlayerSettingsView.swift b/JellyfinPlayer/VideoPlayerSettingsView.swift index c7045849..a6aab3fb 100644 --- a/JellyfinPlayer/VideoPlayerSettingsView.swift +++ b/JellyfinPlayer/VideoPlayerSettingsView.swift @@ -37,8 +37,8 @@ struct VideoPlayerSettings: View { weak var delegate: PlayerViewController! @State var captionTrack: Int32 = -99 @State var audioTrack: Int32 = -99 - @State var playbackSpeedSelection : Int = 3 - + @State var playbackSpeedSelection: Int = 3 + init(delegate: PlayerViewController) { self.delegate = delegate } @@ -66,8 +66,7 @@ struct VideoPlayerSettings: View { let speed = delegate.playbackSpeeds[speedIndex] if floor(speed) == speed { Text(String(format: "%.0fx", speed)).tag(speedIndex) - } - else { + } else { Text(String(format: "%.2fx", speed)).tag(speedIndex) } } diff --git a/JellyfinPlayer/VideoUpNextView.swift b/JellyfinPlayer/VideoUpNextView.swift index ee5fd47d..7ad06a9d 100644 --- a/JellyfinPlayer/VideoUpNextView.swift +++ b/JellyfinPlayer/VideoUpNextView.swift @@ -12,9 +12,9 @@ import JellyfinAPI class UpNextViewModel: ObservableObject { @Published var largeView: Bool = false - @Published var item: BaseItemDto? = nil - var delegate: PlayerViewController? - + @Published var item: BaseItemDto? + weak var delegate: PlayerViewController? + func nextUp() { if delegate != nil { delegate?.setPlayerToNextUp() @@ -23,9 +23,9 @@ class UpNextViewModel: ObservableObject { } struct VideoUpNextView: View { - + @ObservedObject var viewModel: UpNextViewModel - + var body: some View { Button { viewModel.nextUp() diff --git a/Shared/Extensions/APIExtensions.swift b/Shared/Extensions/APIExtensions.swift index 041913b0..5dcdeffc 100644 --- a/Shared/Extensions/APIExtensions.swift +++ b/Shared/Extensions/APIExtensions.swift @@ -73,7 +73,7 @@ extension BaseItemDto { let urlString = "\(ServerEnvironment.current.server.baseURI!)/Items/\(imageItemId)/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)" return URL(string: urlString)! } - + func getEpisodeLocator() -> String { if let seasonNo = self.parentIndexNumber, let episodeNo = self.indexNumber { return "S\(seasonNo):E\(episodeNo)" @@ -111,7 +111,7 @@ extension BaseItemDto { let x = UIScreen.main.nativeScale * CGFloat(maxWidth) let urlString = "\(ServerEnvironment.current.server.baseURI!)/Items/\(imageItemId)/Images/\(imageType)?maxWidth=\(String(Int(x)))&quality=96&tag=\(imageTag)" - //print(urlString) + // print(urlString) return URL(string: urlString)! } diff --git a/Shared/Singleton/SessionManager.swift b/Shared/Singleton/SessionManager.swift index 2102a467..8c4e29fc 100644 --- a/Shared/Singleton/SessionManager.swift +++ b/Shared/Singleton/SessionManager.swift @@ -54,17 +54,17 @@ final class SessionManager { var deviceName = UIDevice.current.name deviceName = deviceName.folding(options: .diacriticInsensitive, locale: .current) deviceName = String(deviceName.unicodeScalars.filter {CharacterSet.urlQueryAllowed.contains($0) }) - + var header = "MediaBrowser " #if os(tvOS) header.append("Client=\"Jellyfin tvOS\", ") #else header.append("Client=\"SwiftFin iOS\", ") #endif - + header.append("Device=\"\(deviceName)\", ") - - if(devID == nil) { + + if devID == nil { #if os(tvOS) header.append("DeviceId=\"tvOS_\(UIDevice.current.identifierForVendor!.uuidString)_\(String(Date().timeIntervalSince1970))\", ") deviceID = "tvOS_\(UIDevice.current.identifierForVendor!.uuidString)_\(String(Date().timeIntervalSince1970))" @@ -78,7 +78,7 @@ final class SessionManager { header.append("DeviceId=\"\(devID!)\", ") deviceID = devID! } - + header.append("Version=\"\(appVersion ?? "0.0.1")\", ") if authToken != nil { @@ -116,8 +116,8 @@ final class SessionManager { func loginWithSavedSession(user: SignedInUser) { let accessToken = getAuthToken(userID: user.user_id!) - print("logging in with saved session"); - + print("logging in with saved session") + self.user = user generateAuthHeader(with: accessToken, deviceID: user.device_uuid) print(JellyfinAPI.customHeaders) @@ -134,7 +134,7 @@ final class SessionManager { user.username = response.user?.name user.user_id = response.user?.id user.device_uuid = self.deviceID - + #if os(tvOS) // user.appletv_id = tvUserManager.currentUserIdentifier ?? "" #endif diff --git a/Shared/ViewModels/DetailItemViewModel.swift b/Shared/ViewModels/DetailItemViewModel.swift index 1056c6f4..ce18e4d4 100644 --- a/Shared/ViewModels/DetailItemViewModel.swift +++ b/Shared/ViewModels/DetailItemViewModel.swift @@ -14,7 +14,7 @@ import JellyfinAPI class DetailItemViewModel: ViewModel { @Published var item: BaseItemDto @Published var similarItems: [BaseItemDto] = [] - + @Published var isWatched = false @Published var isFavorited = false @@ -23,10 +23,10 @@ class DetailItemViewModel: ViewModel { isFavorited = item.userData?.isFavorite ?? false isWatched = item.userData?.played ?? false super.init() - + getRelatedItems() } - + func getRelatedItems() { LibraryAPI.getSimilarItems(itemId: item.id!, userId: SessionManager.current.user.user_id!, limit: 20, fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people]) .trackActivity(loading) diff --git a/Shared/ViewModels/LibraryFilterViewModel.swift b/Shared/ViewModels/LibraryFilterViewModel.swift index afbc206a..1eb81c7c 100644 --- a/Shared/ViewModels/LibraryFilterViewModel.swift +++ b/Shared/ViewModels/LibraryFilterViewModel.swift @@ -39,7 +39,7 @@ final class LibraryFilterViewModel: ViewModel { var selectedSortOrder: APISortOrder = .descending @Published var selectedSortBy: SortBy = .name - + var parentId: String = "" func updateModifiedFilter() { diff --git a/Shared/ViewModels/LibraryViewModel.swift b/Shared/ViewModels/LibraryViewModel.swift index daabc25b..ec88dde7 100644 --- a/Shared/ViewModels/LibraryViewModel.swift +++ b/Shared/ViewModels/LibraryViewModel.swift @@ -87,7 +87,7 @@ final class LibraryViewModel: ViewModel { }) .store(in: &cancellables) } - + func requestItemsAsync(with filters: LibraryFilters) { let personIDs: [String] = [person].compactMap(\.?.id) let studioIDs: [String] = [studio].compactMap(\.?.id) @@ -121,7 +121,7 @@ final class LibraryViewModel: ViewModel { currentPage += 1 requestItems(with: filters) } - + func requestNextPageAsync() { currentPage += 1 requestItemsAsync(with: filters) diff --git a/Shared/ViewModels/SeasonItemViewModel.swift b/Shared/ViewModels/SeasonItemViewModel.swift index 0d1a175d..90895feb 100644 --- a/Shared/ViewModels/SeasonItemViewModel.swift +++ b/Shared/ViewModels/SeasonItemViewModel.swift @@ -13,11 +13,11 @@ import JellyfinAPI final class SeasonItemViewModel: DetailItemViewModel { @Published var episodes = [BaseItemDto]() - + override init(item: BaseItemDto) { super.init(item: item) self.item = item - + requestEpisodes() } diff --git a/Shared/ViewModels/SeriesItemViewModel.swift b/Shared/ViewModels/SeriesItemViewModel.swift index 02f6df5b..11b094a7 100644 --- a/Shared/ViewModels/SeriesItemViewModel.swift +++ b/Shared/ViewModels/SeriesItemViewModel.swift @@ -14,15 +14,15 @@ import JellyfinAPI final class SeriesItemViewModel: DetailItemViewModel { @Published var seasons = [BaseItemDto]() @Published var nextUpItem: BaseItemDto? - + override init(item: BaseItemDto) { super.init(item: item) self.item = item - + requestSeasons() getNextUp() } - + func getNextUp() { TvShowsAPI.getNextUp(userId: SessionManager.current.user.user_id!, fields: [.primaryImageAspectRatio, .seriesPrimaryImage, .seasonUserData, .overview, .genres, .people], seriesId: self.item.id!, enableUserData: true) .trackActivity(loading) @@ -33,22 +33,22 @@ final class SeriesItemViewModel: DetailItemViewModel { }) .store(in: &cancellables) } - + func getRunYears() -> String { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy" - - var startYear: String? = nil - var endYear: String? = nil - - if(item.premiereDate != nil) { + + var startYear: String? + var endYear: String? + + if item.premiereDate != nil { startYear = dateFormatter.string(from: item.premiereDate!) } - - if(item.endDate != nil) { + + if item.endDate != nil { endYear = dateFormatter.string(from: item.endDate!) } - + return "\(startYear ?? "Unknown") - \(endYear ?? "Present")" }