Parse by row

This commit is contained in:
Damontecres 2026-01-25 01:32:14 -05:00
parent 668a3960f3
commit f58b371698
No known key found for this signature in database
3 changed files with 67 additions and 17 deletions

View file

@ -34,7 +34,7 @@ sealed interface HomeRowConfig {
@SerialName("ContinueWatching") @SerialName("ContinueWatching")
data class ContinueWatching( data class ContinueWatching(
override val id: Int, override val id: Int,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : HomeRowConfig { ) : HomeRowConfig {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): ContinueWatching = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): ContinueWatching = this.copy(viewOptions = viewOptions)
} }
@ -46,7 +46,7 @@ sealed interface HomeRowConfig {
@SerialName("NextUp") @SerialName("NextUp")
data class NextUp( data class NextUp(
override val id: Int, override val id: Int,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : HomeRowConfig { ) : HomeRowConfig {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): NextUp = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): NextUp = this.copy(viewOptions = viewOptions)
} }
@ -58,7 +58,7 @@ sealed interface HomeRowConfig {
@SerialName("ContinueWatchingCombined") @SerialName("ContinueWatchingCombined")
data class ContinueWatchingCombined( data class ContinueWatchingCombined(
override val id: Int, override val id: Int,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : HomeRowConfig { ) : HomeRowConfig {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): ContinueWatchingCombined = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): ContinueWatchingCombined = this.copy(viewOptions = viewOptions)
} }
@ -71,7 +71,7 @@ sealed interface HomeRowConfig {
data class RecentlyAdded( data class RecentlyAdded(
override val id: Int, override val id: Int,
val parentId: UUID, val parentId: UUID,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : HomeRowConfig { ) : HomeRowConfig {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): RecentlyAdded = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): RecentlyAdded = this.copy(viewOptions = viewOptions)
} }
@ -84,7 +84,7 @@ sealed interface HomeRowConfig {
data class RecentlyReleased( data class RecentlyReleased(
override val id: Int, override val id: Int,
val parentId: UUID, val parentId: UUID,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : HomeRowConfig { ) : HomeRowConfig {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): RecentlyReleased = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): RecentlyReleased = this.copy(viewOptions = viewOptions)
} }
@ -116,7 +116,7 @@ sealed interface HomeRowConfig {
val parentId: UUID, val parentId: UUID,
val recursive: Boolean, val recursive: Boolean,
val sort: SortAndDirection? = null, val sort: SortAndDirection? = null,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : HomeRowConfig { ) : HomeRowConfig {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): ByParent = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): ByParent = this.copy(viewOptions = viewOptions)
} }
@ -130,7 +130,7 @@ sealed interface HomeRowConfig {
override val id: Int, override val id: Int,
val name: String, val name: String,
val getItems: GetItemsRequest, val getItems: GetItemsRequest,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) : HomeRowConfig { ) : HomeRowConfig {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): GetItems = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): GetItems = this.copy(viewOptions = viewOptions)
} }

View file

@ -7,7 +7,6 @@ import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomePageSettings
import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfig
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
import com.github.damontecres.wholphin.data.model.SUPPORTED_HOME_PAGE_SETTINGS_VERSION
import com.github.damontecres.wholphin.preferences.HomePagePreferences import com.github.damontecres.wholphin.preferences.HomePagePreferences
import com.github.damontecres.wholphin.ui.DefaultItemFields import com.github.damontecres.wholphin.ui.DefaultItemFields
import com.github.damontecres.wholphin.ui.SlimItemFields import com.github.damontecres.wholphin.ui.SlimItemFields
@ -24,8 +23,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToStream import kotlinx.serialization.json.encodeToStream
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi
import org.jellyfin.sdk.api.client.extensions.userLibraryApi import org.jellyfin.sdk.api.client.extensions.userLibraryApi
@ -85,9 +87,8 @@ class HomeSettingsService
): HomePageSettings? { ): HomePageSettings? {
val current = getDisplayPreferences(userId, displayPreferencesId) val current = getDisplayPreferences(userId, displayPreferencesId)
return current.customPrefs[DISPLAY_PREF_ID]?.let { return current.customPrefs[DISPLAY_PREF_ID]?.let {
Json val jsonElement = jsonParser.parseToJsonElement(it)
.decodeFromString<HomePageSettings>(it) decode(jsonElement)
.takeIf { it.version <= SUPPORTED_HOME_PAGE_SETTINGS_VERSION }
} }
} }
@ -120,16 +121,30 @@ class HomeSettingsService
val dir = File(context.filesDir, CUSTOM_PREF_ID) val dir = File(context.filesDir, CUSTOM_PREF_ID)
val file = File(dir, filename(userId)) val file = File(dir, filename(userId))
return if (file.exists()) { return if (file.exists()) {
file.inputStream().use { val fileContents = file.readText()
jsonParser val jsonElement = jsonParser.parseToJsonElement(fileContents)
.decodeFromStream<HomePageSettings>(it) decode(jsonElement)
.takeIf { it.version <= SUPPORTED_HOME_PAGE_SETTINGS_VERSION }
}
} else { } else {
null null
} }
} }
fun decode(element: JsonElement): HomePageSettings {
val rowsElement = element.jsonObject["rows"]?.jsonArray
val rows =
rowsElement
?.mapNotNull { row ->
try {
jsonParser.decodeFromJsonElement<HomeRowConfig>(row)
} catch (ex: Exception) {
Timber.w(ex, "Unknown row %s", row)
// TODO maybe use placeholder instead of null?
null
}
}.orEmpty()
return HomePageSettings(rows)
}
suspend fun updateCurrent(userId: UUID) { suspend fun updateCurrent(userId: UUID) {
Timber.v("Getting setting for %s", userId) Timber.v("Getting setting for %s", userId)
// User local then server/remote otherwise create a default // User local then server/remote otherwise create a default

View file

@ -3,9 +3,11 @@ package com.github.damontecres.wholphin.test
import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfig
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
import com.github.damontecres.wholphin.preferences.PrefContentScale import com.github.damontecres.wholphin.preferences.PrefContentScale
import com.github.damontecres.wholphin.services.HomeSettingsService
import com.github.damontecres.wholphin.ui.AspectRatio import com.github.damontecres.wholphin.ui.AspectRatio
import com.github.damontecres.wholphin.ui.components.ViewOptionImageType import com.github.damontecres.wholphin.ui.components.ViewOptionImageType
import com.github.damontecres.wholphin.ui.data.SortAndDirection import com.github.damontecres.wholphin.ui.data.SortAndDirection
import io.mockk.mockk
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.BaseItemKind
@ -112,4 +114,37 @@ class TestHomeRowSamples {
println(string) println(string)
json.decodeFromString<List<HomeRowConfig>>(string) json.decodeFromString<List<HomeRowConfig>>(string)
} }
@Test
fun test() {
val service =
HomeSettingsService(
context = mockk(),
api = mockk(),
userPreferencesService = mockk(),
navDrawerItemRepository = mockk(),
latestNextUpService = mockk(),
imageUrlService = mockk(),
)
val str = """{
"type": "HomePageSettings",
"version": 1,
"rows": [
{
"type": "RecentlyAdded",
"id": 0,
"parentId": "1dd1c2fd-2e1b-48e4-ba94-17a2350fe9cf"
},
{
"type": "Does not exist",
"viewOptions": {}
}
]
}"""
val jsonElement = service.jsonParser.parseToJsonElement(str)
val settings = service.decode(jsonElement)
Assert.assertEquals(1, settings.rows.size)
}
} }