mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +02:00
WIP live tv home rows
This commit is contained in:
parent
ccb79257fd
commit
9cd3e7df4e
3 changed files with 193 additions and 12 deletions
|
|
@ -114,6 +114,28 @@ sealed interface HomeRowConfig {
|
|||
override fun updateViewOptions(viewOptions: HomeRowViewOptions): Favorite = this.copy(viewOptions = viewOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("Recordings")
|
||||
data class Recordings(
|
||||
override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
|
||||
) : HomeRowConfig {
|
||||
override fun updateViewOptions(viewOptions: HomeRowViewOptions): Recordings = this.copy(viewOptions = viewOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Serializable
|
||||
@SerialName("TvPrograms")
|
||||
data class TvPrograms(
|
||||
override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
|
||||
) : HomeRowConfig {
|
||||
override fun updateViewOptions(viewOptions: HomeRowViewOptions): TvPrograms = this.copy(viewOptions = viewOptions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch by parent ID such as a library, collection, or playlist with optional simple sorting
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.github.damontecres.wholphin.data.NavDrawerItemRepository
|
|||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.data.model.HomePageSettings
|
||||
import com.github.damontecres.wholphin.data.model.HomeRowConfig
|
||||
import com.github.damontecres.wholphin.preferences.DefaultUserConfiguration
|
||||
import com.github.damontecres.wholphin.preferences.HomePagePreferences
|
||||
import com.github.damontecres.wholphin.ui.DefaultItemFields
|
||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||
|
|
@ -18,6 +19,7 @@ import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
|||
import com.github.damontecres.wholphin.util.GetPersonsHandler
|
||||
import com.github.damontecres.wholphin.util.HomeRowLoadingState
|
||||
import com.github.damontecres.wholphin.util.HomeRowLoadingState.Success
|
||||
import com.github.damontecres.wholphin.util.supportedHomeCollectionTypes
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -31,7 +33,9 @@ import kotlinx.serialization.json.jsonArray
|
|||
import kotlinx.serialization.json.jsonObject
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi
|
||||
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.model.UUID
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.ImageType
|
||||
|
|
@ -42,6 +46,7 @@ import org.jellyfin.sdk.model.api.request.GetGenresRequest
|
|||
import org.jellyfin.sdk.model.api.request.GetItemsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetPersonsRequest
|
||||
import org.jellyfin.sdk.model.api.request.GetRecordingsRequest
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
|
@ -58,10 +63,12 @@ class HomeSettingsService
|
|||
private val latestNextUpService: LatestNextUpService,
|
||||
private val imageUrlService: ImageUrlService,
|
||||
) {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
val jsonParser =
|
||||
Json {
|
||||
isLenient = true
|
||||
ignoreUnknownKeys = true
|
||||
allowTrailingComma = true
|
||||
}
|
||||
|
||||
val currentSettings = MutableStateFlow(HomePageResolvedSettings.EMPTY)
|
||||
|
|
@ -201,18 +208,18 @@ class HomeSettingsService
|
|||
Timber.w(ex, "Error loading remote settings")
|
||||
null
|
||||
}
|
||||
val resolvedSettings =
|
||||
if (settings != null) {
|
||||
Timber.v("Found settings")
|
||||
// Resolve
|
||||
val resolvedRows =
|
||||
settings.rows.mapIndexed { index, config ->
|
||||
resolve(index, config)
|
||||
}
|
||||
HomePageResolvedSettings(resolvedRows)
|
||||
} else {
|
||||
createDefault(userId)
|
||||
}
|
||||
val resolvedSettings = parseFromWebConfig(userId)!!
|
||||
if (settings != null) {
|
||||
Timber.v("Found settings")
|
||||
// Resolve
|
||||
val resolvedRows =
|
||||
settings.rows.mapIndexed { index, config ->
|
||||
resolve(index, config)
|
||||
}
|
||||
HomePageResolvedSettings(resolvedRows)
|
||||
} else {
|
||||
createDefault(userId)
|
||||
}
|
||||
|
||||
currentSettings.update { resolvedSettings }
|
||||
}
|
||||
|
|
@ -275,6 +282,112 @@ class HomeSettingsService
|
|||
return HomePageResolvedSettings(rowConfig)
|
||||
}
|
||||
|
||||
suspend fun parseFromWebConfig(userId: UUID): HomePageResolvedSettings? {
|
||||
val customPrefs =
|
||||
api.displayPreferencesApi
|
||||
.getDisplayPreferences(
|
||||
displayPreferencesId = "usersettings",
|
||||
userId = userId,
|
||||
client = "emby",
|
||||
).content.customPrefs
|
||||
val userDto by api.userApi.getUserById(userId)
|
||||
val config = userDto.configuration ?: DefaultUserConfiguration
|
||||
val libraries =
|
||||
api.userViewsApi
|
||||
.getUserViews(userId = userId)
|
||||
.content.items
|
||||
.filter {
|
||||
it.collectionType in supportedHomeCollectionTypes &&
|
||||
it.id !in config.latestItemsExcludes
|
||||
}
|
||||
|
||||
return if (customPrefs.isNotEmpty()) {
|
||||
var id = 0
|
||||
val rowConfigs =
|
||||
(0..9)
|
||||
.mapNotNull { idx ->
|
||||
val sectionType =
|
||||
HomeSectionType.fromString(customPrefs["homesection$idx"]?.lowercase())
|
||||
Timber.v(
|
||||
"sectionType=$sectionType, %s",
|
||||
customPrefs["homesection$idx"]?.lowercase(),
|
||||
)
|
||||
val config =
|
||||
when (sectionType) {
|
||||
HomeSectionType.ACTIVE_RECORDINGS -> {
|
||||
// GetRecordingsRequest
|
||||
TODO()
|
||||
}
|
||||
|
||||
HomeSectionType.RESUME -> {
|
||||
HomeRowConfigDisplay(
|
||||
id = id++,
|
||||
title = context.getString(R.string.continue_watching),
|
||||
config = HomeRowConfig.ContinueWatching(),
|
||||
)
|
||||
}
|
||||
|
||||
HomeSectionType.NEXT_UP -> {
|
||||
HomeRowConfigDisplay(
|
||||
id = id++,
|
||||
title = context.getString(R.string.next_up),
|
||||
config = HomeRowConfig.NextUp(),
|
||||
)
|
||||
}
|
||||
|
||||
HomeSectionType.LIVE_TV -> {
|
||||
if (userDto.policy?.enableLiveTvAccess == true) {
|
||||
// GetRecommendedProgramsRequest
|
||||
TODO()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
HomeSectionType.LATEST_MEDIA -> {
|
||||
// Handled below
|
||||
null
|
||||
}
|
||||
|
||||
// Unsupported
|
||||
HomeSectionType.RESUME_AUDIO,
|
||||
HomeSectionType.RESUME_BOOK,
|
||||
-> {
|
||||
null
|
||||
}
|
||||
|
||||
HomeSectionType.SMALL_LIBRARY_TILES,
|
||||
HomeSectionType.LIBRARY_BUTTONS,
|
||||
HomeSectionType.NONE,
|
||||
null,
|
||||
-> {
|
||||
null
|
||||
}
|
||||
}
|
||||
if (sectionType == HomeSectionType.LATEST_MEDIA) {
|
||||
libraries.map {
|
||||
HomeRowConfigDisplay(
|
||||
id = id++,
|
||||
title =
|
||||
context.getString(
|
||||
R.string.recently_added_in,
|
||||
it.name ?: "",
|
||||
),
|
||||
config = HomeRowConfig.RecentlyAdded(it.id),
|
||||
)
|
||||
}
|
||||
} else if (config != null) {
|
||||
listOf(config)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.flatten()
|
||||
HomePageResolvedSettings(rowConfigs)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a [HomeRowConfig] into [HomeRowConfigDisplay] for UI purposes
|
||||
*/
|
||||
|
|
@ -363,6 +476,14 @@ class HomeSettingsService
|
|||
val name = context.getString(R.string.favorites) // TODO "Favorite <type>"
|
||||
HomeRowConfigDisplay(id, name, config)
|
||||
}
|
||||
|
||||
is HomeRowConfig.Recordings -> {
|
||||
TODO()
|
||||
}
|
||||
|
||||
is HomeRowConfig.TvPrograms -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -630,6 +751,15 @@ class HomeSettingsService
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
is HomeRowConfig.Recordings -> {
|
||||
GetRecordingsRequest()
|
||||
TODO()
|
||||
}
|
||||
|
||||
is HomeRowConfig.TvPrograms -> {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
@ -659,3 +789,24 @@ data class HomePageResolvedSettings(
|
|||
val EMPTY = HomePageResolvedSettings(listOf())
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/jellyfin/jellyfin/blob/v10.11.6/src/Jellyfin.Database/Jellyfin.Database.Implementations/Enums/HomeSectionType.cs
|
||||
enum class HomeSectionType(
|
||||
val serialName: String,
|
||||
) {
|
||||
NONE("none"),
|
||||
SMALL_LIBRARY_TILES("smalllibrarytitles"),
|
||||
LIBRARY_BUTTONS("librarybuttons"),
|
||||
ACTIVE_RECORDINGS("activerecordings"),
|
||||
RESUME("resume"),
|
||||
RESUME_AUDIO("resumeaudio"),
|
||||
LATEST_MEDIA("latestmedia"),
|
||||
NEXT_UP("nextup"),
|
||||
LIVE_TV("livetv"),
|
||||
RESUME_BOOK("resumebook"),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromString(homeKey: String?) = homeKey?.let { entries.firstOrNull { it.serialName == homeKey } }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@ val supportedCollectionTypes =
|
|||
null, // Mixed
|
||||
)
|
||||
|
||||
val supportedHomeCollectionTypes =
|
||||
setOf(
|
||||
CollectionType.MOVIES,
|
||||
CollectionType.TVSHOWS,
|
||||
CollectionType.HOMEVIDEOS,
|
||||
null, // Mixed
|
||||
)
|
||||
|
||||
val supportedPlayableTypes =
|
||||
setOf(
|
||||
BaseItemKind.MOVIE,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue