Post start, stop and progress of media to the server

This commit is contained in:
Jarne Demeulemeester 2021-07-14 12:00:05 +02:00
parent e87a9804ec
commit 00ec736ff4
No known key found for this signature in database
GPG key ID: 60884A0C1EBA43E5
4 changed files with 68 additions and 1 deletions

View file

@ -34,6 +34,7 @@ class JellyfinApi(context: Context, baseUrl: String) {
val sessionApi = SessionApi(api) val sessionApi = SessionApi(api)
val videosApi = VideosApi(api) val videosApi = VideosApi(api)
val mediaInfoApi = MediaInfoApi(api) val mediaInfoApi = MediaInfoApi(api)
val playstateApi = PlayStateApi(api)
companion object { companion object {
@Volatile @Volatile

View file

@ -19,4 +19,10 @@ interface JellyfinRepository {
suspend fun getMediaSources(itemId: UUID): List<MediaSourceInfo> suspend fun getMediaSources(itemId: UUID): List<MediaSourceInfo>
suspend fun getStreamUrl(itemId: UUID, mediaSourceId: String): String suspend fun getStreamUrl(itemId: UUID, mediaSourceId: String): String
suspend fun postPlaybackStart(itemId: UUID)
suspend fun postPlaybackStop(itemId: UUID, positionTicks: Long)
suspend fun postPlaybackProgress(itemId: UUID, positionTicks: Long, isPaused: Boolean)
} }

View file

@ -101,7 +101,7 @@ class JellyfinRepositoryImpl(private val jellyfinApi: JellyfinApi) : JellyfinRep
} }
override suspend fun getStreamUrl(itemId: UUID, mediaSourceId: String): String { override suspend fun getStreamUrl(itemId: UUID, mediaSourceId: String): String {
var streamUrl: String = "" var streamUrl = ""
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
try { try {
streamUrl = jellyfinApi.videosApi.getVideoStreamUrl( streamUrl = jellyfinApi.videosApi.getVideoStreamUrl(
@ -115,4 +115,24 @@ class JellyfinRepositoryImpl(private val jellyfinApi: JellyfinApi) : JellyfinRep
} }
return streamUrl return streamUrl
} }
override suspend fun postPlaybackStart(itemId: UUID) {
Log.d("PlayerActivity", "Sending start $itemId")
withContext(Dispatchers.IO) {
jellyfinApi.playstateApi.onPlaybackStart(jellyfinApi.userId!!, itemId)
}
}
override suspend fun postPlaybackStop(itemId: UUID, positionTicks: Long) {
Log.d("PlayerActivity", "Sending stop $itemId")
withContext(Dispatchers.IO) {
jellyfinApi.playstateApi.onPlaybackStopped(jellyfinApi.userId!!, itemId, positionTicks = positionTicks)
}
}
override suspend fun postPlaybackProgress(itemId: UUID, positionTicks: Long, isPaused: Boolean) {
withContext(Dispatchers.IO) {
jellyfinApi.playstateApi.onPlaybackProgress(jellyfinApi.userId!!, itemId, positionTicks = positionTicks, isPaused = isPaused)
}
}
} }

View file

@ -1,6 +1,8 @@
package dev.jdtech.jellyfin.viewmodels package dev.jdtech.jellyfin.viewmodels
import android.app.Application import android.app.Application
import android.os.Handler
import android.os.Looper
import android.util.Log import android.util.Log
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@ -11,6 +13,7 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dev.jdtech.jellyfin.repository.JellyfinRepository import dev.jdtech.jellyfin.repository.JellyfinRepository
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@ -30,6 +33,8 @@ constructor(
private var playbackPosition: Long = 0 private var playbackPosition: Long = 0
private var _playbackStateListener: PlaybackStateListener private var _playbackStateListener: PlaybackStateListener
private var itemId: UUID? = null
val playbackStateListener: PlaybackStateListener val playbackStateListener: PlaybackStateListener
get() = _playbackStateListener get() = _playbackStateListener
@ -38,6 +43,8 @@ constructor(
} }
fun initializePlayer(itemId: UUID, mediaSourceId: String, playbackPosition: Long) { fun initializePlayer(itemId: UUID, mediaSourceId: String, playbackPosition: Long) {
this.itemId = itemId
val renderersFactory = val renderersFactory =
DefaultRenderersFactory(application).setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON) DefaultRenderersFactory(application).setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
val trackSelector = DefaultTrackSelector(application) val trackSelector = DefaultTrackSelector(application)
@ -62,10 +69,22 @@ constructor(
player.playWhenReady = playWhenReady player.playWhenReady = playWhenReady
player.prepare() player.prepare()
_player.value = player _player.value = player
jellyfinRepository.postPlaybackStart(itemId)
} }
pollPosition(player, itemId)
} }
private fun releasePlayer() { private fun releasePlayer() {
itemId?.let { itemId ->
_player.value?.let { player ->
runBlocking {
jellyfinRepository.postPlaybackStop(itemId, player.currentPosition.times(10000))
}
}
}
if (player.value != null) { if (player.value != null) {
playWhenReady = player.value!!.playWhenReady playWhenReady = player.value!!.playWhenReady
playbackPosition = player.value!!.currentPosition playbackPosition = player.value!!.currentPosition
@ -76,6 +95,27 @@ constructor(
} }
} }
private fun pollPosition(player: SimpleExoPlayer, itemId: UUID) {
val handler = Handler(Looper.getMainLooper())
val runnable: Runnable = object : Runnable {
override fun run() {
viewModelScope.launch {
Log.d(
"PlayerActivity",
"Posting progress of $itemId, position: ${player.currentPosition}"
)
jellyfinRepository.postPlaybackProgress(
itemId,
player.currentPosition.times(10000),
!player.isPlaying
)
}
handler.postDelayed(this, 2000)
}
}
handler.post(runnable)
}
class PlaybackStateListener : Player.Listener { class PlaybackStateListener : Player.Listener {
private val _navigateBack = MutableLiveData<Boolean>() private val _navigateBack = MutableLiveData<Boolean>()
val navigateBack: LiveData<Boolean> = _navigateBack val navigateBack: LiveData<Boolean> = _navigateBack