mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
feat: enhance media item retrieval to include resume position calculation
This commit is contained in:
@@ -9,11 +9,11 @@ import org.jellyfin.sdk.api.client.Response
|
||||
import org.jellyfin.sdk.api.client.extensions.authenticateUserByName
|
||||
import org.jellyfin.sdk.api.client.extensions.itemsApi
|
||||
import org.jellyfin.sdk.api.client.extensions.mediaInfoApi
|
||||
import org.jellyfin.sdk.api.client.extensions.playStateApi
|
||||
import org.jellyfin.sdk.api.client.extensions.tvShowsApi
|
||||
import org.jellyfin.sdk.api.client.extensions.userApi
|
||||
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||
import org.jellyfin.sdk.api.client.extensions.userViewsApi
|
||||
import org.jellyfin.sdk.api.client.extensions.playStateApi
|
||||
import org.jellyfin.sdk.api.client.extensions.videosApi
|
||||
import org.jellyfin.sdk.createJellyfin
|
||||
import org.jellyfin.sdk.model.ClientInfo
|
||||
@@ -24,12 +24,12 @@ import org.jellyfin.sdk.model.api.CollectionType
|
||||
import org.jellyfin.sdk.model.api.DeviceProfile
|
||||
import org.jellyfin.sdk.model.api.ItemFields
|
||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||
import org.jellyfin.sdk.model.api.PlayMethod
|
||||
import org.jellyfin.sdk.model.api.PlaybackInfoDto
|
||||
import org.jellyfin.sdk.model.api.PlaybackOrder
|
||||
import org.jellyfin.sdk.model.api.PlaybackProgressInfo
|
||||
import org.jellyfin.sdk.model.api.PlaybackStartInfo
|
||||
import org.jellyfin.sdk.model.api.PlaybackStopInfo
|
||||
import org.jellyfin.sdk.model.api.PlayMethod
|
||||
import org.jellyfin.sdk.model.api.RepeatMode
|
||||
import org.jellyfin.sdk.model.api.SubtitleDeliveryMethod
|
||||
import org.jellyfin.sdk.model.api.SubtitleProfile
|
||||
@@ -189,7 +189,7 @@ class JellyfinApiClient @Inject constructor(
|
||||
}
|
||||
val result = api.userLibraryApi.getItem(
|
||||
itemId = mediaId,
|
||||
userId = getUserId(),
|
||||
userId = getUserId()
|
||||
)
|
||||
Log.d("getItemInfo", result.content.toString())
|
||||
return result.content
|
||||
|
||||
@@ -5,6 +5,8 @@ import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.MediaMetadata
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import hu.bbara.purefin.client.JellyfinApiClient
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -13,7 +15,7 @@ class MediaRepository @Inject constructor(
|
||||
private val jellyfinApiClient: JellyfinApiClient
|
||||
) {
|
||||
|
||||
suspend fun getMediaItem(mediaId: UUID): MediaItem? {
|
||||
suspend fun getMediaItem(mediaId: UUID): Pair<MediaItem, Long?>? {
|
||||
val mediaSources = jellyfinApiClient.getMediaSources(mediaId)
|
||||
val selectedMediaSource = mediaSources.firstOrNull() ?: return null
|
||||
val playbackUrl = jellyfinApiClient.getMediaPlaybackUrl(
|
||||
@@ -21,12 +23,42 @@ class MediaRepository @Inject constructor(
|
||||
mediaSourceId = selectedMediaSource.id
|
||||
) ?: return null
|
||||
val baseItem = jellyfinApiClient.getItemInfo(mediaId)
|
||||
return createMediaItem(
|
||||
|
||||
// Calculate resume position
|
||||
val resumePositionMs = calculateResumePosition(baseItem, selectedMediaSource)
|
||||
|
||||
val mediaItem = createMediaItem(
|
||||
mediaId = mediaId.toString(),
|
||||
playbackUrl = playbackUrl,
|
||||
title = baseItem?.name ?: selectedMediaSource.name,
|
||||
subtitle = "S${baseItem!!.parentIndexNumber}:E${baseItem.indexNumber}"
|
||||
)
|
||||
|
||||
return Pair(mediaItem, resumePositionMs)
|
||||
}
|
||||
|
||||
private fun calculateResumePosition(
|
||||
baseItem: BaseItemDto?,
|
||||
mediaSource: MediaSourceInfo
|
||||
): Long? {
|
||||
val userData = baseItem?.userData ?: return null
|
||||
|
||||
// Get runtime in ticks
|
||||
val runtimeTicks = mediaSource.runTimeTicks ?: baseItem.runTimeTicks ?: 0L
|
||||
if (runtimeTicks == 0L) return null
|
||||
|
||||
// Get saved playback position from userData
|
||||
val playbackPositionTicks = userData.playbackPositionTicks ?: 0L
|
||||
if (playbackPositionTicks == 0L) return null
|
||||
|
||||
// Convert ticks to milliseconds
|
||||
val positionMs = playbackPositionTicks / 10_000
|
||||
|
||||
// Calculate percentage for threshold check
|
||||
val percentage = (playbackPositionTicks.toDouble() / runtimeTicks.toDouble()) * 100.0
|
||||
|
||||
// Apply thresholds: resume only if 5% ≤ progress ≤ 95%
|
||||
return if (percentage in 5.0..95.0) positionMs else null
|
||||
}
|
||||
|
||||
suspend fun getNextUpMediaItems(episodeId: UUID, existingIds: Set<String>, count: Int = 2): List<MediaItem> {
|
||||
|
||||
@@ -9,7 +9,6 @@ import hu.bbara.purefin.player.manager.PlayerManager
|
||||
import hu.bbara.purefin.player.manager.ProgressManager
|
||||
import hu.bbara.purefin.player.model.PlayerUiState
|
||||
import hu.bbara.purefin.player.model.TrackOption
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -18,6 +17,7 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class PlayerViewModel @Inject constructor(
|
||||
@@ -133,9 +133,15 @@ class PlayerViewModel @Inject constructor(
|
||||
return
|
||||
}
|
||||
viewModelScope.launch {
|
||||
val mediaItem = mediaRepository.getMediaItem(uuid)
|
||||
if (mediaItem != null) {
|
||||
val result = mediaRepository.getMediaItem(uuid)
|
||||
if (result != null) {
|
||||
val (mediaItem, resumePositionMs) = result
|
||||
|
||||
playerManager.play(mediaItem)
|
||||
|
||||
// Seek to resume position after play() is called
|
||||
resumePositionMs?.let { playerManager.seekTo(it) }
|
||||
|
||||
if (dataErrorMessage != null) {
|
||||
dataErrorMessage = null
|
||||
_uiState.update { it.copy(error = null) }
|
||||
|
||||
Reference in New Issue
Block a user