update JellyfinApiClient methods and logging

- Rename `getNextUpEpisode` to `getNextUpEpisodes` and update it to return a list of episodes with expanded request fields.
- Rename `getMediaPlaybackInfo` to `getMediaPlaybackUrl` and update its usages in `MediaRepository`.
- Simplify logging format by removing curly brace placeholders across multiple API call methods.
- Reorder `getContinueWatching` and `getLibraryContent` for better class organization.
- Remove unused `episode` import in `MediaRepository`.
This commit is contained in:
2026-01-31 21:39:42 +01:00
parent fa76517e12
commit b643988ed4
2 changed files with 48 additions and 47 deletions

View File

@@ -80,26 +80,6 @@ class JellyfinApiClient @Inject constructor(
ensureConfigured() ensureConfigured()
} }
suspend fun getContinueWatching(): List<BaseItemDto> {
if (!ensureConfigured()) {
return emptyList()
}
val userId = getUserId()
if (userId == null) {
return emptyList()
}
val getResumeItemsRequest = GetResumeItemsRequest(
userId = userId,
fields = listOf(ItemFields.CHILD_COUNT, ItemFields.PARENT_ID, ItemFields.DATE_LAST_REFRESHED),
includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.EPISODE),
enableUserData = true,
startIndex = 0,
)
val response: Response<BaseItemDtoQueryResult> = api.itemsApi.getResumeItems(getResumeItemsRequest)
Log.d("getContinueWatching response: {}", response.content.toString())
return response.content.items
}
suspend fun getLibraries(): List<BaseItemDto> { suspend fun getLibraries(): List<BaseItemDto> {
if (!ensureConfigured()) { if (!ensureConfigured()) {
return emptyList() return emptyList()
@@ -109,7 +89,7 @@ class JellyfinApiClient @Inject constructor(
presetViews = listOf(CollectionType.MOVIES, CollectionType.TVSHOWS), presetViews = listOf(CollectionType.MOVIES, CollectionType.TVSHOWS),
includeHidden = false, includeHidden = false,
) )
Log.d("getLibraries response: {}", response.content.toString()) Log.d("getLibraries", response.content.toString())
val libraries = response.content.items val libraries = response.content.items
return libraries return libraries
} }
@@ -128,10 +108,45 @@ class JellyfinApiClient @Inject constructor(
recursive = true, recursive = true,
) )
val response = api.itemsApi.getItems(getItemsRequest) val response = api.itemsApi.getItems(getItemsRequest)
Log.d("getLibraryContent response: {}", response.content.toString()) Log.d("getLibraryContent", response.content.toString())
return response.content.items return response.content.items
} }
suspend fun getContinueWatching(): List<BaseItemDto> {
if (!ensureConfigured()) {
return emptyList()
}
val userId = getUserId()
if (userId == null) {
return emptyList()
}
val getResumeItemsRequest = GetResumeItemsRequest(
userId = userId,
fields = listOf(ItemFields.CHILD_COUNT, ItemFields.PARENT_ID, ItemFields.DATE_LAST_REFRESHED),
includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.EPISODE),
enableUserData = true,
startIndex = 0,
)
val response: Response<BaseItemDtoQueryResult> = api.itemsApi.getResumeItems(getResumeItemsRequest)
Log.d("getContinueWatching", response.content.toString())
return response.content.items
}
suspend fun getNextUpEpisodes(mediaId: UUID): List<BaseItemDto> {
if (!ensureConfigured()) {
throw IllegalStateException("Not configured")
}
val getNextUpRequest = GetNextUpRequest(
userId = getUserId(),
fields = listOf(ItemFields.CHILD_COUNT, ItemFields.PARENT_ID, ItemFields.DATE_LAST_REFRESHED),
enableResumable = true,
seriesId = mediaId,
)
val result = api.tvShowsApi.getNextUp(getNextUpRequest)
Log.d("getNextUpEpisodes", result.content.toString())
return result.content.items
}
/** /**
* Fetches the latest media items from a specified library including Movie, Episode, Season. * Fetches the latest media items from a specified library including Movie, Episode, Season.
* *
@@ -149,7 +164,7 @@ class JellyfinApiClient @Inject constructor(
includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.EPISODE, BaseItemKind.SEASON), includeItemTypes = listOf(BaseItemKind.MOVIE, BaseItemKind.EPISODE, BaseItemKind.SEASON),
limit = 10 limit = 10
) )
Log.d("getLatestFromLibrary response: {}", response.content.toString()) Log.d("getLatestFromLibrary", response.content.toString())
return response.content return response.content
} }
@@ -161,7 +176,7 @@ class JellyfinApiClient @Inject constructor(
itemId = mediaId, itemId = mediaId,
userId = getUserId(), userId = getUserId(),
) )
Log.d("getItemInfo response: {}", result.content.toString()) Log.d("getItemInfo", result.content.toString())
return result.content return result.content
} }
@@ -175,7 +190,7 @@ class JellyfinApiClient @Inject constructor(
fields = listOf(ItemFields.CHILD_COUNT, ItemFields.PARENT_ID, ItemFields.DATE_LAST_REFRESHED), fields = listOf(ItemFields.CHILD_COUNT, ItemFields.PARENT_ID, ItemFields.DATE_LAST_REFRESHED),
enableUserData = true enableUserData = true
) )
Log.d("getSeasons response: {}", result.content.toString()) Log.d("getSeasons", result.content.toString())
return result.content.items return result.content.items
} }
@@ -190,23 +205,10 @@ class JellyfinApiClient @Inject constructor(
fields = listOf(ItemFields.CHILD_COUNT, ItemFields.PARENT_ID, ItemFields.DATE_LAST_REFRESHED), fields = listOf(ItemFields.CHILD_COUNT, ItemFields.PARENT_ID, ItemFields.DATE_LAST_REFRESHED),
enableUserData = true enableUserData = true
) )
Log.d("getEpisodesInSeason response: {}", result.content.toString()) Log.d("getEpisodesInSeason", result.content.toString())
return result.content.items return result.content.items
} }
suspend fun getNextUpEpisode(mediaId: UUID): BaseItemDto {
if (!ensureConfigured()) {
throw IllegalStateException("Not configured")
}
val getNextUpRequest = GetNextUpRequest(
userId = getUserId(),
seriesId = mediaId,
)
val result = api.tvShowsApi.getNextUp(getNextUpRequest)
Log.d("getNextUpEpisode response: {}", result.content.toString())
return result.content.items.first()
}
suspend fun getMediaSources(mediaId: UUID): List<MediaSourceInfo> { suspend fun getMediaSources(mediaId: UUID): List<MediaSourceInfo> {
val result = api.mediaInfoApi val result = api.mediaInfoApi
.getPostedPlaybackInfo( .getPostedPlaybackInfo(
@@ -232,7 +234,7 @@ class JellyfinApiClient @Inject constructor(
maxStreamingBitrate = 1_000_000_000, maxStreamingBitrate = 1_000_000_000,
), ),
) )
Log.d("getMediaSources result: {}", result.toString()) Log.d("getMediaSources", result.toString())
return result.content.mediaSources return result.content.mediaSources
} }
@@ -252,11 +254,11 @@ class JellyfinApiClient @Inject constructor(
) )
//Remove first element as we need only the next episodes //Remove first element as we need only the next episodes
val nextUpEpisodes = nextUpEpisodesResult.content.items.drop(1) val nextUpEpisodes = nextUpEpisodesResult.content.items.drop(1)
Log.d("getNextEpisodeMediaSources response: {}", nextUpEpisodes.toString()) Log.d("getNextEpisodes", nextUpEpisodes.toString())
return nextUpEpisodes return nextUpEpisodes
} }
suspend fun getMediaPlaybackInfo(mediaId: UUID, mediaSourceId: String? = null): String? { suspend fun getMediaPlaybackUrl(mediaId: UUID, mediaSourceId: String? = null): String? {
if (!ensureConfigured()) { if (!ensureConfigured()) {
return null return null
} }
@@ -265,7 +267,7 @@ class JellyfinApiClient @Inject constructor(
static = true, static = true,
mediaSourceId = mediaSourceId, mediaSourceId = mediaSourceId,
) )
Log.d("getMediaPlaybackInfo response: {}", response.toString()) Log.d("getMediaPlaybackUrl", response)
return response return response
} }

View File

@@ -4,10 +4,9 @@ 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
import hu.bbara.purefin.app.content.ContentMockData.episode
import hu.bbara.purefin.client.JellyfinApiClient import hu.bbara.purefin.client.JellyfinApiClient
import javax.inject.Inject
import java.util.UUID import java.util.UUID
import javax.inject.Inject
@ViewModelScoped @ViewModelScoped
class MediaRepository @Inject constructor( class MediaRepository @Inject constructor(
@@ -17,7 +16,7 @@ class MediaRepository @Inject constructor(
suspend fun getMediaItem(mediaId: UUID): MediaItem? { suspend fun getMediaItem(mediaId: UUID): MediaItem? {
val mediaSources = jellyfinApiClient.getMediaSources(mediaId) val mediaSources = jellyfinApiClient.getMediaSources(mediaId)
val selectedMediaSource = mediaSources.firstOrNull() ?: return null val selectedMediaSource = mediaSources.firstOrNull() ?: return null
val playbackUrl = jellyfinApiClient.getMediaPlaybackInfo( val playbackUrl = jellyfinApiClient.getMediaPlaybackUrl(
mediaId = mediaId, mediaId = mediaId,
mediaSourceId = selectedMediaSource.id mediaSourceId = selectedMediaSource.id
) ?: return null ) ?: return null
@@ -40,7 +39,7 @@ class MediaRepository @Inject constructor(
} }
val mediaSources = jellyfinApiClient.getMediaSources(id) val mediaSources = jellyfinApiClient.getMediaSources(id)
val selectedMediaSource = mediaSources.firstOrNull() ?: return@mapNotNull null val selectedMediaSource = mediaSources.firstOrNull() ?: return@mapNotNull null
val playbackUrl = jellyfinApiClient.getMediaPlaybackInfo( val playbackUrl = jellyfinApiClient.getMediaPlaybackUrl(
mediaId = id, mediaId = id,
mediaSourceId = selectedMediaSource.id mediaSourceId = selectedMediaSource.id
) ?: return@mapNotNull null ) ?: return@mapNotNull null