Don't report playback started until it actually starts (#107)

Wait until playback actually beings before reporting status to the
server. And also ensure progress isn't reported until after reporting
start.
This commit is contained in:
damontecres 2025-10-29 13:15:17 -04:00 committed by GitHub
parent 576c20edff
commit cbcae526b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 38 deletions

View file

@ -293,7 +293,7 @@ sealed interface AppPreference<T> {
) )
private const val MEGA_BIT = 1024 * 1024L private const val MEGA_BIT = 1024 * 1024L
const val DEFAULT_BITRATE = 20 * MEGA_BIT const val DEFAULT_BITRATE = 100 * MEGA_BIT
private val bitrateValues = private val bitrateValues =
listOf( listOf(
500 * 1024L, 500 * 1024L,
@ -305,7 +305,7 @@ sealed interface AppPreference<T> {
8 * MEGA_BIT, 8 * MEGA_BIT,
10 * MEGA_BIT, 10 * MEGA_BIT,
15 * MEGA_BIT, 15 * MEGA_BIT,
DEFAULT_BITRATE, 20 * MEGA_BIT,
*(30..100 step 10).map { it * MEGA_BIT }.toTypedArray(), *(30..100 step 10).map { it * MEGA_BIT }.toTypedArray(),
*(120..200 step 20).map { it * MEGA_BIT }.toTypedArray(), *(120..200 step 20).map { it * MEGA_BIT }.toTypedArray(),
) )

View file

@ -30,14 +30,27 @@ import kotlin.time.Duration.Companion.seconds
class TrackActivityPlaybackListener( class TrackActivityPlaybackListener(
private val api: ApiClient, private val api: ApiClient,
private val player: Player, private val player: Player,
var playback: CurrentPlayback, val playback: CurrentPlayback,
var itemPlayback: ItemPlayback, val itemPlayback: ItemPlayback,
) : Player.Listener { ) : Player.Listener {
private val coroutineScope = CoroutineScope(Dispatchers.Main) private val coroutineScope = CoroutineScope(Dispatchers.Main)
private val task: TimerTask private val task: TimerTask =
object : TimerTask() {
override fun run() {
try {
saveActivity(-1L)
} catch (ex: Exception) {
Timber.w(ex, "Exception during track activity timer")
}
}
}
init { @Volatile
private var initialized = false
fun init() {
coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) { coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) {
Timber.v("reportPlaybackStart for ${itemPlayback.itemId}")
api.playStateApi.reportPlaybackStart( api.playStateApi.reportPlaybackStart(
PlaybackStartInfo( PlaybackStartInfo(
canSeek = true, canSeek = true,
@ -49,23 +62,15 @@ class TrackActivityPlaybackListener(
isMuted = false, isMuted = false,
audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled }, audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled },
subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled }, subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled },
playSessionId = playback.playSessionId,
liveStreamId = playback.liveStreamId, liveStreamId = playback.liveStreamId,
), ),
) )
val delay = 5.seconds.inWholeMilliseconds
// Every x seconds, check if the video is playing
TIMER.schedule(task, delay, delay)
initialized = true
} }
val delay = 5.seconds.inWholeMilliseconds
// Every x seconds, check if the video is playing
task =
object : TimerTask() {
override fun run() {
try {
saveActivity(-1L)
} catch (ex: Exception) {
Timber.Forest.w(ex, "Exception during track activity timer")
}
}
}
TIMER.schedule(task, delay, delay)
} }
fun release() { fun release() {
@ -73,6 +78,7 @@ class TrackActivityPlaybackListener(
TIMER.purge() TIMER.purge()
val position = player.currentPosition.milliseconds.inWholeTicks val position = player.currentPosition.milliseconds.inWholeTicks
coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) { coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) {
Timber.v("reportPlaybackStopped for ${itemPlayback.itemId}")
api.playStateApi.reportPlaybackStopped( api.playStateApi.reportPlaybackStopped(
PlaybackStopInfo( PlaybackStopInfo(
itemId = itemPlayback.itemId, itemId = itemPlayback.itemId,
@ -86,7 +92,11 @@ class TrackActivityPlaybackListener(
} }
override fun onIsPlayingChanged(isPlaying: Boolean) { override fun onIsPlayingChanged(isPlaying: Boolean) {
saveActivity(-1) if (initialized) {
saveActivity(-1)
} else if (isPlaying) {
init()
}
} }
override fun onPlaybackStateChanged(playbackState: Int) { override fun onPlaybackStateChanged(playbackState: Int) {
@ -100,25 +110,28 @@ class TrackActivityPlaybackListener(
coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) { coroutineScope.launch(Dispatchers.IO + ExceptionHandler()) {
val calcPosition = val calcPosition =
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
(if (position >= 0) position else player.currentPosition).milliseconds (if (position >= 0) position else player.currentPosition)
} }
// Timber.v("saveActivity: itemId=${itemPlayback.itemId}, pos=$calcPosition") if (calcPosition > 0) {
api.playStateApi.reportPlaybackProgress( val isPaused = withContext(Dispatchers.Main) { !player.isPlaying }
PlaybackProgressInfo( Timber.v("saveActivity: itemId=${itemPlayback.itemId}, pos=$calcPosition")
itemId = itemPlayback.itemId, api.playStateApi.reportPlaybackProgress(
positionTicks = calcPosition.inWholeTicks, PlaybackProgressInfo(
canSeek = true, itemId = itemPlayback.itemId,
isPaused = withContext(Dispatchers.Main) { !player.isPlaying }, positionTicks = calcPosition.milliseconds.inWholeTicks,
isMuted = false, canSeek = true,
playMethod = playback.playMethod, isPaused = isPaused,
repeatMode = RepeatMode.REPEAT_NONE, isMuted = false,
playbackOrder = PlaybackOrder.DEFAULT, playMethod = playback.playMethod,
playSessionId = playback.playSessionId, repeatMode = RepeatMode.REPEAT_NONE,
audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled }, playbackOrder = PlaybackOrder.DEFAULT,
subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled }, audioStreamIndex = itemPlayback.audioIndex.takeIf { itemPlayback.audioIndexEnabled },
liveStreamId = playback.liveStreamId, subtitleStreamIndex = itemPlayback.subtitleIndex.takeIf { itemPlayback.subtitleIndexEnabled },
), playSessionId = playback.playSessionId,
) liveStreamId = playback.liveStreamId,
),
)
}
} }
} }