feature: Added MediaSegmentManager

This commit is contained in:
2026-04-23 19:59:12 +02:00
parent f0a4aadcf0
commit 59a471c535
5 changed files with 101 additions and 16 deletions

View File

@@ -2,12 +2,17 @@ package hu.bbara.purefin.core.model
import java.util.UUID import java.util.UUID
enum class SegmentType { enum class SegmentType(val value: Int) {
INTRO, INTRO(0),
OUTRO, OUTRO(1),
MAIN_CONTENT, MAIN_CONTENT(2),
PREVIEW, PREVIEW(3),
RECAP; RECAP(4);
companion object {
fun fromValue(value: Int): SegmentType? =
entries.firstOrNull { it.value == value }
}
} }
data class MediaSegment( data class MediaSegment(

View File

@@ -0,0 +1,69 @@
package hu.bbara.purefin.core.player.manager
import android.os.Looper
import android.util.Log
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.PlayerMessage
import hu.bbara.purefin.core.model.MediaSegment
import hu.bbara.purefin.core.model.SegmentType
import hu.bbara.purefin.core.player.model.SegmentStatus
@OptIn(UnstableApi::class)
class MediaSegmentManager(private val player: ExoPlayer) {
private var listener: MediaSegmentListener? = null
interface MediaSegmentListener {
fun onEvent(segmentType: SegmentType, status: SegmentStatus)
}
@Synchronized
fun registerListener(listener: MediaSegmentListener) {
this.listener?.let {
Log.w("PlayerMessageManager", "Listener was already register")
return
}
this.listener = listener
}
fun addMediaSegments(mediaSegments: List<MediaSegment>) {
val messageTarget = PlayerMessage.Target { messageType, payload ->
SegmentType.fromValue(messageType)?.let { segmentType ->
notifyListener(segmentType, payload as SegmentStatus)
}
}
mediaSegments.forEach { mediaSegment ->
installMediaSegment(messageTarget, mediaSegment)
}
}
private fun notifyListener(segmentType: SegmentType, status: SegmentStatus) {
if (listener == null) {
Log.w("PlayerMessageManager", "Listener was not register therefore it cannot notify")
}
listener?.onEvent(segmentType, status)
}
private fun installMediaSegment(messageTarget: PlayerMessage.Target, mediaSegment: MediaSegment) {
player.createMessage(messageTarget)
.setType(mediaSegment.type.value)
.setPosition(mediaSegment.startMs)
.setPayload(SegmentStatus.START)
.setLooper(Looper.getMainLooper())
.setDeleteAfterDelivery(false)
.send()
player.createMessage(messageTarget)
.setType(mediaSegment.type.value)
.setPayload(SegmentStatus.END)
.setPosition(mediaSegment.endMs)
.setLooper(Looper.getMainLooper())
.setDeleteAfterDelivery(false)
.send()
}
}

View File

@@ -7,8 +7,10 @@ import androidx.media3.common.PlaybackException
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.TrackSelectionOverride import androidx.media3.common.TrackSelectionOverride
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import dagger.hilt.android.scopes.ViewModelScoped import dagger.hilt.android.scopes.ViewModelScoped
import hu.bbara.purefin.core.data.PlaybackReportContext import hu.bbara.purefin.core.data.PlaybackReportContext
import hu.bbara.purefin.core.model.MediaSegment
import hu.bbara.purefin.core.player.model.MediaContext import hu.bbara.purefin.core.player.model.MediaContext
import hu.bbara.purefin.core.player.model.MetadataState import hu.bbara.purefin.core.player.model.MetadataState
import hu.bbara.purefin.core.player.model.PlaybackProgressSnapshot import hu.bbara.purefin.core.player.model.PlaybackProgressSnapshot
@@ -51,6 +53,8 @@ class PlayerManager @Inject constructor(
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
private val mediaSegmentManager = MediaSegmentManager(player as ExoPlayer)
private var currentMediaContext: MediaContext? = null private var currentMediaContext: MediaContext? = null
private var pendingSeekPositionMs: Long? = null private var pendingSeekPositionMs: Long? = null
@@ -84,10 +88,14 @@ class PlayerManager @Inject constructor(
} }
} }
override fun onEvents(player: Player, events: Player.Events) { override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
if (events.contains(Player.EVENT_MEDIA_ITEM_TRANSITION)) {
clearPendingSeek() clearPendingSeek()
currentMediaContext?.let {
installMediaSegments(it.mediaSegments)
} }
}
override fun onEvents(player: Player, events: Player.Events) {
updateFromPlayer(player) updateFromPlayer(player)
if (events.contains(Player.EVENT_TRACKS_CHANGED)) { if (events.contains(Player.EVENT_TRACKS_CHANGED)) {
scope.launch { scope.launch {
@@ -215,8 +223,10 @@ class PlayerManager @Inject constructor(
} }
} }
fun setPlaybackSpeed(speed: Float) { private fun installMediaSegments(mediaSegments: List<MediaSegment>) {
player.setPlaybackSpeed(speed) mediaSegmentManager.addMediaSegments(
mediaSegments = mediaSegments
)
} }
fun retry() { fun retry() {

View File

@@ -0,0 +1,6 @@
package hu.bbara.purefin.core.player.model
enum class SegmentStatus {
START,
END
}

View File

@@ -272,11 +272,6 @@ class PlayerViewModel @Inject constructor(
playerManager.selectTrack(option) playerManager.selectTrack(option)
} }
fun setPlaybackSpeed(speed: Float) {
playerManager.setPlaybackSpeed(speed)
_uiState.update { it.copy(playbackSpeed = speed) }
}
fun retry() { fun retry() {
playerManager.retry() playerManager.retry()
} }