diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift b/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift index c6e71b1..44a7eb8 100644 --- a/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift +++ b/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift @@ -920,6 +920,20 @@ class CustomMediaPlayerViewController: UIViewController { } DispatchQueue.main.async { + let remainingPercentage = (self.duration - self.currentTimeVal) / self.duration + + if remainingPercentage < 0.1 && self.module.metadata.type == "anime" && self.aniListID != 0 { + let aniListMutation = AniListMutation() + aniListMutation.updateAnimeProgress(animeId: self.aniListID, episodeNumber: self.episodeNumber) { result in + switch result { + case .success: + Logger.shared.log("Successfully updated AniList progress for episode \(self.episodeNumber)", type: "General") + case .failure(let error): + Logger.shared.log("Failed to update AniList progress: \(error.localizedDescription)", type: "Error") + } + } + } + self.sliderHostingController?.rootView = MusicProgressSlider( value: Binding( get: { max(0, min(self.sliderViewModel.sliderValue, self.duration)) }, @@ -1623,7 +1637,7 @@ class CustomMediaPlayerViewController: UIViewController { func setupTimeControlStatusObservation() { playerTimeControlStatusObserver = player.observe(\.timeControlStatus, options: [.new]) { [weak self] player, _ in - guard let self = self else { return } + guard self != nil else { return } if player.timeControlStatus == .paused, let reason = player.reasonForWaitingToPlay { // If we are paused for a “stall/minimize stalls” reason, forcibly resume: diff --git a/Sora/Utils/MediaPlayer/VideoPlayer.swift b/Sora/Utils/MediaPlayer/VideoPlayer.swift index 1f001c3..e26f29a 100644 --- a/Sora/Utils/MediaPlayer/VideoPlayer.swift +++ b/Sora/Utils/MediaPlayer/VideoPlayer.swift @@ -101,8 +101,9 @@ class VideoPlayerViewController: UIViewController { 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, + timeObserverToken = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in + guard let self = self, + let currentItem = player.currentItem, currentItem.duration.seconds.isFinite else { return } @@ -112,26 +113,37 @@ class VideoPlayerViewController: UIViewController { UserDefaults.standard.set(currentTime, forKey: "lastPlayedTime_\(fullURL)") UserDefaults.standard.set(duration, forKey: "totalTime_\(fullURL)") - } - - if let currentItem = player.currentItem, currentItem.duration.seconds > 0, - let streamUrl = streamUrl { - let currentTime = UserDefaults.standard.double(forKey: "lastPlayedTime_\(fullUrl)") - let duration = currentItem.duration.seconds - let progress = currentTime / duration - let item = ContinueWatchingItem( - id: UUID(), - imageUrl: episodeImageUrl, - episodeNumber: episodeNumber, - mediaTitle: mediaTitle, - progress: progress, - streamUrl: streamUrl, - fullUrl: fullUrl, - subtitles: subtitles, - aniListID: aniListID, - module: module - ) - ContinueWatchingManager.shared.save(item: item) + + let remainingPercentage = (duration - currentTime) / duration + + if remainingPercentage < 0.1 && self.module.metadata.type == "anime" && self.aniListID != 0 { + let aniListMutation = AniListMutation() + aniListMutation.updateAnimeProgress(animeId: self.aniListID, episodeNumber: self.episodeNumber) { result in + switch result { + case .success: + Logger.shared.log("Successfully updated AniList progress for episode \(self.episodeNumber)", type: "General") + case .failure(let error): + Logger.shared.log("Failed to update AniList progress: \(error.localizedDescription)", type: "Error") + } + } + } + + if let streamUrl = self.streamUrl { + let progress = currentTime / duration + let item = ContinueWatchingItem( + id: UUID(), + imageUrl: self.episodeImageUrl, + episodeNumber: self.episodeNumber, + mediaTitle: self.mediaTitle, + progress: progress, + streamUrl: streamUrl, + fullUrl: self.fullUrl, + subtitles: self.subtitles, + aniListID: self.aniListID, + module: self.module + ) + ContinueWatchingManager.shared.save(item: item) + } } } diff --git a/Sora/Views/LibraryView/LibraryView.swift b/Sora/Views/LibraryView/LibraryView.swift index 9dc269b..0048c41 100644 --- a/Sora/Views/LibraryView/LibraryView.swift +++ b/Sora/Views/LibraryView/LibraryView.swift @@ -233,6 +233,7 @@ struct ContinueWatchingCell: View { videoPlayerViewController.episodeNumber = item.episodeNumber videoPlayerViewController.mediaTitle = item.mediaTitle videoPlayerViewController.subtitles = item.subtitles ?? "" + videoPlayerViewController.aniListID = item.aniListID ?? 0 videoPlayerViewController.modalPresentationStyle = .fullScreen if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, diff --git a/Sora/Views/MediaInfoView/MediaInfoView.swift b/Sora/Views/MediaInfoView/MediaInfoView.swift index 2c1788a..6d0ee74 100644 --- a/Sora/Views/MediaInfoView/MediaInfoView.swift +++ b/Sora/Views/MediaInfoView/MediaInfoView.swift @@ -694,6 +694,7 @@ struct MediaInfoView: View { videoPlayerViewController.episodeImageUrl = selectedEpisodeImage videoPlayerViewController.mediaTitle = title videoPlayerViewController.subtitles = subtitles ?? "" + videoPlayerViewController.aniListID = itemID ?? 0 videoPlayerViewController.modalPresentationStyle = .fullScreen if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, diff --git a/Sulfur.xcodeproj/project.pbxproj b/Sulfur.xcodeproj/project.pbxproj index d21e31e..a2d7091 100644 --- a/Sulfur.xcodeproj/project.pbxproj +++ b/Sulfur.xcodeproj/project.pbxproj @@ -45,7 +45,6 @@ 13B7F4C12D58FFDD0045714A /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13B7F4C02D58FFDD0045714A /* Shimmer.swift */; }; 13C0E5EA2D5F85EA00E7F619 /* ContinueWatchingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C0E5E92D5F85EA00E7F619 /* ContinueWatchingManager.swift */; }; 13C0E5EC2D5F85F800E7F619 /* ContinueWatchingItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13C0E5EB2D5F85F800E7F619 /* ContinueWatchingItem.swift */; }; - 13C285F62DA56B6F009FB0D0 /* SlideOverCard in Frameworks */ = {isa = PBXBuildFile; productRef = 13C285F52DA56B6F009FB0D0 /* SlideOverCard */; }; 13CBA0882D60F19C00EFE70A /* VTTSubtitlesLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CBA0872D60F19C00EFE70A /* VTTSubtitlesLoader.swift */; }; 13CBEFDA2D5F7D1200D011EE /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13CBEFD92D5F7D1200D011EE /* String.swift */; }; 13D842552D45267500EBBFA6 /* DropManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13D842542D45267500EBBFA6 /* DropManager.swift */; }; @@ -129,7 +128,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 13C285F62DA56B6F009FB0D0 /* SlideOverCard in Frameworks */, 13B77E192DA44F8300126FDF /* MarqueeLabel in Frameworks */, 132E35232D959E410007800E /* Kingfisher in Frameworks */, 132E35202D959E1D0007800E /* FFmpeg-iOS-Lame in Frameworks */, @@ -438,7 +436,6 @@ 132E351F2D959E1D0007800E /* FFmpeg-iOS-Lame */, 132E35222D959E410007800E /* Kingfisher */, 13B77E182DA44F8300126FDF /* MarqueeLabel */, - 13C285F52DA56B6F009FB0D0 /* SlideOverCard */, ); productName = Sora; productReference = 133D7C6A2D2BE2500075467E /* Sulfur.app */; @@ -472,7 +469,6 @@ 132E351E2D959E1D0007800E /* XCRemoteSwiftPackageReference "FFmpeg-iOS-Lame" */, 132E35212D959E410007800E /* XCRemoteSwiftPackageReference "Kingfisher" */, 13B77E172DA44F8300126FDF /* XCRemoteSwiftPackageReference "MarqueeLabel" */, - 13C285F42DA56B6F009FB0D0 /* XCRemoteSwiftPackageReference "SlideOverCard" */, ); productRefGroup = 133D7C6B2D2BE2500075467E /* Products */; projectDirPath = ""; @@ -816,14 +812,6 @@ version = 4.2.1; }; }; - 13C285F42DA56B6F009FB0D0 /* XCRemoteSwiftPackageReference "SlideOverCard" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/joogps/SlideOverCard"; - requirement = { - kind = exactVersion; - version = 3.0.1; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -847,11 +835,6 @@ package = 13B77E172DA44F8300126FDF /* XCRemoteSwiftPackageReference "MarqueeLabel" */; productName = MarqueeLabel; }; - 13C285F52DA56B6F009FB0D0 /* SlideOverCard */ = { - isa = XCSwiftPackageProductDependency; - package = 13C285F42DA56B6F009FB0D0 /* XCRemoteSwiftPackageReference "SlideOverCard" */; - productName = SlideOverCard; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 133D7C622D2BE2500075467E /* Project object */; diff --git a/Sulfur.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Sulfur.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2754ca7..5fe78fe 100644 --- a/Sulfur.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Sulfur.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -45,15 +45,6 @@ "revision": "cffb6938940d3242882e6a2f9170b7890a4729ea", "version": "4.2.1" } - }, - { - "package": "SlideOverCard", - "repositoryURL": "https://github.com/joogps/SlideOverCard", - "state": { - "branch": null, - "revision": "e38be074ab7a5b46d0a18f550bf94972a0f582c6", - "version": "3.0.1" - } } ] },