mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-29 22:29:29 +02:00
Sync player session with server media progress
This commit is contained in:
parent
519969eee0
commit
5fd3f3c080
3 changed files with 51 additions and 0 deletions
|
@ -40,6 +40,7 @@ public class AbsAudioPlayer: CAPPlugin {
|
||||||
let activeSession = try Realm().objects(PlaybackSession.self).where({ $0.isActiveSession == true }).last
|
let activeSession = try Realm().objects(PlaybackSession.self).where({ $0.isActiveSession == true }).last
|
||||||
if let activeSession = activeSession {
|
if let activeSession = activeSession {
|
||||||
try self.startPlaybackSession(activeSession, playWhenReady: false)
|
try self.startPlaybackSession(activeSession, playWhenReady: false)
|
||||||
|
PlayerHandler.syncServerProgressDuringPause()
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
NSLog("Failed to restore playback session")
|
NSLog("Failed to restore playback session")
|
||||||
|
|
|
@ -11,6 +11,7 @@ import RealmSwift
|
||||||
class PlayerHandler {
|
class PlayerHandler {
|
||||||
private static var player: AudioPlayer?
|
private static var player: AudioPlayer?
|
||||||
private static var timer: Timer?
|
private static var timer: Timer?
|
||||||
|
private static var pausedTimer: Timer?
|
||||||
private static var lastSyncTime: Double = 0.0
|
private static var lastSyncTime: Double = 0.0
|
||||||
|
|
||||||
public static var sleepTimerChapterStopTime: Int? = nil
|
public static var sleepTimerChapterStopTime: Int? = nil
|
||||||
|
@ -48,6 +49,7 @@ class PlayerHandler {
|
||||||
self.player?.pause()
|
self.player?.pause()
|
||||||
} else {
|
} else {
|
||||||
self.player?.play()
|
self.player?.play()
|
||||||
|
self.pausedTimer?.invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +58,7 @@ class PlayerHandler {
|
||||||
DispatchQueue.runOnMainQueue {
|
DispatchQueue.runOnMainQueue {
|
||||||
NSLog("Starting the tick timer")
|
NSLog("Starting the tick timer")
|
||||||
timer?.invalidate()
|
timer?.invalidate()
|
||||||
|
pausedTimer?.invalidate()
|
||||||
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
|
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
|
||||||
self.tick()
|
self.tick()
|
||||||
}
|
}
|
||||||
|
@ -65,9 +68,16 @@ class PlayerHandler {
|
||||||
public static func stopTickTimer() {
|
public static func stopTickTimer() {
|
||||||
NSLog("Stopping the tick timer")
|
NSLog("Stopping the tick timer")
|
||||||
timer?.invalidate()
|
timer?.invalidate()
|
||||||
|
pausedTimer?.invalidate()
|
||||||
timer = nil
|
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?) {
|
private static func cleanupOldSessions(currentSessionId: String?) {
|
||||||
let realm = try! Realm()
|
let realm = try! Realm()
|
||||||
let oldSessions = realm.objects(PlaybackSession.self) .where({ $0.isActiveSession == true })
|
let oldSessions = realm.objects(PlaybackSession.self) .where({ $0.isActiveSession == true })
|
||||||
|
@ -99,6 +109,7 @@ class PlayerHandler {
|
||||||
player = AudioPlayer(sessionId: sessionId, playWhenReady: playWhenReady, playbackRate: playbackRate)
|
player = AudioPlayer(sessionId: sessionId, playWhenReady: playWhenReady, playbackRate: playbackRate)
|
||||||
|
|
||||||
startTickTimer()
|
startTickTimer()
|
||||||
|
startPausedTimer()
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func stopPlayback() {
|
public static func stopPlayback() {
|
||||||
|
@ -204,6 +215,8 @@ class PlayerHandler {
|
||||||
guard player.isInitialized() else { return }
|
guard player.isInitialized() else { return }
|
||||||
guard let session = getPlaybackSession() else { return }
|
guard let session = getPlaybackSession() else { return }
|
||||||
|
|
||||||
|
NSLog("Syncing player progress")
|
||||||
|
|
||||||
// Get current time
|
// Get current time
|
||||||
let playerCurrentTime = player.getCurrentTime()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
public static func getLibraryItemWithProgress(libraryItemId:String, episodeId:String?, callback: @escaping (_ param: LibraryItem?) -> Void) {
|
||||||
var endpoint = "api/items/\(libraryItemId)?expanded=1&include=progress"
|
var endpoint = "api/items/\(libraryItemId)?expanded=1&include=progress"
|
||||||
if episodeId != nil {
|
if episodeId != nil {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue