This commit is contained in:
6ip 2026-07-23 18:57:09 -04:00 committed by GitHub
commit ecdeb29cee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 78 additions and 6 deletions

View file

@ -38,6 +38,7 @@ data class MetaDetails(
val trailers: List<MetaTrailer> = emptyList(),
val links: List<MetaLink> = emptyList(),
val videos: List<MetaVideo> = emptyList(),
val customSeasons: List<MetaSeason> = emptyList(),
)
enum class MoreLikeThisSource {
@ -82,6 +83,11 @@ data class MetaLink(
val url: String,
)
data class MetaSeason(
val season: Int,
val poster: String? = null,
)
data class MetaVideo(
val id: String,
val title: String,

View file

@ -55,6 +55,7 @@ internal object MetaDetailsParser {
trailers = meta.trailers(),
links = links,
videos = meta.videos(),
customSeasons = meta.customSeasons(),
)
}
@ -219,6 +220,16 @@ internal object MetaDetailsParser {
return merged.values.toList()
}
private fun JsonObject.customSeasons(): List<MetaSeason> =
array("seasons").mapNotNull { element ->
val obj = element as? JsonObject ?: return@mapNotNull null
val season = obj.int("season") ?: return@mapNotNull null
MetaSeason(
season = season,
poster = obj.string("poster") ?: obj.string("poster_path"),
)
}
private fun JsonObject.videos(): List<MetaVideo> =
array("videos").mapNotNull { element ->
val video = element as? JsonObject ?: return@mapNotNull null

View file

@ -189,9 +189,10 @@ fun DetailSeriesContent(
) {
if (seasons.size > 1) {
val hasSeasonPosters = seasons.any { season ->
groupedEpisodes[season]
.orEmpty()
.any { !it.seasonPoster.isNullOrBlank() }
meta.customSeasons.any { it.season == season && !it.poster.isNullOrBlank() } ||
groupedEpisodes[season]
.orEmpty()
.any { !it.seasonPoster.isNullOrBlank() }
}
Column(
modifier = Modifier.animateContentSize(animationSpec = tween(280)),
@ -495,9 +496,11 @@ private fun SeasonPosterScrollRow(
items(seasons, key = { season -> season }) { season ->
SeasonPosterButton(
label = season.label(),
imageUrl = groupedEpisodes[season]
.orEmpty()
.firstNotNullOfOrNull { episode -> episode.seasonPoster }
imageUrl = meta.customSeasons.find { it.season == season }?.poster
?.takeIf { it.isNotBlank() }
?: groupedEpisodes[season]
.orEmpty()
.firstNotNullOfOrNull { episode -> episode.seasonPoster }
?: meta.poster
?: meta.background,
isSelected = season == currentSeason,

View file

@ -0,0 +1,52 @@
package com.nuvio.app.features.details
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class MetaDetailsParserSeasonsTest {
@Test
fun `parse reads custom seasons with poster and poster_path fallback`() {
val result = MetaDetailsParser.parse(
"""
{
"meta": {
"id": "custom:show",
"type": "series",
"name": "Show",
"seasons": [
{ "season": 1, "poster": "https://example.com/s1.jpg" },
{ "season": 2, "poster_path": "https://example.com/s2.jpg" },
{ "poster": "https://example.com/orphan.jpg" }
]
}
}
""".trimIndent(),
)
// The entry without a season number is skipped.
assertEquals(2, result.customSeasons.size)
assertEquals(1, result.customSeasons[0].season)
assertEquals("https://example.com/s1.jpg", result.customSeasons[0].poster)
assertEquals(2, result.customSeasons[1].season)
assertEquals("https://example.com/s2.jpg", result.customSeasons[1].poster)
}
@Test
fun `parse defaults custom seasons to empty when absent`() {
val result = MetaDetailsParser.parse(
"""
{
"meta": {
"id": "custom:show",
"type": "series",
"name": "Show"
}
}
""".trimIndent(),
)
assertTrue(result.customSeasons.isEmpty())
}
}