From 6c26891bff4cefc23b585fcefe30a35ac9bc5e71 Mon Sep 17 00:00:00 2001 From: Damontecres Date: Mon, 16 Mar 2026 13:30:25 -0400 Subject: [PATCH] Make TrackActivityPlaybackListener more generic --- .../wholphin/ui/playback/PlaybackViewModel.kt | 5 +- .../util/TrackActivityPlaybackListener.kt | 67 +++++++++++++------ 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt index c5450d3f..b54dea6f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt @@ -63,6 +63,7 @@ import com.github.damontecres.wholphin.ui.showToast import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.LoadingState +import com.github.damontecres.wholphin.util.PlaybackItemState import com.github.damontecres.wholphin.util.TrackActivityPlaybackListener import com.github.damontecres.wholphin.util.checkForSupport import com.github.damontecres.wholphin.util.mpv.mpvDeviceProfile @@ -737,12 +738,12 @@ class PlaybackViewModel player.removeListener(it) } + val playbackItemState = PlaybackItemState(playback, currentItemPlayback) val activityListener = TrackActivityPlaybackListener( api = api, player = player, - playback = playback, - itemPlayback = currentItemPlayback, + getState = { playbackItemState }, ) player.addListener(activityListener) this@PlaybackViewModel.activityListener = activityListener diff --git a/app/src/main/java/com/github/damontecres/wholphin/util/TrackActivityPlaybackListener.kt b/app/src/main/java/com/github/damontecres/wholphin/util/TrackActivityPlaybackListener.kt index b0c1f593..206d262b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/util/TrackActivityPlaybackListener.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/util/TrackActivityPlaybackListener.kt @@ -11,6 +11,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.playStateApi +import org.jellyfin.sdk.model.api.PlayMethod import org.jellyfin.sdk.model.api.PlaybackOrder import org.jellyfin.sdk.model.api.PlaybackProgressInfo import org.jellyfin.sdk.model.api.PlaybackStartInfo @@ -20,6 +21,7 @@ import org.jellyfin.sdk.model.extensions.inWholeTicks import timber.log.Timber import java.util.Timer import java.util.TimerTask +import java.util.UUID import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -30,8 +32,7 @@ import kotlin.time.Duration.Companion.seconds class TrackActivityPlaybackListener( private val api: ApiClient, private val player: Player, - val playback: CurrentPlayback, - val itemPlayback: ItemPlayback, + private val getState: () -> PlaybackItemState, ) : Player.Listener { private val coroutineScope = CoroutineScope(Dispatchers.Main) private val task: TimerTask = @@ -50,20 +51,21 @@ class TrackActivityPlaybackListener( fun init() { launch("reportPlaybackStart") { - Timber.v("reportPlaybackStart for ${itemPlayback.itemId}") + val state = getState.invoke() + Timber.v("reportPlaybackStart for ${state.itemId}") api.playStateApi.reportPlaybackStart( PlaybackStartInfo( canSeek = true, - itemId = itemPlayback.itemId, + itemId = state.itemId, isPaused = withContext(Dispatchers.Main) { !player.isPlaying }, - playMethod = playback.playMethod, + playMethod = state.playMethod, repeatMode = RepeatMode.REPEAT_NONE, playbackOrder = PlaybackOrder.DEFAULT, isMuted = false, - audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled }, - subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled }, - playSessionId = playback.playSessionId, - liveStreamId = playback.liveStreamId, + audioStreamIndex = state.audioStreamIndex, + subtitleStreamIndex = state.subtitleStreamIndex, + playSessionId = state.playSessionId, + liveStreamId = state.liveStreamId, ), ) val delay = 5.seconds.inWholeMilliseconds @@ -78,14 +80,15 @@ class TrackActivityPlaybackListener( TIMER.purge() val position = player.currentPosition.milliseconds launch("reportPlaybackStopped") { - Timber.v("reportPlaybackStopped for ${itemPlayback.itemId} at $position") + val state = getState.invoke() + Timber.v("reportPlaybackStopped for ${state.itemId} at $position") api.playStateApi.reportPlaybackStopped( PlaybackStopInfo( - itemId = itemPlayback.itemId, + itemId = state.itemId, positionTicks = position.inWholeTicks, failed = false, - playSessionId = playback.playSessionId, - liveStreamId = playback.liveStreamId, + playSessionId = state.playSessionId, + liveStreamId = state.liveStreamId, ), ) } @@ -108,27 +111,28 @@ class TrackActivityPlaybackListener( private fun saveActivity(position: Long) { launch("saveActivity") { + val state = getState.invoke() val calcPosition = withContext(Dispatchers.Main) { (if (position >= 0) position else player.currentPosition) } if (calcPosition > 0) { val isPaused = withContext(Dispatchers.Main) { !player.isPlaying } - Timber.v("saveActivity: itemId=${itemPlayback.itemId}, pos=$calcPosition") + Timber.v("saveActivity: itemId=${state.itemId}, pos=$calcPosition") api.playStateApi.reportPlaybackProgress( PlaybackProgressInfo( - itemId = itemPlayback.itemId, + itemId = state.itemId, positionTicks = calcPosition.milliseconds.inWholeTicks, canSeek = true, isPaused = isPaused, isMuted = false, - playMethod = playback.playMethod, + playMethod = state.playMethod, repeatMode = RepeatMode.REPEAT_NONE, playbackOrder = PlaybackOrder.DEFAULT, - audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled }, - subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled }, - playSessionId = playback.playSessionId, - liveStreamId = playback.liveStreamId, + audioStreamIndex = state.audioStreamIndex, + subtitleStreamIndex = state.subtitleStreamIndex, + playSessionId = state.playSessionId, + liveStreamId = state.liveStreamId, ), ) } @@ -143,7 +147,7 @@ class TrackActivityPlaybackListener( try { block.invoke(this) } catch (ex: Exception) { - Timber.w(ex, "Exception during %s for %s", name, itemPlayback.itemId) + Timber.w(ex, "Exception during %s", name) } } } @@ -154,3 +158,24 @@ class TrackActivityPlaybackListener( private val TIMER by lazy { Timer("$TAG-timer", true) } } } + +data class PlaybackItemState( + val itemId: UUID, + val playMethod: PlayMethod, + val audioStreamIndex: Int? = null, + val subtitleStreamIndex: Int? = null, + val playSessionId: String? = null, + val liveStreamId: String? = null, +) { + constructor( + playback: CurrentPlayback, + itemPlayback: ItemPlayback, + ) : this( + itemId = itemPlayback.itemId, + playMethod = playback.playMethod, + audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled }, + subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled }, + playSessionId = playback.playSessionId, + liveStreamId = playback.liveStreamId, + ) +}