mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-09-01 07:30:00 +02:00
Fix:Check with server after pause of 1 minute or longer for updated media progress & show toast on client if progress sync is failing
This commit is contained in:
parent
2decf532b2
commit
480df58ce4
8 changed files with 177 additions and 26 deletions
|
@ -62,6 +62,8 @@ class PlaybackSession(
|
||||||
val localMediaProgressId get() = if (episodeId.isNullOrEmpty()) localLibraryItemId else "$localLibraryItemId-$localEpisodeId"
|
val localMediaProgressId get() = if (episodeId.isNullOrEmpty()) localLibraryItemId else "$localLibraryItemId-$localEpisodeId"
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val progress get() = currentTime / getTotalDuration()
|
val progress get() = currentTime / getTotalDuration()
|
||||||
|
@get:JsonIgnore
|
||||||
|
val isLocalLibraryItemOnly get() = localLibraryItemId != "" && libraryItemId == null
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
fun getCurrentTrackIndex():Int {
|
fun getCurrentTrackIndex():Int {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.audiobookshelf.app.data.LocalMediaProgress
|
import com.audiobookshelf.app.data.LocalMediaProgress
|
||||||
|
import com.audiobookshelf.app.data.MediaProgress
|
||||||
import com.audiobookshelf.app.data.PlaybackSession
|
import com.audiobookshelf.app.data.PlaybackSession
|
||||||
import com.audiobookshelf.app.device.DeviceManager
|
import com.audiobookshelf.app.device.DeviceManager
|
||||||
import com.audiobookshelf.app.server.ApiHandler
|
import com.audiobookshelf.app.server.ApiHandler
|
||||||
|
@ -24,6 +25,7 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
||||||
var listeningTimerRunning:Boolean = false
|
var listeningTimerRunning:Boolean = false
|
||||||
|
|
||||||
private var lastSyncTime:Long = 0
|
private var lastSyncTime:Long = 0
|
||||||
|
private var failedSyncs:Int = 0
|
||||||
|
|
||||||
var currentPlaybackSession: PlaybackSession? = null // copy of pb session currently syncing
|
var currentPlaybackSession: PlaybackSession? = null // copy of pb session currently syncing
|
||||||
var currentLocalMediaProgress: LocalMediaProgress? = null
|
var currentLocalMediaProgress: LocalMediaProgress? = null
|
||||||
|
@ -41,6 +43,7 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
||||||
currentLocalMediaProgress = null
|
currentLocalMediaProgress = null
|
||||||
listeningTimerTask?.cancel()
|
listeningTimerTask?.cancel()
|
||||||
lastSyncTime = 0L
|
lastSyncTime = 0L
|
||||||
|
failedSyncs = 0
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -68,6 +71,16 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
||||||
reset()
|
reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun syncFromServerProgress(mediaProgress: MediaProgress) {
|
||||||
|
currentPlaybackSession?.let {
|
||||||
|
it.updatedAt = mediaProgress.lastUpdate
|
||||||
|
it.currentTime = mediaProgress.currentTime
|
||||||
|
|
||||||
|
DeviceManager.dbManager.saveLocalPlaybackSession(it)
|
||||||
|
saveLocalProgress(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun sync(currentTime:Double) {
|
fun sync(currentTime:Double) {
|
||||||
val diffSinceLastSync = System.currentTimeMillis() - lastSyncTime
|
val diffSinceLastSync = System.currentTimeMillis() - lastSyncTime
|
||||||
if (diffSinceLastSync < 1000L) {
|
if (diffSinceLastSync < 1000L) {
|
||||||
|
@ -100,7 +113,17 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
apiHandler.sendProgressSync(currentSessionId, syncData) {
|
apiHandler.sendProgressSync(currentSessionId, syncData) {
|
||||||
Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime")
|
if (it) {
|
||||||
|
Log.d(tag, "Progress sync data sent to server $currentDisplayTitle for time $currentTime")
|
||||||
|
failedSyncs = 0
|
||||||
|
} else {
|
||||||
|
failedSyncs++
|
||||||
|
if (failedSyncs == 2) {
|
||||||
|
playerNotificationService.alertSyncFailing() // Show alert in client
|
||||||
|
failedSyncs = 0
|
||||||
|
}
|
||||||
|
Log.d(tag, "Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,5 +153,6 @@ class MediaProgressSyncer(val playerNotificationService:PlayerNotificationServic
|
||||||
currentPlaybackSession = null
|
currentPlaybackSession = null
|
||||||
currentLocalMediaProgress = null
|
currentLocalMediaProgress = null
|
||||||
lastSyncTime = 0L
|
lastSyncTime = 0L
|
||||||
|
failedSyncs = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,8 @@ import android.os.Message
|
||||||
import android.support.v4.media.session.MediaSessionCompat
|
import android.support.v4.media.session.MediaSessionCompat
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import com.audiobookshelf.app.data.LibraryItem
|
|
||||||
import com.audiobookshelf.app.data.LibraryItemWrapper
|
import com.audiobookshelf.app.data.LibraryItemWrapper
|
||||||
import com.audiobookshelf.app.data.PodcastEpisode
|
import com.audiobookshelf.app.data.PodcastEpisode
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.concurrent.schedule
|
import kotlin.concurrent.schedule
|
||||||
|
|
||||||
|
@ -119,10 +115,13 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
|
||||||
|
|
||||||
fun handleCallMediaButton(intent: Intent): Boolean {
|
fun handleCallMediaButton(intent: Intent): Boolean {
|
||||||
if(Intent.ACTION_MEDIA_BUTTON == intent.action) {
|
if(Intent.ACTION_MEDIA_BUTTON == intent.action) {
|
||||||
var keyEvent = intent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
|
val keyEvent = intent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)
|
||||||
if (keyEvent?.getAction() == KeyEvent.ACTION_UP) {
|
|
||||||
when (keyEvent?.getKeyCode()) {
|
if (keyEvent?.action == KeyEvent.ACTION_UP) {
|
||||||
|
Log.d(tag, "handleCallMediaButton: key action_up for ${keyEvent.keyCode}")
|
||||||
|
when (keyEvent.keyCode) {
|
||||||
KeyEvent.KEYCODE_HEADSETHOOK -> {
|
KeyEvent.KEYCODE_HEADSETHOOK -> {
|
||||||
|
Log.d(tag, "handleCallMediaButton: Headset Hook")
|
||||||
if (0 == mediaButtonClickCount) {
|
if (0 == mediaButtonClickCount) {
|
||||||
if (playerNotificationService.mPlayer.isPlaying)
|
if (playerNotificationService.mPlayer.isPlaying)
|
||||||
playerNotificationService.pause()
|
playerNotificationService.pause()
|
||||||
|
@ -132,6 +131,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
}
|
}
|
||||||
KeyEvent.KEYCODE_MEDIA_PLAY -> {
|
KeyEvent.KEYCODE_MEDIA_PLAY -> {
|
||||||
|
Log.d(tag, "handleCallMediaButton: Media Play")
|
||||||
if (0 == mediaButtonClickCount) {
|
if (0 == mediaButtonClickCount) {
|
||||||
playerNotificationService.play()
|
playerNotificationService.play()
|
||||||
playerNotificationService.sleepTimerManager.checkShouldExtendSleepTimer()
|
playerNotificationService.sleepTimerManager.checkShouldExtendSleepTimer()
|
||||||
|
@ -139,6 +139,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
}
|
}
|
||||||
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
|
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
|
||||||
|
Log.d(tag, "handleCallMediaButton: Media Pause")
|
||||||
if (0 == mediaButtonClickCount) playerNotificationService.pause()
|
if (0 == mediaButtonClickCount) playerNotificationService.pause()
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
}
|
}
|
||||||
|
@ -152,6 +153,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
|
||||||
playerNotificationService.closePlayback()
|
playerNotificationService.closePlayback()
|
||||||
}
|
}
|
||||||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
|
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
|
||||||
|
Log.d(tag, "handleCallMediaButton: Media Play/Pause")
|
||||||
if (playerNotificationService.mPlayer.isPlaying) {
|
if (playerNotificationService.mPlayer.isPlaying) {
|
||||||
if (0 == mediaButtonClickCount) playerNotificationService.pause()
|
if (0 == mediaButtonClickCount) playerNotificationService.pause()
|
||||||
handleMediaButtonClickCount()
|
handleMediaButtonClickCount()
|
||||||
|
@ -164,7 +166,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
Log.d(tag, "KeyCode:${keyEvent.getKeyCode()}")
|
Log.d(tag, "KeyCode:${keyEvent.keyCode}")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,7 +175,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleMediaButtonClickCount() {
|
private fun handleMediaButtonClickCount() {
|
||||||
mediaButtonClickCount++
|
mediaButtonClickCount++
|
||||||
if (1 == mediaButtonClickCount) {
|
if (1 == mediaButtonClickCount) {
|
||||||
Timer().schedule(mediaButtonClickTimeout) {
|
Timer().schedule(mediaButtonClickTimeout) {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import com.audiobookshelf.app.data.PlayerState
|
||||||
import com.google.android.exoplayer2.PlaybackException
|
import com.google.android.exoplayer2.PlaybackException
|
||||||
import com.google.android.exoplayer2.Player
|
import com.google.android.exoplayer2.Player
|
||||||
|
|
||||||
|
const val PAUSE_LEN_BEFORE_RECHECK = 60000 // 1 minute
|
||||||
|
|
||||||
class PlayerListener(var playerNotificationService:PlayerNotificationService) : Player.Listener {
|
class PlayerListener(var playerNotificationService:PlayerNotificationService) : Player.Listener {
|
||||||
var tag = "PlayerListener"
|
var tag = "PlayerListener"
|
||||||
|
|
||||||
|
@ -81,6 +83,12 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) :
|
||||||
Log.d(tag, "SeekBackTime: back time is 0")
|
Log.d(tag, "SeekBackTime: back time is 0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if playback session still exists or sync media progress if updated
|
||||||
|
if (lastPauseTime > PAUSE_LEN_BEFORE_RECHECK) {
|
||||||
|
val shouldCarryOn = playerNotificationService.checkCurrentSessionProgress()
|
||||||
|
if (!shouldCarryOn) return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.d(tag, "SeekBackTime: Player not playing set last pause time")
|
Log.d(tag, "SeekBackTime: Player not playing set last pause time")
|
||||||
|
@ -102,8 +110,8 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) :
|
||||||
|
|
||||||
private fun calcPauseSeekBackTime() : Long {
|
private fun calcPauseSeekBackTime() : Long {
|
||||||
if (lastPauseTime <= 0) return 0
|
if (lastPauseTime <= 0) return 0
|
||||||
var time: Long = System.currentTimeMillis() - lastPauseTime
|
val time: Long = System.currentTimeMillis() - lastPauseTime
|
||||||
var seekback: Long
|
val seekback: Long
|
||||||
if (time < 3000) seekback = 0
|
if (time < 3000) seekback = 0
|
||||||
else if (time < 300000) seekback = 10000 // 3s to 5m = jump back 10s
|
else if (time < 300000) seekback = 10000 // 3s to 5m = jump back 10s
|
||||||
else if (time < 1800000) seekback = 20000 // 5m to 30m = jump back 20s
|
else if (time < 1800000) seekback = 20000 // 5m to 30m = jump back 20s
|
||||||
|
|
|
@ -48,12 +48,12 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
fun onPlaybackClosed()
|
fun onPlaybackClosed()
|
||||||
fun onPlayingUpdate(isPlaying: Boolean)
|
fun onPlayingUpdate(isPlaying: Boolean)
|
||||||
fun onMetadata(metadata: PlaybackMetadata)
|
fun onMetadata(metadata: PlaybackMetadata)
|
||||||
fun onPrepare(audiobookId: String, playWhenReady: Boolean)
|
|
||||||
fun onSleepTimerEnded(currentPosition: Long)
|
fun onSleepTimerEnded(currentPosition: Long)
|
||||||
fun onSleepTimerSet(sleepTimeRemaining: Int)
|
fun onSleepTimerSet(sleepTimeRemaining: Int)
|
||||||
fun onLocalMediaProgressUpdate(localMediaProgress: LocalMediaProgress)
|
fun onLocalMediaProgressUpdate(localMediaProgress: LocalMediaProgress)
|
||||||
fun onPlaybackFailed(errorMessage:String)
|
fun onPlaybackFailed(errorMessage:String)
|
||||||
fun onMediaPlayerChanged(mediaPlayer:String)
|
fun onMediaPlayerChanged(mediaPlayer:String)
|
||||||
|
fun onProgressSyncFailing()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val tag = "PlayerService"
|
private val tag = "PlayerService"
|
||||||
|
@ -68,7 +68,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
private lateinit var transportControls:MediaControllerCompat.TransportControls
|
private lateinit var transportControls:MediaControllerCompat.TransportControls
|
||||||
|
|
||||||
lateinit var mediaManager: MediaManager
|
lateinit var mediaManager: MediaManager
|
||||||
private lateinit var apiHandler: ApiHandler
|
lateinit var apiHandler: ApiHandler
|
||||||
|
|
||||||
lateinit var mPlayer: ExoPlayer
|
lateinit var mPlayer: ExoPlayer
|
||||||
lateinit var currentPlayer:Player
|
lateinit var currentPlayer:Player
|
||||||
|
@ -392,6 +392,21 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startNewPlaybackSession() {
|
||||||
|
currentPlaybackSession?.let { playbackSession ->
|
||||||
|
val forceTranscode = playbackSession.isHLS // If already HLS then force
|
||||||
|
val playItemRequestPayload = getPlayItemRequestPayload(forceTranscode)
|
||||||
|
|
||||||
|
val libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play
|
||||||
|
val episodeId = playbackSession.episodeId
|
||||||
|
apiHandler.playLibraryItem(libraryItemId, episodeId, playItemRequestPayload) {
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
preparePlayer(it, true, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun switchToPlayer(useCastPlayer: Boolean) {
|
fun switchToPlayer(useCastPlayer: Boolean) {
|
||||||
val wasPlaying = currentPlayer.isPlaying
|
val wasPlaying = currentPlayer.isPlaying
|
||||||
if (useCastPlayer) {
|
if (useCastPlayer) {
|
||||||
|
@ -483,6 +498,67 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
return currentPlaybackSession?.id
|
return currentPlaybackSession?.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called from PlayerListener play event
|
||||||
|
// check with server if progress has updated since last play and sync progress update
|
||||||
|
fun checkCurrentSessionProgress():Boolean {
|
||||||
|
if (currentPlaybackSession == null) return true
|
||||||
|
|
||||||
|
currentPlaybackSession?.let { playbackSession ->
|
||||||
|
if (!apiHandler.isOnline() || playbackSession.isLocalLibraryItemOnly) {
|
||||||
|
return true // carry on
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playbackSession.isLocal) {
|
||||||
|
// Local playback session check if server has updated media progress
|
||||||
|
Log.d(tag, "checkCurrentSessionProgress: Checking if local media progress was updated on server")
|
||||||
|
apiHandler.getMediaProgress(playbackSession.libraryItemId!!, playbackSession.episodeId) { mediaProgress ->
|
||||||
|
if (mediaProgress.lastUpdate > playbackSession.updatedAt && mediaProgress.currentTime != playbackSession.currentTime) {
|
||||||
|
Log.d(tag, "checkCurrentSessionProgress: Media progress was updated since last play time updating from ${playbackSession.currentTime} to ${mediaProgress.currentTime}")
|
||||||
|
mediaProgressSyncer.syncFromServerProgress(mediaProgress)
|
||||||
|
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
seekPlayer(playbackSession.currentTimeMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
// Should already be playing
|
||||||
|
currentPlayer.volume = 1F // Volume on sleep timer might have decreased this
|
||||||
|
mediaProgressSyncer.start()
|
||||||
|
clientEventEmitter?.onPlayingUpdate(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Streaming from server so check if playback session still exists on server
|
||||||
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"checkCurrentSessionProgress: Checking if playback session for server stream is still available"
|
||||||
|
)
|
||||||
|
apiHandler.getPlaybackSession(playbackSession.id) {
|
||||||
|
if (it == null) {
|
||||||
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"checkCurrentSessionProgress: Playback session does not exist on server - start new playback session"
|
||||||
|
)
|
||||||
|
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
currentPlayer.pause()
|
||||||
|
startNewPlaybackSession()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(tag, "checkCurrentSessionProgress: Playback session still available on server")
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
currentPlayer.volume = 1F // Volume on sleep timer might have decreased this
|
||||||
|
mediaProgressSyncer.start()
|
||||||
|
clientEventEmitter?.onPlayingUpdate(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
fun play() {
|
fun play() {
|
||||||
if (currentPlayer.isPlaying) {
|
if (currentPlayer.isPlaying) {
|
||||||
Log.d(tag, "Already playing")
|
Log.d(tag, "Already playing")
|
||||||
|
@ -570,6 +646,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun alertSyncFailing() {
|
||||||
|
clientEventEmitter?.onProgressSyncFailing()
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// MEDIA BROWSER STUFF (ANDROID AUTO)
|
// MEDIA BROWSER STUFF (ANDROID AUTO)
|
||||||
//
|
//
|
||||||
|
|
|
@ -59,13 +59,6 @@ class AbsAudioPlayer : Plugin() {
|
||||||
notifyListeners("onMetadata", JSObject(jacksonMapper.writeValueAsString(metadata)))
|
notifyListeners("onMetadata", JSObject(jacksonMapper.writeValueAsString(metadata)))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepare(audiobookId: String, playWhenReady: Boolean) {
|
|
||||||
val jsobj = JSObject()
|
|
||||||
jsobj.put("audiobookId", audiobookId)
|
|
||||||
jsobj.put("playWhenReady", playWhenReady)
|
|
||||||
notifyListeners("onPrepareMedia", jsobj)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSleepTimerEnded(currentPosition: Long) {
|
override fun onSleepTimerEnded(currentPosition: Long) {
|
||||||
emit("onSleepTimerEnded", currentPosition)
|
emit("onSleepTimerEnded", currentPosition)
|
||||||
}
|
}
|
||||||
|
@ -85,6 +78,10 @@ class AbsAudioPlayer : Plugin() {
|
||||||
override fun onMediaPlayerChanged(mediaPlayer:String) {
|
override fun onMediaPlayerChanged(mediaPlayer:String) {
|
||||||
emit("onMediaPlayerChanged", mediaPlayer)
|
emit("onMediaPlayerChanged", mediaPlayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onProgressSyncFailing() {
|
||||||
|
emit("onProgressSyncFailing", "")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
mainActivity.pluginCallback = foregroundServiceReady
|
mainActivity.pluginCallback = foregroundServiceReady
|
||||||
|
|
|
@ -86,9 +86,15 @@ class ApiHandler(var ctx:Context) {
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
override fun onResponse(call: Call, response: Response) {
|
||||||
response.use {
|
response.use {
|
||||||
if (!it.isSuccessful) throw IOException("Unexpected code $response")
|
if (!it.isSuccessful) {
|
||||||
|
// throw IOException("Unexpected code $response")
|
||||||
|
val jsobj = JSObject()
|
||||||
|
jsobj.put("error", "Unexpected code $response")
|
||||||
|
cb(jsobj)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val bodyString = it.body!!.string()
|
val bodyString = it.body!!.string()
|
||||||
if (bodyString == "OK") {
|
if (bodyString == "OK") {
|
||||||
cb(JSObject())
|
cb(JSObject())
|
||||||
} else {
|
} else {
|
||||||
|
@ -184,11 +190,15 @@ class ApiHandler(var ctx:Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendProgressSync(sessionId:String, syncData: MediaProgressSyncData, cb: () -> Unit) {
|
fun sendProgressSync(sessionId:String, syncData: MediaProgressSyncData, cb: (Boolean) -> Unit) {
|
||||||
val payload = JSObject(jacksonMapper.writeValueAsString(syncData))
|
val payload = JSObject(jacksonMapper.writeValueAsString(syncData))
|
||||||
|
|
||||||
postRequest("/api/session/$sessionId/sync", payload) {
|
postRequest("/api/session/$sessionId/sync", payload) {
|
||||||
cb()
|
if (!it.getString("error").isNullOrEmpty()) {
|
||||||
|
cb(false)
|
||||||
|
} else {
|
||||||
|
cb(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,4 +262,24 @@ class ApiHandler(var ctx:Context) {
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getMediaProgress(libraryItemId:String, episodeId:String?, cb: (MediaProgress) -> Unit) {
|
||||||
|
val endpoint = if(episodeId.isNullOrEmpty()) "/api/me/progress/$libraryItemId" else "/api/me/progress/$libraryItemId/$episodeId"
|
||||||
|
getRequest(endpoint) {
|
||||||
|
val progress = jacksonMapper.readValue<MediaProgress>(it.toString())
|
||||||
|
cb(progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPlaybackSession(playbackSessionId:String, cb: (PlaybackSession?) -> Unit) {
|
||||||
|
val endpoint = "/api/session/$playbackSessionId"
|
||||||
|
getRequest(endpoint) {
|
||||||
|
val err = it.getString("error")
|
||||||
|
if (!err.isNullOrEmpty()) {
|
||||||
|
cb(null)
|
||||||
|
} else {
|
||||||
|
cb(jacksonMapper.readValue<PlaybackSession>(it.toString()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,11 @@ export default {
|
||||||
onSleepTimerEndedListener: null,
|
onSleepTimerEndedListener: null,
|
||||||
onSleepTimerSetListener: null,
|
onSleepTimerSetListener: null,
|
||||||
onMediaPlayerChangedListener: null,
|
onMediaPlayerChangedListener: null,
|
||||||
|
onProgressSyncFailing: null,
|
||||||
sleepInterval: null,
|
sleepInterval: null,
|
||||||
currentEndOfChapterTime: 0,
|
currentEndOfChapterTime: 0,
|
||||||
serverLibraryItemId: null
|
serverLibraryItemId: null,
|
||||||
|
syncFailedToast: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -241,6 +243,10 @@ export default {
|
||||||
onMediaPlayerChanged(data) {
|
onMediaPlayerChanged(data) {
|
||||||
var mediaPlayer = data.value
|
var mediaPlayer = data.value
|
||||||
this.$store.commit('setMediaPlayer', mediaPlayer)
|
this.$store.commit('setMediaPlayer', mediaPlayer)
|
||||||
|
},
|
||||||
|
showProgressSyncIsFailing() {
|
||||||
|
if (!isNaN(this.syncFailedToast)) this.$toast.dismiss(this.syncFailedToast)
|
||||||
|
this.syncFailedToast = this.$toast('Progress is not being synced', { timeout: false, type: 'error' })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -248,6 +254,7 @@ export default {
|
||||||
this.onSleepTimerEndedListener = AbsAudioPlayer.addListener('onSleepTimerEnded', this.onSleepTimerEnded)
|
this.onSleepTimerEndedListener = AbsAudioPlayer.addListener('onSleepTimerEnded', this.onSleepTimerEnded)
|
||||||
this.onSleepTimerSetListener = AbsAudioPlayer.addListener('onSleepTimerSet', this.onSleepTimerSet)
|
this.onSleepTimerSetListener = AbsAudioPlayer.addListener('onSleepTimerSet', this.onSleepTimerSet)
|
||||||
this.onMediaPlayerChangedListener = AbsAudioPlayer.addListener('onMediaPlayerChanged', this.onMediaPlayerChanged)
|
this.onMediaPlayerChangedListener = AbsAudioPlayer.addListener('onMediaPlayerChanged', this.onMediaPlayerChanged)
|
||||||
|
this.onProgressSyncFailing = AbsAudioPlayer.addListener('onProgressSyncFailing', this.showProgressSyncIsFailing)
|
||||||
|
|
||||||
this.playbackSpeed = this.$store.getters['user/getUserSetting']('playbackRate')
|
this.playbackSpeed = this.$store.getters['user/getUserSetting']('playbackRate')
|
||||||
console.log(`[AudioPlayerContainer] Init Playback Speed: ${this.playbackSpeed}`)
|
console.log(`[AudioPlayerContainer] Init Playback Speed: ${this.playbackSpeed}`)
|
||||||
|
@ -264,6 +271,7 @@ export default {
|
||||||
if (this.onSleepTimerEndedListener) this.onSleepTimerEndedListener.remove()
|
if (this.onSleepTimerEndedListener) this.onSleepTimerEndedListener.remove()
|
||||||
if (this.onSleepTimerSetListener) this.onSleepTimerSetListener.remove()
|
if (this.onSleepTimerSetListener) this.onSleepTimerSetListener.remove()
|
||||||
if (this.onMediaPlayerChangedListener) this.onMediaPlayerChangedListener.remove()
|
if (this.onMediaPlayerChangedListener) this.onMediaPlayerChangedListener.remove()
|
||||||
|
if (this.onProgressSyncFailing) this.onProgressSyncFailing.remove()
|
||||||
|
|
||||||
// if (this.$server.socket) {
|
// if (this.$server.socket) {
|
||||||
// this.$server.socket.off('stream_open', this.streamOpen)
|
// this.$server.socket.off('stream_open', this.streamOpen)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue