mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
feat: add artwork thumbnails to player queue
- Inject UserSessionRepository into MediaRepository to access server URL - Build artwork URLs using JellyfinImageHelper for both initial and next-up episodes - Add artworkUrl parameter to MediaItem metadata via setArtworkUri() - Fix PlayerQueuePanel thumbnail display with proper 4:3 aspect ratio - Increase next-up queue count from 2 to 5 episodes
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
package hu.bbara.purefin.player.data
|
package hu.bbara.purefin.player.data
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.MediaMetadata
|
import androidx.media3.common.MediaMetadata
|
||||||
import dagger.hilt.android.scopes.ViewModelScoped
|
import dagger.hilt.android.scopes.ViewModelScoped
|
||||||
@@ -9,10 +8,16 @@ import org.jellyfin.sdk.model.api.BaseItemDto
|
|||||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import hu.bbara.purefin.image.JellyfinImageHelper
|
||||||
|
import hu.bbara.purefin.session.UserSessionRepository
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import org.jellyfin.sdk.model.api.ImageType
|
||||||
|
|
||||||
@ViewModelScoped
|
@ViewModelScoped
|
||||||
class MediaRepository @Inject constructor(
|
class MediaRepository @Inject constructor(
|
||||||
private val jellyfinApiClient: JellyfinApiClient
|
private val jellyfinApiClient: JellyfinApiClient,
|
||||||
|
private val userSessionRepository: UserSessionRepository
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun getMediaItem(mediaId: UUID): Pair<MediaItem, Long?>? {
|
suspend fun getMediaItem(mediaId: UUID): Pair<MediaItem, Long?>? {
|
||||||
@@ -27,11 +32,15 @@ class MediaRepository @Inject constructor(
|
|||||||
// Calculate resume position
|
// Calculate resume position
|
||||||
val resumePositionMs = calculateResumePosition(baseItem, selectedMediaSource)
|
val resumePositionMs = calculateResumePosition(baseItem, selectedMediaSource)
|
||||||
|
|
||||||
|
val serverUrl = userSessionRepository.serverUrl.first()
|
||||||
|
val artworkUrl = JellyfinImageHelper.toImageUrl(serverUrl, mediaId, ImageType.PRIMARY)
|
||||||
|
|
||||||
val mediaItem = createMediaItem(
|
val mediaItem = createMediaItem(
|
||||||
mediaId = mediaId.toString(),
|
mediaId = mediaId.toString(),
|
||||||
playbackUrl = playbackUrl,
|
playbackUrl = playbackUrl,
|
||||||
title = baseItem?.name ?: selectedMediaSource.name,
|
title = baseItem?.name ?: selectedMediaSource.name!!,
|
||||||
subtitle = "S${baseItem!!.parentIndexNumber}:E${baseItem.indexNumber}"
|
subtitle = "S${baseItem!!.parentIndexNumber}:E${baseItem.indexNumber}",
|
||||||
|
artworkUrl = artworkUrl
|
||||||
)
|
)
|
||||||
|
|
||||||
return Pair(mediaItem, resumePositionMs)
|
return Pair(mediaItem, resumePositionMs)
|
||||||
@@ -61,7 +70,8 @@ class MediaRepository @Inject constructor(
|
|||||||
return if (percentage in 5.0..95.0) positionMs else null
|
return if (percentage in 5.0..95.0) positionMs else null
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getNextUpMediaItems(episodeId: UUID, existingIds: Set<String>, count: Int = 2): List<MediaItem> {
|
suspend fun getNextUpMediaItems(episodeId: UUID, existingIds: Set<String>, count: Int = 5): List<MediaItem> {
|
||||||
|
val serverUrl = userSessionRepository.serverUrl.first()
|
||||||
val episodes = jellyfinApiClient.getNextEpisodes(episodeId = episodeId, count = count)
|
val episodes = jellyfinApiClient.getNextEpisodes(episodeId = episodeId, count = count)
|
||||||
return episodes.mapNotNull { episode ->
|
return episodes.mapNotNull { episode ->
|
||||||
val id = episode.id ?: return@mapNotNull null
|
val id = episode.id ?: return@mapNotNull null
|
||||||
@@ -75,11 +85,13 @@ class MediaRepository @Inject constructor(
|
|||||||
mediaId = id,
|
mediaId = id,
|
||||||
mediaSourceId = selectedMediaSource.id
|
mediaSourceId = selectedMediaSource.id
|
||||||
) ?: return@mapNotNull null
|
) ?: return@mapNotNull null
|
||||||
|
val artworkUrl = JellyfinImageHelper.toImageUrl(serverUrl, id, ImageType.PRIMARY)
|
||||||
createMediaItem(
|
createMediaItem(
|
||||||
mediaId = stringId,
|
mediaId = stringId,
|
||||||
playbackUrl = playbackUrl,
|
playbackUrl = playbackUrl,
|
||||||
title = episode.name ?: selectedMediaSource.name,
|
title = episode.name ?: selectedMediaSource.name!!,
|
||||||
subtitle = "S${episode.parentIndexNumber}:E${episode.indexNumber}"
|
subtitle = "S${episode.parentIndexNumber}:E${episode.indexNumber}",
|
||||||
|
artworkUrl = artworkUrl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,15 +99,17 @@ class MediaRepository @Inject constructor(
|
|||||||
private fun createMediaItem(
|
private fun createMediaItem(
|
||||||
mediaId: String,
|
mediaId: String,
|
||||||
playbackUrl: String,
|
playbackUrl: String,
|
||||||
title: String?,
|
title: String,
|
||||||
subtitle: String?
|
subtitle: String?,
|
||||||
|
artworkUrl: String
|
||||||
): MediaItem {
|
): MediaItem {
|
||||||
val metadata = MediaMetadata.Builder()
|
val metadata = MediaMetadata.Builder()
|
||||||
.setTitle(title)
|
.setTitle(title)
|
||||||
.setSubtitle(subtitle)
|
.setSubtitle(subtitle)
|
||||||
|
.setArtworkUri(artworkUrl.toUri())
|
||||||
.build()
|
.build()
|
||||||
return MediaItem.Builder()
|
return MediaItem.Builder()
|
||||||
.setUri(Uri.parse(playbackUrl))
|
.setUri(playbackUrl.toUri())
|
||||||
.setMediaId(mediaId)
|
.setMediaId(mediaId)
|
||||||
.setMediaMetadata(metadata)
|
.setMediaMetadata(metadata)
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@@ -134,7 +135,9 @@ private fun QueueRow(
|
|||||||
PurefinAsyncImage(
|
PurefinAsyncImage(
|
||||||
model = artworkUrl,
|
model = artworkUrl,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.aspectRatio(4f / 3f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user