Fix EPG showing literal null between title and category on Android TV.

Treat org.json optString JSON-null as missing when parsing programme fields.
This commit is contained in:
Jos Vooges | STH 2026-09-15 20:55:24 +02:00
parent 940470a97d
commit bbb57baf81
2 changed files with 21 additions and 13 deletions

View file

@ -603,19 +603,27 @@ class ApiClient(
} }
private fun JSONObject.toEpgProgram(): EpgProgram? { private fun JSONObject.toEpgProgram(): EpgProgram? {
val title = optString("title").ifBlank { return null } val title = optClean("title") ?: return null
return EpgProgram( return EpgProgram(
title = title, title = title,
subTitle = optString("subTitle").ifBlank { null }, subTitle = optClean("subTitle"),
description = optString("description").ifBlank { null }, description = optClean("description"),
imageUrl = optString("imageUrl").ifBlank { null }, imageUrl = optClean("imageUrl"),
category = optString("category").ifBlank { null }, category = optClean("category"),
episode = optString("episode").ifBlank { null }, episode = optClean("episode"),
start = optString("start").ifBlank { null }, start = optClean("start"),
end = optString("end").ifBlank { null }, end = optClean("end"),
) )
} }
/** org.json optString geeft bij JSON null de literal "null" — die negeren we. */
private fun JSONObject.optClean(key: String): String? {
if (!has(key) || isNull(key)) return null
val raw = optString(key, "").trim()
if (raw.isEmpty() || raw.equals("null", ignoreCase = true)) return null
return raw
}
private fun authed(url: String): Request.Builder { private fun authed(url: String): Request.Builder {
val b = Request.Builder().url(url) val b = Request.Builder().url(url)
val t = token val t = token

View file

@ -847,7 +847,7 @@ private fun RichNowBlock(program: EpgProgram, isLive: Boolean) {
formatEpgTime(program.start, program.end)?.let { time -> formatEpgTime(program.start, program.end)?.let { time ->
Text(time, color = McColors.TextDim, fontSize = 12.sp) Text(time, color = McColors.TextDim, fontSize = 12.sp)
} }
program.episode?.takeIf { it.isNotBlank() }?.let { program.episode?.takeIf { it.isNotBlank() && !it.equals("null", ignoreCase = true) }?.let {
Text(it, color = Color(0xFF888888), fontSize = 11.sp) Text(it, color = Color(0xFF888888), fontSize = 11.sp)
} }
} }
@ -860,10 +860,10 @@ private fun RichNowBlock(program: EpgProgram, isLive: Boolean) {
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
lineHeight = 20.sp, lineHeight = 20.sp,
) )
program.subTitle?.takeIf { it.isNotBlank() }?.let { program.subTitle?.takeIf { it.isNotBlank() && !it.equals("null", ignoreCase = true) }?.let {
Text(it, color = Color(0xFFAAAAAA), fontSize = 12.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) Text(it, color = Color(0xFFAAAAAA), fontSize = 12.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
} }
program.category?.takeIf { it.isNotBlank() }?.let { program.category?.takeIf { it.isNotBlank() && !it.equals("null", ignoreCase = true) }?.let {
Text(it, color = Color(0xFF666666), fontSize = 11.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) Text(it, color = Color(0xFF666666), fontSize = 11.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)
} }
} }
@ -919,8 +919,8 @@ private fun ScheduleRow(program: EpgProgram, isNow: Boolean) {
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
val meta = listOfNotNull( val meta = listOfNotNull(
program.episode, program.episode?.takeIf { it.isNotBlank() && !it.equals("null", ignoreCase = true) },
program.subTitle?.takeIf { it.isNotBlank() }, program.subTitle?.takeIf { it.isNotBlank() && !it.equals("null", ignoreCase = true) },
).joinToString(" · ") ).joinToString(" · ")
if (meta.isNotBlank()) { if (meta.isNotBlank()) {
Text(meta, color = Color(0xFF666666), fontSize = 11.sp, maxLines = 1, overflow = TextOverflow.Ellipsis) Text(meta, color = Color(0xFF666666), fontSize = 11.sp, maxLines = 1, overflow = TextOverflow.Ellipsis)