diff --git a/ios/App/App/plugins/AbsAudioPlayer.swift b/ios/App/App/plugins/AbsAudioPlayer.swift index 760bb4af..e9d173d4 100644 --- a/ios/App/App/plugins/AbsAudioPlayer.swift +++ b/ios/App/App/plugins/AbsAudioPlayer.swift @@ -40,6 +40,7 @@ public class AbsAudioPlayer: CAPPlugin { let activeSession = try Realm().objects(PlaybackSession.self).where({ $0.isActiveSession == true }).last if let activeSession = activeSession { try self.startPlaybackSession(activeSession, playWhenReady: false) + PlayerHandler.syncServerProgressDuringPause() } } catch { NSLog("Failed to restore playback session") diff --git a/ios/App/Shared/player/PlayerHandler.swift b/ios/App/Shared/player/PlayerHandler.swift index e979e1f7..9486b66e 100644 --- a/ios/App/Shared/player/PlayerHandler.swift +++ b/ios/App/Shared/player/PlayerHandler.swift @@ -11,6 +11,7 @@ import RealmSwift class PlayerHandler { private static var player: AudioPlayer? private static var timer: Timer? + private static var pausedTimer: Timer? private static var lastSyncTime: Double = 0.0 public static var sleepTimerChapterStopTime: Int? = nil @@ -48,6 +49,7 @@ class PlayerHandler { self.player?.pause() } else { self.player?.play() + self.pausedTimer?.invalidate() } } } @@ -56,6 +58,7 @@ class PlayerHandler { DispatchQueue.runOnMainQueue { NSLog("Starting the tick timer") timer?.invalidate() + pausedTimer?.invalidate() timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.tick() } @@ -65,9 +68,16 @@ class PlayerHandler { public static func stopTickTimer() { NSLog("Stopping the tick timer") timer?.invalidate() + pausedTimer?.invalidate() timer = nil } + private static func startPausedTimer() { + guard self.paused else { return } + self.pausedTimer?.invalidate() + self.pausedTimer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(syncServerProgressDuringPause), userInfo: nil, repeats: true) + } + private static func cleanupOldSessions(currentSessionId: String?) { let realm = try! Realm() let oldSessions = realm.objects(PlaybackSession.self) .where({ $0.isActiveSession == true }) @@ -99,6 +109,7 @@ class PlayerHandler { player = AudioPlayer(sessionId: sessionId, playWhenReady: playWhenReady, playbackRate: playbackRate) startTickTimer() + startPausedTimer() } public static func stopPlayback() { @@ -204,6 +215,8 @@ class PlayerHandler { guard player.isInitialized() else { return } guard let session = getPlaybackSession() else { return } + NSLog("Syncing player progress") + // Get current time let playerCurrentTime = player.getCurrentTime() @@ -283,4 +296,33 @@ class PlayerHandler { } } } + + @objc public static func syncServerProgressDuringPause() { + guard Connectivity.isConnectedToInternet else { return } + DispatchQueue.global(qos: .utility).async { + NSLog("checkCurrentSessionProgress: Checking if local media progress was updated on server") + guard let session = getPlaybackSession() else { return } + let sessionRef = ThreadSafeReference(to: session) + + ApiClient.getMediaProgress(libraryItemId: session.libraryItemId!, episodeId: session.episodeId) { progress in + guard let session = try! Realm().resolve(sessionRef) else { return } + guard let progress = progress else { return } + + let serverLastUpdate = progress.lastUpdate + guard let localLastUpdate = session.updatedAt else { return } + let serverCurrentTime = progress.currentTime + let localCurrentTime = session.currentTime + + let serverIsNewerThanLocal = serverLastUpdate > localLastUpdate + let currentTimeIsDifferent = serverCurrentTime != localCurrentTime + + if serverIsNewerThanLocal && currentTimeIsDifferent { + session.update { + session.currentTime = serverCurrentTime + } + self.seek(amount: session.currentTime) + } + } + } + } } diff --git a/ios/App/Shared/util/ApiClient.swift b/ios/App/Shared/util/ApiClient.swift index 5af89085..143a5f78 100644 --- a/ios/App/Shared/util/ApiClient.swift +++ b/ios/App/Shared/util/ApiClient.swift @@ -205,6 +205,14 @@ class ApiClient { } } + public static func getMediaProgress(libraryItemId: String, episodeId: String?, callback: @escaping (_ progress: MediaProgress?) -> Void) { + NSLog("getMediaProgress \(libraryItemId) \(episodeId ?? "NIL")") + let endpoint = episodeId?.isEmpty ?? true ? "api/me/progress/\(libraryItemId)" : "api/me/progress/\(libraryItemId)/\(episodeId ?? "")" + getResource(endpoint: endpoint, decodable: MediaProgress.self) { obj in + callback(obj) + } + } + public static func getLibraryItemWithProgress(libraryItemId:String, episodeId:String?, callback: @escaping (_ param: LibraryItem?) -> Void) { var endpoint = "api/items/\(libraryItemId)?expanded=1&include=progress" if episodeId != nil {