diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsModels.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsModels.kt index 0e55fdc06..035aa7436 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsModels.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsModels.kt @@ -9,6 +9,7 @@ data class MetaDetails( val logo: String? = null, val description: String? = null, val releaseInfo: String? = null, + val status: String? = null, val imdbRating: String? = null, val runtime: String? = null, val genres: List = emptyList(), @@ -18,6 +19,7 @@ data class MetaDetails( val awards: String? = null, val language: String? = null, val website: String? = null, + val hasScheduledVideos: Boolean = false, val links: List = emptyList(), val videos: List = emptyList(), ) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsParser.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsParser.kt index 0a99d26e5..7d3b74e2b 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsParser.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/MetaDetailsParser.kt @@ -4,6 +4,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.booleanOrNull import kotlinx.serialization.json.contentOrNull import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.jsonObject @@ -26,6 +27,7 @@ internal object MetaDetailsParser { logo = meta.string("logo"), description = meta.string("description"), releaseInfo = meta.string("releaseInfo"), + status = meta.string("status"), imdbRating = meta.string("imdbRating"), runtime = meta.string("runtime"), genres = meta.stringList("genres"), @@ -35,6 +37,7 @@ internal object MetaDetailsParser { awards = meta.string("awards"), language = meta.string("language"), website = meta.string("website"), + hasScheduledVideos = meta.behaviorHints().boolean("hasScheduledVideos") == true, links = links, videos = meta.videos(), ) @@ -77,6 +80,12 @@ internal object MetaDetailsParser { private fun JsonObject.int(name: String): Int? = this[name]?.jsonPrimitive?.intOrNull + private fun JsonObject.boolean(name: String): Boolean? = + this[name]?.jsonPrimitive?.booleanOrNull + + private fun JsonObject.behaviorHints(): JsonObject = + this["behaviorHints"] as? JsonObject ?: JsonObject(emptyMap()) + private fun JsonObject.directors(links: List): List { val appExtras = this["app_extras"] as? JsonObject val topLevel = stringListOrCsv("director") diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailSeriesContent.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailSeriesContent.kt index 4f4d7942e..4ca4621d9 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailSeriesContent.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/details/components/DetailSeriesContent.kt @@ -57,6 +57,27 @@ fun DetailSeriesContent( progressByVideoId: Map = emptyMap(), onEpisodeClick: ((MetaVideo) -> Unit)? = null, ) { + if (meta.type != "series") return + + if (meta.videos.isEmpty()) { + DetailSection( + title = "Episodes", + modifier = modifier, + ) { + Text( + text = when { + meta.status.equals("Not yet aired", ignoreCase = true) || meta.hasScheduledVideos -> + "Episodes have not been published by this addon yet." + else -> + "This addon did not provide episode metadata for this series." + }, + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + return + } + val groupedEpisodes = remember(meta.videos) { log.d { "videos count=${meta.videos.size}, type=${meta.type}" } val withSeasonOrEp = meta.videos.filter { it.season != null || it.episode != null } @@ -69,7 +90,19 @@ fun DetailSeriesContent( .groupBy { normalizeSeasonNumber(it.season) } } - if (groupedEpisodes.isEmpty()) return + if (groupedEpisodes.isEmpty()) { + DetailSection( + title = "Episodes", + modifier = modifier, + ) { + Text( + text = "This addon returned videos for the series, but none included season or episode numbers.", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + return + } val seasons = groupedEpisodes.keys.sortedBy(::seasonSortKey) val defaultSeason = seasons.first()