Cleanup prev/next

This commit is contained in:
2026-05-11 23:23:04 +02:00
parent 1e4a6e3787
commit 2519998475
15 changed files with 88 additions and 359 deletions
@@ -5,9 +5,12 @@ import androidx.media3.common.C
import androidx.media3.common.C.TRACK_TYPE_AUDIO
import androidx.media3.common.C.TRACK_TYPE_TEXT
import androidx.media3.common.C.TRACK_TYPE_VIDEO
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.PlaybackParameters
import androidx.media3.common.Player
import androidx.media3.common.Player.MEDIA_ITEM_TRANSITION_REASON_AUTO
import androidx.media3.common.Player.MEDIA_ITEM_TRANSITION_REASON_SEEK
import androidx.media3.common.Player.STATE_BUFFERING
import androidx.media3.common.Player.STATE_ENDED
import androidx.media3.common.Player.STATE_IDLE
@@ -34,6 +37,7 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li
private val stateBoolListeners = mutableMapOf<BoolProperty, MutableSet<(Boolean) -> Unit>>()
private val playerStatusListeners = mutableSetOf<(PlayerStatus) -> Unit>()
private var lastTimePosDispatchMs = 0L
private var lastMediaItemIndex = 0
init {
player.addListener(this)
@@ -112,6 +116,20 @@ class EventMap(private val player: Player) : HybridOmniEventMapSpec(), Player.Li
}
}
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
if (reason != MEDIA_ITEM_TRANSITION_REASON_AUTO && reason != MEDIA_ITEM_TRANSITION_REASON_SEEK) {
lastMediaItemIndex = player.currentMediaItemIndex
return
}
val newIndex = player.currentMediaItemIndex
if (newIndex < lastMediaItemIndex) {
onPrevListeners.forEach { it() }
} else if (newIndex > lastMediaItemIndex) {
onNextListeners.forEach { it() }
}
lastMediaItemIndex = newIndex
}
override fun onPositionDiscontinuity(
oldPosition: Player.PositionInfo,
newPosition: Player.PositionInfo,
@@ -102,6 +102,7 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver {
private var currentTrackSelectionParameters = TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT
private var playerError: PlaybackException? = null
private var playlistMetadata: MediaMetadata = MediaMetadata.EMPTY
private var userInitiatedTransition: Boolean = false
private val availableCommands: Player.Commands = Player.Commands.Builder()
.add(COMMAND_PLAY_PAUSE)
@@ -185,6 +186,12 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver {
if (prev != currentMediaItemIndex) {
events.add(EVENT_MEDIA_ITEM_TRANSITION)
}
val transitionReason = if (userInitiatedTransition) {
MEDIA_ITEM_TRANSITION_REASON_SEEK
} else {
MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED
}
userInitiatedTransition = false
notifyListeners(events.toTypedArray()) {
it.onTimelineChanged(currentTimeline, TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED)
it.onMediaMetadataChanged(mediaMetadata)
@@ -192,7 +199,7 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver {
if (prev != currentMediaItemIndex) {
it.onMediaItemTransition(
currentMediaItem,
MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED
transitionReason
)
}
}
@@ -276,6 +283,7 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver {
if (targetIndex == INDEX_UNSET || targetIndex !in mediaItems.indices) return
if (targetIndex != currentMediaItemIndex) {
userInitiatedTransition = true
setMediaItems(mediaItems, targetIndex, positionMs)
return
}
@@ -428,7 +436,7 @@ class MpvPlayer(ctx: Context) : BasePlayer(), MPVLib.EventObserver {
0L,
durationUs,
0,
0,
mediaItems.size-1,
0L
)
}
@@ -68,32 +68,32 @@ class OmniPlayer : HybridOmniPlayerSpec() {
set(value) {
Log.e("omni", "update source")
currentSource = value
val src = value.src.firstOrNull()
if (src == null) {
runOnMainThreadSync {
player.setMediaItem(MediaItem.EMPTY)
player.prepare()
}
return
}
val currentItem = buildMediaItem(src, value.metadata, value.subtitles)
val mediaItems = mutableListOf<MediaItem>()
value.prev?.let { prevSource ->
prevSource.src.firstOrNull()?.let { src ->
mediaItems.add(buildMediaItem(src, prevSource.metadata, prevSource.subtitles))
}
if (value.metadata?.hasPrev == true) {
mediaItems.add(currentItem)
}
value.src.firstOrNull()?.let { src ->
mediaItems.add(buildMediaItem(src, value.metadata, value.subtitles))
}
mediaItems.add(currentItem)
value.next?.let { nextSource ->
nextSource.src.firstOrNull()?.let { src ->
mediaItems.add(buildMediaItem(src, nextSource.metadata, nextSource.subtitles))
}
if (value.metadata?.hasNext == true) {
mediaItems.add(currentItem)
}
runOnMainThreadSync {
if (mediaItems.isEmpty()) {
player.setMediaItem(MediaItem.EMPTY)
} else {
val startIndex = if (value.prev != null) 1 else 0
val startPositionMs = (value.startTime?.coerceAtLeast(0.0) ?: 0.0) * 1000.0
player.setMediaItems(mediaItems, startIndex, startPositionMs.toLong())
}
val startIndex = if (value.metadata?.hasPrev == true) 1 else 0
val startPositionMs = (value.startTime?.coerceAtLeast(0.0) ?: 0.0) * 1000.0
player.setMediaItems(mediaItems, startIndex, startPositionMs.toLong())
player.prepare()
}
}
@@ -163,8 +163,8 @@ class OmniPlayer : HybridOmniPlayerSpec() {
}
}
override val hasPrev by mainThreadProperty { player.hasPreviousMediaItem() }
override val hasNext by mainThreadProperty { player.hasNextMediaItem() }
override val hasPrev: Boolean get() = currentSource?.metadata?.hasPrev == true
override val hasNext: Boolean get() = currentSource?.metadata?.hasNext == true
override val status by mainThreadProperty {
when (player.playbackState) {
Player.STATE_IDLE,