From 317a7afd96c6019ed7ea2325f45e1a5cf771286d Mon Sep 17 00:00:00 2001 From: Francesco <100066266+cranci1@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:08:32 +0100 Subject: [PATCH] progress saving --- Sora.xcodeproj/project.pbxproj | 26 ++++-- .../UserInterfaceState.xcuserstate | Bin 41103 -> 45788 bytes Sora/Utils/Player/PlayerView.swift | 40 --------- Sora/Utils/Player/VideoPlayerView.swift | 78 ++++++++++++++++++ Sora/Views/AnimeViews/AnimeInfoView.swift | 34 ++------ .../EpisodeCell/CircularProgressBar.swift | 31 +++++++ .../AnimeViews/EpisodeCell/EpisodeCell.swift | 36 ++++++++ 7 files changed, 175 insertions(+), 70 deletions(-) delete mode 100644 Sora/Utils/Player/PlayerView.swift create mode 100644 Sora/Utils/Player/VideoPlayerView.swift create mode 100644 Sora/Views/AnimeViews/EpisodeCell/CircularProgressBar.swift create mode 100644 Sora/Views/AnimeViews/EpisodeCell/EpisodeCell.swift diff --git a/Sora.xcodeproj/project.pbxproj b/Sora.xcodeproj/project.pbxproj index 7fa4446..048c571 100644 --- a/Sora.xcodeproj/project.pbxproj +++ b/Sora.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ 132417A12D1319E800B4F2D2 /* ModuleStruct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417992D1319E800B4F2D2 /* ModuleStruct.swift */; }; 132417A22D1319E800B4F2D2 /* ModulesManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1324179A2D1319E800B4F2D2 /* ModulesManager.swift */; }; 132417A32D1319E800B4F2D2 /* NormalPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1324179C2D1319E800B4F2D2 /* NormalPlayer.swift */; }; - 132417A42D1319E800B4F2D2 /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1324179D2D1319E800B4F2D2 /* PlayerView.swift */; }; 132417B82D131A0600B4F2D2 /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417A72D131A0600B4F2D2 /* SearchView.swift */; }; 132417B92D131A0600B4F2D2 /* SearchResultsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417A82D131A0600B4F2D2 /* SearchResultsView.swift */; }; 132417BA2D131A0600B4F2D2 /* SettingsAboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417AB2D131A0600B4F2D2 /* SettingsAboutView.swift */; }; @@ -33,6 +32,9 @@ 132417C42D131A0600B4F2D2 /* AnimeInfoExtraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417B72D131A0600B4F2D2 /* AnimeInfoExtraction.swift */; }; 132417CF2D131B7400B4F2D2 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 132417CE2D131B7400B4F2D2 /* SwiftSoup */; }; 132417D22D131C5300B4F2D2 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 132417D12D131C5300B4F2D2 /* Kingfisher */; }; + 132417D52D13240200B4F2D2 /* EpisodeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417D42D13240200B4F2D2 /* EpisodeCell.swift */; }; + 132417D72D13242400B4F2D2 /* CircularProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417D62D13242400B4F2D2 /* CircularProgressBar.swift */; }; + 132417D92D1328B900B4F2D2 /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417D82D1328B900B4F2D2 /* VideoPlayerView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -47,7 +49,6 @@ 132417992D1319E800B4F2D2 /* ModuleStruct.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModuleStruct.swift; sourceTree = ""; }; 1324179A2D1319E800B4F2D2 /* ModulesManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModulesManager.swift; sourceTree = ""; }; 1324179C2D1319E800B4F2D2 /* NormalPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NormalPlayer.swift; sourceTree = ""; }; - 1324179D2D1319E800B4F2D2 /* PlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerView.swift; sourceTree = ""; }; 132417A72D131A0600B4F2D2 /* SearchView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = ""; }; 132417A82D131A0600B4F2D2 /* SearchResultsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchResultsView.swift; sourceTree = ""; }; 132417AB2D131A0600B4F2D2 /* SettingsAboutView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAboutView.swift; sourceTree = ""; }; @@ -62,6 +63,9 @@ 132417B62D131A0600B4F2D2 /* AnimeInfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimeInfoView.swift; sourceTree = ""; }; 132417B72D131A0600B4F2D2 /* AnimeInfoExtraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimeInfoExtraction.swift; sourceTree = ""; }; 132417C52D131AA500B4F2D2 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 132417D42D13240200B4F2D2 /* EpisodeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EpisodeCell.swift; sourceTree = ""; }; + 132417D62D13242400B4F2D2 /* CircularProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularProgressBar.swift; sourceTree = ""; }; + 132417D82D1328B900B4F2D2 /* VideoPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoPlayerView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -97,8 +101,8 @@ isa = PBXGroup; children = ( 132417C52D131AA500B4F2D2 /* Info.plist */, - 132417A52D131A0600B4F2D2 /* Views */, 132417912D1319E800B4F2D2 /* Utils */, + 132417A52D131A0600B4F2D2 /* Views */, 132417832D13198000B4F2D2 /* SoraApp.swift */, 132417852D13198000B4F2D2 /* ContentView.swift */, 132417872D13198200B4F2D2 /* Assets.xcassets */, @@ -163,8 +167,8 @@ 1324179B2D1319E800B4F2D2 /* Player */ = { isa = PBXGroup; children = ( + 132417D82D1328B900B4F2D2 /* VideoPlayerView.swift */, 1324179C2D1319E800B4F2D2 /* NormalPlayer.swift */, - 1324179D2D1319E800B4F2D2 /* PlayerView.swift */, ); path = Player; sourceTree = ""; @@ -223,12 +227,22 @@ 132417B52D131A0600B4F2D2 /* AnimeViews */ = { isa = PBXGroup; children = ( + 132417D32D1323F500B4F2D2 /* EpisodeCell */, 132417B62D131A0600B4F2D2 /* AnimeInfoView.swift */, 132417B72D131A0600B4F2D2 /* AnimeInfoExtraction.swift */, ); path = AnimeViews; sourceTree = ""; }; + 132417D32D1323F500B4F2D2 /* EpisodeCell */ = { + isa = PBXGroup; + children = ( + 132417D42D13240200B4F2D2 /* EpisodeCell.swift */, + 132417D62D13242400B4F2D2 /* CircularProgressBar.swift */, + ); + path = EpisodeCell; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -310,7 +324,7 @@ 132417BB2D131A0600B4F2D2 /* SettingsIUView.swift in Sources */, 132417C42D131A0600B4F2D2 /* AnimeInfoExtraction.swift in Sources */, 132417B82D131A0600B4F2D2 /* SearchView.swift in Sources */, - 132417A42D1319E800B4F2D2 /* PlayerView.swift in Sources */, + 132417D92D1328B900B4F2D2 /* VideoPlayerView.swift in Sources */, 1324179F2D1319E800B4F2D2 /* Notification.swift in Sources */, 132417BD2D131A0600B4F2D2 /* SettingsModuleView.swift in Sources */, 132417BC2D131A0600B4F2D2 /* SettingsLogsView.swift in Sources */, @@ -318,6 +332,7 @@ 132417862D13198000B4F2D2 /* ContentView.swift in Sources */, 132417C22D131A0600B4F2D2 /* LibraryView.swift in Sources */, 132417A32D1319E800B4F2D2 /* NormalPlayer.swift in Sources */, + 132417D72D13242400B4F2D2 /* CircularProgressBar.swift in Sources */, 132417C02D131A0600B4F2D2 /* HomeView.swift in Sources */, 132417BF2D131A0600B4F2D2 /* SettingView.swift in Sources */, 132417C32D131A0600B4F2D2 /* AnimeInfoView.swift in Sources */, @@ -328,6 +343,7 @@ 132417C12D131A0600B4F2D2 /* LibraryManager.swift in Sources */, 132417BA2D131A0600B4F2D2 /* SettingsAboutView.swift in Sources */, 1324179E2D1319E800B4F2D2 /* MiruDataStruct.swift in Sources */, + 132417D52D13240200B4F2D2 /* EpisodeCell.swift in Sources */, 132417A02D1319E800B4F2D2 /* HistoryManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sora.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate b/Sora.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate index 9a2a1a31990b6814eaed41f5b798cf3d44a96f79..b498757d7117fa360e5003b4cb1fb62635f904f9 100644 GIT binary patch delta 21296 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 f54vAH90h)5NrNRc8%;5<0MqZ}RSwT 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 diff --git a/Sora/Utils/Player/PlayerView.swift b/Sora/Utils/Player/PlayerView.swift deleted file mode 100644 index 1079c43..0000000 --- a/Sora/Utils/Player/PlayerView.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// PlayerView.swift -// Sora -// -// Created by Francesco on 18/12/24. -// - -import UIKit -import AVKit - -class VideoPlayerViewController: UIViewController { - var player: AVPlayer? - var playerViewController: AVPlayerViewController? - - var streamUrl: String? - - override func viewDidLoad() { - super.viewDidLoad() - - guard let streamUrl = streamUrl, let url = URL(string: streamUrl) else { - return - } - - player = AVPlayer(url: url) - playerViewController = AVPlayerViewController() - playerViewController?.player = player - - if let playerViewController = playerViewController { - playerViewController.view.frame = self.view.frame - self.view.addSubview(playerViewController.view) - self.addChild(playerViewController) - playerViewController.didMove(toParent: self) - } - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - player?.play() - } -} diff --git a/Sora/Utils/Player/VideoPlayerView.swift b/Sora/Utils/Player/VideoPlayerView.swift new file mode 100644 index 0000000..2dcc942 --- /dev/null +++ b/Sora/Utils/Player/VideoPlayerView.swift @@ -0,0 +1,78 @@ +// +// VideoPlayerView.swift +// Sora +// +// Created by Francesco on 18/12/24. +// + +import UIKit +import AVKit + +class VideoPlayerViewController: UIViewController { + var player: AVPlayer? + var playerViewController: AVPlayerViewController? + var timeObserverToken: Any? + var streamUrl: String? + var fullUrl: String = "" + + override func viewDidLoad() { + super.viewDidLoad() + + guard let streamUrl = streamUrl, let url = URL(string: streamUrl) else { + return + } + + player = AVPlayer(url: url) + playerViewController = AVPlayerViewController() + playerViewController?.player = player + addPeriodicTimeObserver(fullURL: fullUrl) + + if let playerViewController = playerViewController { + playerViewController.view.frame = self.view.frame + self.view.addSubview(playerViewController.view) + self.addChild(playerViewController) + playerViewController.didMove(toParent: self) + } + + let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(fullUrl)") + if lastPlayedTime > 0 { + let seekTime = CMTime(seconds: lastPlayedTime, preferredTimescale: 1) + self.player?.seek(to: seekTime) { _ in + self.player?.play() + } + } else { + self.player?.play() + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + player?.play() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + if let timeObserverToken = timeObserverToken { + player?.removeTimeObserver(timeObserverToken) + self.timeObserverToken = nil + } + } + + func addPeriodicTimeObserver(fullURL: String) { + guard let player = self.player else { return } + + let interval = CMTime(seconds: 1.0, preferredTimescale: CMTimeScale(NSEC_PER_SEC)) + timeObserverToken = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { time in + guard let currentItem = player.currentItem, + currentItem.duration.seconds.isFinite else { + return + } + + let currentTime = time.seconds + let duration = currentItem.duration.seconds + + UserDefaults.standard.set(currentTime, forKey: "lastPlayedTime_\(fullURL)") + UserDefaults.standard.set(duration, forKey: "totalTime_\(fullURL)") + } + } +} diff --git a/Sora/Views/AnimeViews/AnimeInfoView.swift b/Sora/Views/AnimeViews/AnimeInfoView.swift index 391b0de..ba0f9cf 100644 --- a/Sora/Views/AnimeViews/AnimeInfoView.swift +++ b/Sora/Views/AnimeViews/AnimeInfoView.swift @@ -7,31 +7,9 @@ import AVKit import SwiftUI -import SwiftSoup import Kingfisher import SafariServices -struct EpisodeCell: View { - let episode: String - let episodeID: Int - let imageUrl: String - - var body: some View { - HStack { - KFImage(URL(string: "https://cdn.discordapp.com/attachments/1218851049625092138/1318941731349332029/IMG_5081.png?ex=676427b5&is=6762d635&hm=923252d3448fda337f52c964f1428538095cbd018e36a6cfb21d01918e071c9d&")) - .resizable() - .aspectRatio(16/9, contentMode: .fill) - .frame(width: 100, height: 56) - .cornerRadius(8) - - VStack(alignment: .leading) { - Text("Episode \(episodeID + 1)") - .font(.headline) - } - } - } -} - struct AnimeInfoView: View { let module: ModuleStruct let anime: SearchResult @@ -44,7 +22,7 @@ struct AnimeInfoView: View { @State var isLoading: Bool = true @State var showFullSynopsis: Bool = false - @AppStorage("externalPlayer") private var externalPlayer: String = "default" + @AppStorage("externalPlayer") private var externalPlayer: String = "Default" var body: some View { VStack { @@ -152,9 +130,14 @@ struct AnimeInfoView: View { .fontWeight(.bold) ForEach(episodes.indices, id: \.self) { index in - EpisodeCell(episode: episodes[index], episodeID: index, imageUrl: anime.imageUrl) + let episodeURL = "\(module.module[0].details.baseURL)\(episodes[index])" + let lastPlayedTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(episodeURL)") + let totalTime = UserDefaults.standard.double(forKey: "totalTime_\(episodeURL)") + let progress = totalTime > 0 ? lastPlayedTime / totalTime : 0 + + EpisodeCell(episode: episodes[index], episodeID: index, imageUrl: anime.imageUrl, progress: progress) .onTapGesture { - fetchEpisodeStream(urlString: "\(module.module[0].details.baseURL)\(episodes[index])") + fetchEpisodeStream(urlString: episodeURL) } } } @@ -194,6 +177,7 @@ struct AnimeInfoView: View { DispatchQueue.main.async { let videoPlayerViewController = VideoPlayerViewController() videoPlayerViewController.streamUrl = streamUrl + videoPlayerViewController.fullUrl = fullURL videoPlayerViewController.modalPresentationStyle = .fullScreen Logger.shared.log("Opening video player with url: \(streamUrl)") diff --git a/Sora/Views/AnimeViews/EpisodeCell/CircularProgressBar.swift b/Sora/Views/AnimeViews/EpisodeCell/CircularProgressBar.swift new file mode 100644 index 0000000..7bebbc0 --- /dev/null +++ b/Sora/Views/AnimeViews/EpisodeCell/CircularProgressBar.swift @@ -0,0 +1,31 @@ +// +// CircularProgressBar.swift +// Sora +// +// Created by Francesco on 18/12/24. +// + +import SwiftUI + +struct CircularProgressBar: View { + var progress: Double + + var body: some View { + ZStack { + Circle() + .stroke(lineWidth: 5.0) + .opacity(0.3) + .foregroundColor(Color.accentColor) + + Circle() + .trim(from: 0.0, to: CGFloat(min(progress, 1.0))) + .stroke(style: StrokeStyle(lineWidth: 5.0, lineCap: .round, lineJoin: .round)) + .foregroundColor(Color.accentColor) + .rotationEffect(Angle(degrees: 270.0)) + .animation(.linear, value: progress) + + Text(String(format: "%.0f%%", min(progress, 1.0) * 100.0)) + .font(.system(size: 12)) + } + } +} diff --git a/Sora/Views/AnimeViews/EpisodeCell/EpisodeCell.swift b/Sora/Views/AnimeViews/EpisodeCell/EpisodeCell.swift new file mode 100644 index 0000000..7014090 --- /dev/null +++ b/Sora/Views/AnimeViews/EpisodeCell/EpisodeCell.swift @@ -0,0 +1,36 @@ +// +// EpisodeCell.swift +// Sora +// +// Created by Francesco on 18/12/24. +// + +import SwiftUI +import Kingfisher + +struct EpisodeCell: View { + let episode: String + let episodeID: Int + let imageUrl: String + let progress: Double + + var body: some View { + HStack { + KFImage(URL(string: "https://cdn.discordapp.com/attachments/1218851049625092138/1318941731349332029/IMG_5081.png?ex=676427b5&is=6762d635&hm=923252d3448fda337f52c964f1428538095cbd018e36a6cfb21d01918e071c9d&")) + .resizable() + .aspectRatio(16/9, contentMode: .fill) + .frame(width: 100, height: 56) + .cornerRadius(8) + + VStack(alignment: .leading) { + Text("Episode \(episodeID + 1)") + .font(.headline) + } + + Spacer() + + CircularProgressBar(progress: progress) + .frame(width: 40, height: 40) + } + } +}