feat: add preferenceMediaId to PlayableMedia and update related logic to make more prone to mistakes

This commit is contained in:
2026-05-13 22:52:49 +02:00
parent 9fb3672c19
commit cc643ae34f
3 changed files with 41 additions and 20 deletions

View File

@@ -5,6 +5,7 @@ import java.util.UUID
sealed class PlayableMedia { sealed class PlayableMedia {
abstract val id: UUID abstract val id: UUID
abstract val preferenceMediaId: UUID
abstract val resumePositionMs: Long abstract val resumePositionMs: Long
abstract val mediaItem: MediaItem abstract val mediaItem: MediaItem
abstract val preferences: MediaTrackPreferences abstract val preferences: MediaTrackPreferences
@@ -12,6 +13,7 @@ sealed class PlayableMedia {
data class Movie( data class Movie(
override val id: UUID, override val id: UUID,
override val preferenceMediaId: UUID,
override val resumePositionMs: Long, override val resumePositionMs: Long,
override val mediaItem: MediaItem, override val mediaItem: MediaItem,
override val preferences: MediaTrackPreferences, override val preferences: MediaTrackPreferences,
@@ -20,6 +22,7 @@ sealed class PlayableMedia {
data class Series( data class Series(
override val id: UUID, override val id: UUID,
override val preferenceMediaId: UUID,
override val resumePositionMs: Long, override val resumePositionMs: Long,
override val mediaItem: MediaItem, override val mediaItem: MediaItem,
override val preferences: MediaTrackPreferences, override val preferences: MediaTrackPreferences,
@@ -28,6 +31,7 @@ sealed class PlayableMedia {
data class Episode( data class Episode(
override val id: UUID, override val id: UUID,
override val preferenceMediaId: UUID,
override val resumePositionMs: Long, override val resumePositionMs: Long,
override val mediaItem: MediaItem, override val mediaItem: MediaItem,
override val preferences: MediaTrackPreferences, override val preferences: MediaTrackPreferences,

View File

@@ -11,7 +11,6 @@ import androidx.media3.exoplayer.ExoPlayer
import dagger.hilt.android.scopes.ViewModelScoped import dagger.hilt.android.scopes.ViewModelScoped
import hu.bbara.purefin.core.data.PlayableMediaRepository import hu.bbara.purefin.core.data.PlayableMediaRepository
import hu.bbara.purefin.core.data.PlaybackReportContext import hu.bbara.purefin.core.data.PlaybackReportContext
import hu.bbara.purefin.core.feature.content.episode.SeriesIdLookUpUseCase
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
import hu.bbara.purefin.core.player.model.PlaybackStateSnapshot import hu.bbara.purefin.core.player.model.PlaybackStateSnapshot
@@ -56,7 +55,6 @@ class PlayerManager @Inject constructor(
private val playableMediaRepository: PlayableMediaRepository, private val playableMediaRepository: PlayableMediaRepository,
private val trackPreferencesRepository: TrackPreferencesRepository, private val trackPreferencesRepository: TrackPreferencesRepository,
private val trackMatcher: TrackMatcher, private val trackMatcher: TrackMatcher,
private val seriesIdLookUpUseCase: SeriesIdLookUpUseCase,
private val settingsRepository: SettingsRepository private val settingsRepository: SettingsRepository
) { ) {
companion object { companion object {
@@ -116,7 +114,8 @@ class PlayerManager @Inject constructor(
override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) { override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
clearActiveSkippableSegment() clearActiveSkippableSegment()
_currentMediaId.value = mediaItem?.mediaId?.let { UUID.fromString(it) } val mediaId = mediaItem?.mediaId?.let { UUID.fromString(it) }
_currentMediaId.value = mediaId
scope.launch { scope.launch {
val currentMedia = _playlist.value.firstOrNull { it.id == _currentMediaId.value } val currentMedia = _playlist.value.firstOrNull { it.id == _currentMediaId.value }
if (currentMedia == null) { if (currentMedia == null) {
@@ -263,6 +262,15 @@ class PlayerManager @Inject constructor(
} }
fun selectTrack(option: TrackOption) { fun selectTrack(option: TrackOption) {
scope.launch {
if (option.type != TrackType.VIDEO) {
saveTrackPreference(option)
}
applyTrackSelection(option)
}
}
private fun applyTrackSelection(option: TrackOption) {
val builder = player.trackSelectionParameters.buildUpon() val builder = player.trackSelectionParameters.buildUpon()
when (option.type) { when (option.type) {
TrackType.TEXT -> { TrackType.TEXT -> {
@@ -296,13 +304,6 @@ class PlayerManager @Inject constructor(
} }
} }
player.trackSelectionParameters = builder.build() player.trackSelectionParameters = builder.build()
// Save track preference if media id is available
_currentMediaId.value?.let { mediaId ->
scope.launch {
saveTrackPreference(option, mediaId)
}
}
} }
private fun installMediaSegments(mediaSegments: List<MediaSegment>) { private fun installMediaSegments(mediaSegments: List<MediaSegment>) {
@@ -329,9 +330,14 @@ class PlayerManager @Inject constructor(
} }
private suspend fun applyTrackPreferences() { private suspend fun applyTrackPreferences() {
val preferences = currentPlayableMedia.firstOrNull()?.preferences ?: return val currentMedia = currentPlayableMedia.firstOrNull() ?: return
val currentTrackState = _tracks.value val currentTrackState = _tracks.value
if (currentTrackState.audioTracks.isEmpty() && currentTrackState.textTracks.isEmpty()) return
val preferences = trackPreferencesRepository
.getMediaPreferences(currentMedia.preferenceMediaId.toString())
.firstOrNull()
?: return
// Apply audio preference // Apply audio preference
preferences.audioPreference?.let { audioPreference -> preferences.audioPreference?.let { audioPreference ->
@@ -339,7 +345,9 @@ class PlayerManager @Inject constructor(
currentTrackState.audioTracks, currentTrackState.audioTracks,
audioPreference audioPreference
) )
matchedAudio?.let { selectTrack(it) } if (matchedAudio != null && matchedAudio.id != currentTrackState.selectedAudioTrackId) {
applyTrackSelection(matchedAudio)
}
} }
// Apply subtitle preference // Apply subtitle preference
@@ -348,15 +356,17 @@ class PlayerManager @Inject constructor(
currentTrackState.textTracks, currentTrackState.textTracks,
subtitlePreference subtitlePreference
) )
matchedSubtitle?.let { selectTrack(it) } if (matchedSubtitle != null && matchedSubtitle.id != currentTrackState.selectedTextTrackId) {
applyTrackSelection(matchedSubtitle)
}
} }
} }
private suspend fun saveTrackPreference(option: TrackOption, mediaId: UUID) { private suspend fun saveTrackPreference(option: TrackOption) {
val preferenceMediaId = when (currentPlayableMedia.firstOrNull()) { val preferenceMediaId = currentPlayableMedia.firstOrNull()
is PlayableMedia.Episode -> seriesIdLookUpUseCase(mediaId) ?: mediaId ?.preferenceMediaId
else -> mediaId ?.toString()
}.toString() ?: return
when (option.type) { when (option.type) {
TrackType.AUDIO -> { TrackType.AUDIO -> {

View File

@@ -48,11 +48,16 @@ class DefaultPlayableMediaRepository @Inject constructor(
val mediaItem = getMediaItem(baseItem, playbackDecision) val mediaItem = getMediaItem(baseItem, playbackDecision)
val resumePositionMs = calculateResumePosition(baseItem, playbackDecision.mediaSource) val resumePositionMs = calculateResumePosition(baseItem, playbackDecision.mediaSource)
val mediaTrackPreferences = trackPreferencesRepository.getMediaPreferences(baseItem.parentId.toString()).first() val preferenceMediaId = when (baseItem.type) {
BaseItemKind.EPISODE -> baseItem.seriesId ?: mediaId
else -> mediaId
}
val mediaTrackPreferences = trackPreferencesRepository.getMediaPreferences(preferenceMediaId.toString()).first()
val mediaSegments = getMediaSegments(mediaId) val mediaSegments = getMediaSegments(mediaId)
when (baseItem.type) { when (baseItem.type) {
BaseItemKind.MOVIE -> PlayableMedia.Movie( BaseItemKind.MOVIE -> PlayableMedia.Movie(
id = mediaId, id = mediaId,
preferenceMediaId = preferenceMediaId,
mediaItem = mediaItem, mediaItem = mediaItem,
resumePositionMs = resumePositionMs ?: 0L, resumePositionMs = resumePositionMs ?: 0L,
preferences = mediaTrackPreferences, preferences = mediaTrackPreferences,
@@ -60,6 +65,7 @@ class DefaultPlayableMediaRepository @Inject constructor(
) )
BaseItemKind.SERIES -> PlayableMedia.Series( BaseItemKind.SERIES -> PlayableMedia.Series(
id = mediaId, id = mediaId,
preferenceMediaId = preferenceMediaId,
mediaItem = mediaItem, mediaItem = mediaItem,
resumePositionMs = resumePositionMs ?: 0L, resumePositionMs = resumePositionMs ?: 0L,
preferences = mediaTrackPreferences, preferences = mediaTrackPreferences,
@@ -67,6 +73,7 @@ class DefaultPlayableMediaRepository @Inject constructor(
) )
BaseItemKind.EPISODE -> PlayableMedia.Episode( BaseItemKind.EPISODE -> PlayableMedia.Episode(
id = mediaId, id = mediaId,
preferenceMediaId = preferenceMediaId,
mediaItem = mediaItem, mediaItem = mediaItem,
resumePositionMs = resumePositionMs ?: 0L, resumePositionMs = resumePositionMs ?: 0L,
preferences = mediaTrackPreferences, preferences = mediaTrackPreferences,