refactor: convert PlayableMedia to sealed class with specific media types

This commit is contained in:
2026-04-25 21:25:11 +02:00
parent f9eaf0cf84
commit b15453ab01
5 changed files with 139 additions and 29 deletions

View File

@@ -1,5 +1,6 @@
package hu.bbara.purefin.data.catalog
import android.util.Log
import hu.bbara.purefin.data.MediaRepository
import hu.bbara.purefin.data.UserSessionRepository
import hu.bbara.purefin.data.converter.toEpisode
@@ -18,9 +19,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.BaseItemKind
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
@@ -47,6 +50,10 @@ class InMemoryMediaRepository @Inject constructor(
override suspend fun getMovie(id: UUID): Flow<Movie?> {
if (!moviesState.value.containsKey(id)) {
jellyfinApiClient.getItemInfo(id)?.let { item ->
if (item.type != BaseItemKind.MOVIE) {
Log.d("InMemoryMediaRepository", "Item is not an movie: ${item.type}")
return flowOf(null)
}
val movie = item.toMovie(serverUrl.first())
moviesState.update { current -> current + (movie.id to movie) }
}
@@ -57,6 +64,10 @@ class InMemoryMediaRepository @Inject constructor(
override suspend fun getSeries(id: UUID): Flow<Series?> {
if (!seriesState.value.containsKey(id)) {
jellyfinApiClient.getItemInfo(id)?.let { item ->
if (item.type != BaseItemKind.SERIES) {
Log.d("InMemoryMediaRepository", "Item is not an series: ${item.type}")
return flowOf(null)
}
val series = item.toSeries(serverUrl.first())
seriesState.update { current -> current + (series.id to series) }
}
@@ -67,6 +78,10 @@ class InMemoryMediaRepository @Inject constructor(
override suspend fun getEpisode(id: UUID): Flow<Episode?> {
if (!episodesState.value.containsKey(id)) {
jellyfinApiClient.getItemInfo(id)?.let { item ->
if (item.type != BaseItemKind.EPISODE) {
Log.d("InMemoryMediaRepository", "Item is not an episode: ${item.type}")
return flowOf(null)
}
val episode = item.toEpisode(serverUrl.first())
episodesState.update { current -> current + (episode.id to episode) }
}

View File

@@ -23,6 +23,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.MediaSegmentDto
import org.jellyfin.sdk.model.api.MediaSegmentType.INTRO
import org.jellyfin.sdk.model.api.MediaSegmentType.OUTRO
@@ -49,13 +50,30 @@ class DefaultPlayableMediaRepository @Inject constructor(
val resumePositionMs = calculateResumePosition(baseItem, playbackDecision.mediaSource)
val mediaTrackPreferences = trackPreferencesRepository.getMediaPreferences(mediaId.toString()).first()
val mediaSegments = getMediaSegments(mediaId)
PlayableMedia(
id = mediaId,
mediaItem = mediaItem,
resumePositionMs = resumePositionMs?.toFloat() ?: 0f,
preferences = mediaTrackPreferences,
mediaSegments = mediaSegments
)
when (baseItem.type) {
BaseItemKind.MOVIE -> PlayableMedia.Movie(
id = mediaId,
mediaItem = mediaItem,
resumePositionMs = resumePositionMs ?: 0L,
preferences = mediaTrackPreferences,
mediaSegments = mediaSegments
)
BaseItemKind.SERIES -> PlayableMedia.Series(
id = mediaId,
mediaItem = mediaItem,
resumePositionMs = resumePositionMs ?: 0L,
preferences = mediaTrackPreferences,
mediaSegments = mediaSegments
)
BaseItemKind.EPISODE -> PlayableMedia.Episode(
id = mediaId,
mediaItem = mediaItem,
resumePositionMs = resumePositionMs ?: 0L,
preferences = mediaTrackPreferences,
mediaSegments = mediaSegments
)
else -> null
}
}
private suspend fun getMediaItem(baseItem: BaseItemDto, playbackDecision: PlaybackDecision): MediaItem = withContext(Dispatchers.IO) {