diff --git a/ios/App/App/plugins/AbsAudioPlayer.m b/ios/App/App/plugins/AbsAudioPlayer.m index 2bb2c0c2..7e97d4ae 100644 --- a/ios/App/App/plugins/AbsAudioPlayer.m +++ b/ios/App/App/plugins/AbsAudioPlayer.m @@ -23,4 +23,10 @@ CAP_PLUGIN(AbsAudioPlayer, "AbsAudioPlayer", CAP_PLUGIN_METHOD(seekBackward, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(getCurrentTime, CAPPluginReturnPromise); + + CAP_PLUGIN_METHOD(cancelSleepTimer, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(decreaseSleepTime, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(increaseSleepTime, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getSleepTimerTime, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(setSleepTimer, CAPPluginReturnPromise); ) diff --git a/ios/App/App/plugins/AbsAudioPlayer.swift b/ios/App/App/plugins/AbsAudioPlayer.swift index 51c1f7a3..3cc31218 100644 --- a/ios/App/App/plugins/AbsAudioPlayer.swift +++ b/ios/App/App/plugins/AbsAudioPlayer.swift @@ -13,9 +13,12 @@ public class AbsAudioPlayer: CAPPlugin { override public func load() { NotificationCenter.default.addObserver(self, selector: #selector(sendMetadata), name: NSNotification.Name(PlayerEvents.update.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(sendPlaybackClosedEvent), name: NSNotification.Name(PlayerEvents.closed.rawValue), object: nil) - self.bridge?.webView?.allowsBackForwardNavigationGestures = true; NotificationCenter.default.addObserver(self, selector: #selector(sendMetadata), name: UIApplication.didBecomeActiveNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(sendMetadata), name: UIApplication.willEnterForegroundNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(sendSleepTimerSet), name: NSNotification.Name(PlayerEvents.sleepSet.rawValue), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(sendSleepTimerEnded), name: NSNotification.Name(PlayerEvents.sleepEnded.rawValue), object: nil) + + self.bridge?.webView?.allowsBackForwardNavigationGestures = true; } @objc func prepareLibraryItem(_ call: CAPPluginCall) { @@ -69,15 +72,15 @@ public class AbsAudioPlayer: CAPPlugin { } @objc func playPause(_ call: CAPPluginCall) { - PlayerHandler.playPause() - call.resolve([ "playing": !PlayerHandler.paused() ]) + PlayerHandler.paused = !PlayerHandler.paused + call.resolve([ "playing": !PlayerHandler.paused ]) } @objc func playPlayer(_ call: CAPPluginCall) { - PlayerHandler.play() + PlayerHandler.paused = false call.resolve() } @objc func pausePlayer(_ call: CAPPluginCall) { - PlayerHandler.pause() + PlayerHandler.paused = true call.resolve() } @@ -95,13 +98,69 @@ public class AbsAudioPlayer: CAPPlugin { } @objc func sendMetadata() { - self.notifyListeners("onPlayingUpdate", data: [ "value": !PlayerHandler.paused() ]) + self.notifyListeners("onPlayingUpdate", data: [ "value": !PlayerHandler.paused ]) self.notifyListeners("onMetadata", data: PlayerHandler.getMetdata()) } @objc func sendPlaybackClosedEvent() { self.notifyListeners("onPlaybackClosed", data: [ "value": true ]) } + @objc func decreaseSleepTime(_ call: CAPPluginCall) { + guard let timeString = call.getString("time") else { return call.resolve([ "success": false ]) } + guard let time = Int(timeString) else { return call.resolve([ "success": false ]) } + guard let currentSleepTime = PlayerHandler.remainingSleepTime else { return call.resolve([ "success": false ]) } + + PlayerHandler.remainingSleepTime = currentSleepTime - time + call.resolve() + } + @objc func increaseSleepTime(_ call: CAPPluginCall) { + guard let timeString = call.getString("time") else { return call.resolve([ "success": false ]) } + guard let time = Int(timeString) else { return call.resolve([ "success": false ]) } + guard let currentSleepTime = PlayerHandler.remainingSleepTime else { return call.resolve([ "success": false ]) } + + PlayerHandler.remainingSleepTime = currentSleepTime + time + call.resolve() + } + @objc func setSleepTimer(_ call: CAPPluginCall) { + guard let timeString = call.getString("time") else { return call.resolve([ "success": false ]) } + guard let time = Int(timeString) else { return call.resolve([ "success": false ]) } + + NSLog("chapter time: \(call.getBool("isChapterTime", false))") + + if call.getBool("isChapterTime", false) { + let timeToPause = time / 1000 - Int(PlayerHandler.getCurrentTime() ?? 0) + if timeToPause < 0 { return call.resolve([ "success": false ]) } + + NSLog("oof \(timeToPause)") + + PlayerHandler.remainingSleepTime = timeToPause + return call.resolve([ "success": true ]) + } + + PlayerHandler.remainingSleepTime = time / 1000 + call.resolve([ "success": true ]) + } + @objc func cancelSleepTimer(_ call: CAPPluginCall) { + PlayerHandler.remainingSleepTime = nil + call.resolve() + } + @objc func getSleepTimerTime(_ call: CAPPluginCall) { + call.resolve([ + "value": PlayerHandler.remainingSleepTime + ]) + } + + @objc func sendSleepTimerEnded() { + self.notifyListeners("onSleepTimerEnded", data: [ + "value": PlayerHandler.getCurrentTime() + ]) + } + @objc func sendSleepTimerSet() { + self.notifyListeners("onSleepTimerSet", data: [ + "value": PlayerHandler.remainingSleepTime + ]) + } + @objc func sendPrepareMetadataEvent(itemId: String, playWhenReady: Bool) { self.notifyListeners("onPrepareMedia", data: [ "audiobookId": itemId, @@ -115,11 +174,11 @@ public class AbsAudioPlayer: CAPPlugin { /* IMPLEMENTED: - cancelSleepTimer - decreaseSleepTime - increaseSleepTime - getSleepTimerTime - setSleepTimer + * cancelSleepTimer + decreaseSleepTime (millis) + increaseSleepTime (millis) + * getSleepTimerTime (millis) + * setSleepTimer (millis) * closePlayback * setPlaybackSpeed * seekBackward @@ -136,7 +195,7 @@ public class AbsAudioPlayer: CAPPlugin { * onPlaybackClosed * onPlayingUpdate * onMetadata - onSleepTimerEnded - onSleepTimerSet + onSleepTimerEnded (millis) + onSleepTimerSet (millis) */ } diff --git a/ios/App/Shared/player/PlayerHandler.swift b/ios/App/Shared/player/PlayerHandler.swift index b7554139..5cb05a43 100644 --- a/ios/App/Shared/player/PlayerHandler.swift +++ b/ios/App/Shared/player/PlayerHandler.swift @@ -12,7 +12,39 @@ class PlayerHandler { private static var session: PlaybackSession? private static var timer: Timer? - private static var listeningTimePassedSinceLastSync = 0.0 + private static var _remainingSleepTime: Int? = nil + public static var remainingSleepTime: Int? { + get { + return _remainingSleepTime + } + set(time) { + if time != nil && time! < 0 { + _remainingSleepTime = nil + } else { + _remainingSleepTime = time + } + + if _remainingSleepTime == nil { + NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.sleepEnded.rawValue), object: _remainingSleepTime) + } else { + NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.sleepSet.rawValue), object: _remainingSleepTime) + } + } + } + private static var listeningTimePassedSinceLastSync: Double = 0.0 + + public static var paused: Bool { + get { + return player?.rate == 0.0 + } + set(paused) { + if paused { + self.player?.pause() + } else { + self.player?.play() + } + } + } public static func startPlayback(session: PlaybackSession, playWhenReady: Bool, playbackRate: Float) { if player != nil { @@ -48,20 +80,6 @@ class PlayerHandler { self.player?.setPlaybackRate(speed) } - public static func play() { - self.player?.play() - } - public static func pause() { - self.player?.play() - } - public static func playPause() { - if paused() { - self.player?.play() - } else { - self.player?.pause() - } - } - public static func seekForward(amount: Double) { guard let player = player else { return @@ -81,11 +99,6 @@ class PlayerHandler { public static func seek(amount: Double) { player?.seek(amount) } - - public static func paused() -> Bool { - player?.rate == 0.0 - } - public static func getMetdata() -> [String: Any] { DispatchQueue.main.async { syncProgress() @@ -94,27 +107,30 @@ class PlayerHandler { return [ "duration": player?.getDuration() ?? 0, "currentTime": player?.getCurrentTime() ?? 0, - "playerState": !paused(), + "playerState": !paused, "currentRate": player?.rate ?? 0, ] } private static func tick() { - if !paused() { + if !paused { listeningTimePassedSinceLastSync += 1 } if listeningTimePassedSinceLastSync > 3 { syncProgress() } + + if remainingSleepTime != nil { + if remainingSleepTime! == 0 { + paused = true + } + remainingSleepTime! -= 1 + } } public static func syncProgress() { - if session == nil { - return - } - guard let player = player else { - return - } + if session == nil { return } + guard let player = player else { return } let report = PlaybackReport(currentTime: player.getCurrentTime(), duration: player.getDuration(), timeListened: listeningTimePassedSinceLastSync) diff --git a/ios/App/Shared/util/PlayerEvents.swift b/ios/App/Shared/util/PlayerEvents.swift index 5c794e92..8c04c098 100644 --- a/ios/App/Shared/util/PlayerEvents.swift +++ b/ios/App/Shared/util/PlayerEvents.swift @@ -10,4 +10,6 @@ import Foundation enum PlayerEvents: String { case update = "com.audiobookshelf.app.player.update" case closed = "com.audiobookshelf.app.player.closed" + case sleepSet = "com.audiobookshelf.app.player.sleep.set" + case sleepEnded = "com.audiobookshelf.app.player.sleep.ended" }