Add option to attempt to use first volume cover on MangaDex (#14031)
* Add option to attempt to use first volume cover on MangaDex. * Fix missing first volume covers and remove logical symbols. * Reinforce isOneShot check and reword preference.
This commit is contained in:
parent
c18a8d5860
commit
eaa7b15bae
@ -6,7 +6,7 @@ ext {
|
||||
extName = 'MangaDex'
|
||||
pkgNameSuffix = 'all.mangadex'
|
||||
extClass = '.MangaDexFactory'
|
||||
extVersionCode = 170
|
||||
extVersionCode = 171
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
@ -108,9 +108,18 @@ object MDConstants {
|
||||
return "${hasSanitizedUuidsPref}_$dexLang"
|
||||
}
|
||||
|
||||
private const val tryUsingFirstVolumeCoverPref = "tryUsingFirstVolumeCover"
|
||||
const val tryUsingFirstVolumeCoverDefault = false
|
||||
fun getTryUsingFirstVolumeCoverPrefKey(dexLang: String): String {
|
||||
return "${tryUsingFirstVolumeCoverPref}_$dexLang"
|
||||
}
|
||||
|
||||
private const val tagGroupContent = "content"
|
||||
private const val tagGroupFormat = "format"
|
||||
private const val tagGroupGenre = "genre"
|
||||
private const val tagGroupTheme = "theme"
|
||||
val tagGroupsOrder = arrayOf(tagGroupContent, tagGroupFormat, tagGroupGenre, tagGroupTheme)
|
||||
|
||||
const val tagAnthologyUuid = "51d83883-4103-437c-b4b1-731cb73d786c"
|
||||
const val tagOneShotUuid = "0234a31e-a729-4e28-9d6a-3f87c4966b9e"
|
||||
}
|
||||
|
@ -9,10 +9,13 @@ import androidx.preference.MultiSelectListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.AggregateDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.AggregateVolume
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.AtHomeDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ChapterDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ChapterListDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.CoverListDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ListDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaDataDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaListDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.RelationshipDto
|
||||
@ -26,7 +29,6 @@ import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.Headers
|
||||
@ -97,9 +99,10 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
val hasMoreResults = mangaListDto.limit + mangaListDto.offset < mangaListDto.total
|
||||
|
||||
val coverSuffix = preferences.coverQuality
|
||||
val firstVolumeCovers = fetchFirstVolumeCovers(mangaListDto.data).orEmpty()
|
||||
|
||||
val mangaList = mangaListDto.data.map { mangaDataDto ->
|
||||
val fileName = mangaDataDto.relationships
|
||||
val fileName = firstVolumeCovers[mangaDataDto.id] ?: mangaDataDto.relationships
|
||||
.firstOrNull { it.type.equals(MDConstants.coverArt, true) }
|
||||
?.attributes?.fileName
|
||||
helper.createBasicManga(mangaDataDto, fileName, coverSuffix, dexLang)
|
||||
@ -129,13 +132,14 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
val mangaRequest = GET(mangaUrl.build().toString(), headers, CacheControl.FORCE_NETWORK)
|
||||
val mangaResponse = client.newCall(mangaRequest).execute()
|
||||
val mangaListDto = mangaResponse.parseAs<MangaListDto>()
|
||||
val firstVolumeCovers = fetchFirstVolumeCovers(mangaListDto.data).orEmpty()
|
||||
|
||||
val mangaDtoMap = mangaListDto.data.associateBy({ it.id }, { it })
|
||||
|
||||
val coverSuffix = preferences.coverQuality
|
||||
|
||||
val mangaList = mangaIds.mapNotNull { mangaDtoMap[it] }.map { mangaDataDto ->
|
||||
val fileName = mangaDataDto.relationships
|
||||
val fileName = firstVolumeCovers[mangaDataDto.id] ?: mangaDataDto.relationships
|
||||
.firstOrNull { it.type.equals(MDConstants.coverArt, true) }
|
||||
?.attributes?.fileName
|
||||
helper.createBasicManga(mangaDataDto, fileName, coverSuffix, dexLang)
|
||||
@ -182,7 +186,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
.map { searchMangaListRequest(it, page) }
|
||||
|
||||
else ->
|
||||
return super.fetchSearchManga(page, query, filters)
|
||||
return super.fetchSearchManga(page, query.trim(), filters)
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,11 +296,12 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
}
|
||||
|
||||
val mangaListDto = response.parseAs<MangaListDto>()
|
||||
val firstVolumeCovers = fetchFirstVolumeCovers(mangaListDto.data).orEmpty()
|
||||
|
||||
val coverSuffix = preferences.coverQuality
|
||||
|
||||
val mangaList = mangaListDto.data.map { mangaDataDto ->
|
||||
val fileName = mangaDataDto.relationships
|
||||
val fileName = firstVolumeCovers[mangaDataDto.id] ?: mangaDataDto.relationships
|
||||
.firstOrNull { it.type.equals(MDConstants.coverArt, true) }
|
||||
?.attributes?.fileName
|
||||
helper.createBasicManga(mangaDataDto, fileName, coverSuffix, dexLang)
|
||||
@ -365,33 +370,74 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
return helper.createManga(
|
||||
manga.data,
|
||||
fetchSimpleChapterList(manga, dexLang),
|
||||
fetchFirstVolumeCover(manga),
|
||||
dexLang,
|
||||
preferences.coverQuality
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* get a quick-n-dirty list of the chapters to be used in determining the manga status.
|
||||
* uses the 'aggregate' endpoint
|
||||
* Get a quick-n-dirty list of the chapters to be used in determining the manga status.
|
||||
* Uses the 'aggregate' endpoint.
|
||||
*
|
||||
* @see MangaDexHelper.getPublicationStatus
|
||||
* @see AggregateDto
|
||||
*/
|
||||
private fun fetchSimpleChapterList(manga: MangaDto, langCode: String): List<String> {
|
||||
private fun fetchSimpleChapterList(manga: MangaDto, langCode: String): Map<String, AggregateVolume> {
|
||||
val url = "${MDConstants.apiMangaUrl}/${manga.data.id}/aggregate?translatedLanguage[]=$langCode"
|
||||
val response = client.newCall(GET(url, headers)).execute()
|
||||
val chapters: AggregateDto
|
||||
|
||||
try {
|
||||
chapters = response.parseAs()
|
||||
} catch (e: SerializationException) {
|
||||
return emptyList()
|
||||
return runCatching { response.parseAs<AggregateDto>() }
|
||||
.getOrNull()?.volumes.orEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the first volume cover if the setting is enabled.
|
||||
* Uses the 'covers' endpoint.
|
||||
*
|
||||
* @see CoverListDto
|
||||
*/
|
||||
private fun fetchFirstVolumeCover(manga: MangaDto): String? {
|
||||
return fetchFirstVolumeCovers(listOf(manga.data))?.get(manga.data.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the first volume cover if the setting is enabled.
|
||||
* Uses the 'covers' endpoint.
|
||||
*
|
||||
* @see CoverListDto
|
||||
*/
|
||||
private fun fetchFirstVolumeCovers(mangaList: List<MangaDataDto>): Map<String, String>? {
|
||||
if (!preferences.tryUsingFirstVolumeCover) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (chapters.volumes.isNullOrEmpty()) return emptyList()
|
||||
val mangaMap = mangaList.associate { it.id to it.attributes }
|
||||
.filterValues { !it.originalLanguage.isNullOrEmpty() }
|
||||
val locales = mangaList.mapNotNull { it.attributes.originalLanguage }.distinct()
|
||||
val limit = (mangaMap.size * locales.size).coerceAtMost(100)
|
||||
|
||||
return chapters.volumes.values
|
||||
.flatMap { it.chapters.values }
|
||||
.map { it.chapter }
|
||||
val apiUrl = "${MDConstants.apiUrl}/cover".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("order[volume]", "asc")
|
||||
.addQueryParameter("manga[]", mangaMap.keys)
|
||||
.addQueryParameter("locales[]", locales.toSet())
|
||||
.addQueryParameter("limit", limit.toString())
|
||||
.addQueryParameter("offset", "0")
|
||||
.toString()
|
||||
|
||||
val result = runCatching {
|
||||
client.newCall(GET(apiUrl, headers)).execute().parseAs<CoverListDto>().data
|
||||
}
|
||||
|
||||
val covers = result.getOrNull() ?: return null
|
||||
|
||||
return covers
|
||||
.groupBy { it.relationships.find { r -> r.type == MDConstants.manga }!!.id }
|
||||
.mapValues {
|
||||
it.value.find { c -> c.attributes?.locale == mangaMap[it.key]?.originalLanguage }
|
||||
}
|
||||
.filterValues { !it?.attributes?.fileName.isNullOrEmpty() }
|
||||
.mapValues { it.value!!.attributes!!.fileName!! }
|
||||
}
|
||||
|
||||
// Chapter list section
|
||||
@ -525,6 +571,21 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
}
|
||||
}
|
||||
|
||||
val tryUsingFirstVolumeCoverPref = SwitchPreferenceCompat(screen.context).apply {
|
||||
key = MDConstants.getTryUsingFirstVolumeCoverPrefKey(dexLang)
|
||||
title = helper.intl.tryUsingFirstVolumeCover
|
||||
summary = helper.intl.tryUsingFirstVolumeCoverSummary
|
||||
setDefaultValue(MDConstants.tryUsingFirstVolumeCoverDefault)
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val checkValue = newValue as Boolean
|
||||
|
||||
preferences.edit()
|
||||
.putBoolean(MDConstants.getDataSaverPreferenceKey(dexLang), checkValue)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
|
||||
val dataSaverPref = SwitchPreferenceCompat(screen.context).apply {
|
||||
key = MDConstants.getDataSaverPreferenceKey(dexLang)
|
||||
title = helper.intl.dataSaver
|
||||
@ -636,6 +697,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
}
|
||||
|
||||
screen.addPreference(coverQualityPref)
|
||||
screen.addPreference(tryUsingFirstVolumeCoverPref)
|
||||
screen.addPreference(dataSaverPref)
|
||||
screen.addPreference(standardHttpsPortPref)
|
||||
screen.addPreference(contentRatingPref)
|
||||
@ -680,6 +742,12 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
|
||||
private val SharedPreferences.coverQuality
|
||||
get() = getString(MDConstants.getCoverQualityPreferenceKey(dexLang), "")
|
||||
|
||||
private val SharedPreferences.tryUsingFirstVolumeCover
|
||||
get() = getBoolean(
|
||||
MDConstants.getTryUsingFirstVolumeCoverPrefKey(dexLang),
|
||||
MDConstants.tryUsingFirstVolumeCoverDefault
|
||||
)
|
||||
|
||||
private val SharedPreferences.blockedGroups
|
||||
get() = getString(MDConstants.getBlockedGroupsPrefKey(dexLang), "")
|
||||
?.split(",")
|
||||
|
@ -5,18 +5,18 @@ import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.AggregateVolume
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.AtHomeDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.ChapterDataDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaAttributesDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.MangaDataDto
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.asMdMap
|
||||
import eu.kanade.tachiyomi.extension.all.mangadex.dto.toLocalizedString
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
@ -27,7 +27,7 @@ import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MangaDexHelper(private val lang: String) {
|
||||
class MangaDexHelper(lang: String) {
|
||||
|
||||
val mdFilters = MangaDexFilters()
|
||||
|
||||
@ -98,7 +98,11 @@ class MangaDexHelper(private val lang: String) {
|
||||
* Maps dex status to Tachi status.
|
||||
* Adapted from the MangaDex handler from TachiyomiSY.
|
||||
*/
|
||||
fun getPublicationStatus(attr: MangaAttributesDto, chapters: List<String>): Int {
|
||||
fun getPublicationStatus(attr: MangaAttributesDto, volumes: Map<String, AggregateVolume>): Int {
|
||||
val chaptersList = volumes.values
|
||||
.flatMap { it.chapters.values }
|
||||
.map { it.chapter }
|
||||
|
||||
val tempStatus = when (attr.status) {
|
||||
"ongoing" -> SManga.ONGOING
|
||||
"cancelled" -> SManga.CANCELLED
|
||||
@ -110,10 +114,13 @@ class MangaDexHelper(private val lang: String) {
|
||||
val publishedOrCancelled = tempStatus == SManga.PUBLISHING_FINISHED ||
|
||||
tempStatus == SManga.CANCELLED
|
||||
|
||||
return if (chapters.contains(attr.lastChapter) && publishedOrCancelled) {
|
||||
SManga.COMPLETED
|
||||
} else {
|
||||
tempStatus
|
||||
val isOneShot = attr.tags.any { it.id == MDConstants.tagOneShotUuid } &&
|
||||
attr.tags.none { it.id == MDConstants.tagAnthologyUuid }
|
||||
|
||||
return when {
|
||||
chaptersList.contains(attr.lastChapter) && publishedOrCancelled -> SManga.COMPLETED
|
||||
isOneShot && volumes["none"]?.chapters?.get("none") != null -> SManga.COMPLETED
|
||||
else -> tempStatus
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,15 +217,14 @@ class MangaDexHelper(private val lang: String) {
|
||||
): SManga {
|
||||
return SManga.create().apply {
|
||||
url = "/manga/${mangaDataDto.id}"
|
||||
val titleMap = mangaDataDto.attributes.title.asMdMap()
|
||||
val titleMap = mangaDataDto.attributes.title.toLocalizedString()
|
||||
val dirtyTitle = titleMap[lang]
|
||||
?: titleMap["en"]
|
||||
?: titleMap["ja-ro"]
|
||||
?: mangaDataDto.attributes.altTitles.jsonArray
|
||||
.find {
|
||||
val altTitle = it.asMdMap()
|
||||
(altTitle[lang] ?: altTitle["en"]) != null
|
||||
}?.asMdMap()?.values?.singleOrNull()
|
||||
?: mangaDataDto.attributes.altTitles
|
||||
.map { it.toLocalizedString() }
|
||||
.find { (it[lang] ?: it["en"]) !== null }
|
||||
?.values?.singleOrNull()
|
||||
?: titleMap["ja"] // romaji titles are sometimes ja (and are not altTitles)
|
||||
?: titleMap.values.firstOrNull() // use literally anything from title as a last resort
|
||||
title = cleanString(dirtyTitle ?: "")
|
||||
@ -237,7 +243,8 @@ class MangaDexHelper(private val lang: String) {
|
||||
*/
|
||||
fun createManga(
|
||||
mangaDataDto: MangaDataDto,
|
||||
chapters: List<String>,
|
||||
chapters: Map<String, AggregateVolume>,
|
||||
firstVolumeCover: String?,
|
||||
lang: String,
|
||||
coverSuffix: String?
|
||||
): SManga {
|
||||
@ -275,7 +282,7 @@ class MangaDexHelper(private val lang: String) {
|
||||
.mapNotNull { it.attributes!!.name }
|
||||
.distinct()
|
||||
|
||||
val coverFileName = mangaDataDto.relationships
|
||||
val coverFileName = firstVolumeCover ?: mangaDataDto.relationships
|
||||
.firstOrNull { it.type.equals(MDConstants.coverArt, true) }
|
||||
?.attributes?.fileName
|
||||
|
||||
@ -293,7 +300,7 @@ class MangaDexHelper(private val lang: String) {
|
||||
val genreList = MDConstants.tagGroupsOrder.flatMap { genresMap[it].orEmpty() } +
|
||||
nonGenres.filterNotNull()
|
||||
|
||||
val desc = attr.description.asMdMap()
|
||||
val desc = attr.description.toLocalizedString()
|
||||
|
||||
return createBasicManga(mangaDataDto, coverFileName, coverSuffix, lang).apply {
|
||||
description = cleanString(desc[lang] ?: desc["en"] ?: "")
|
||||
|
@ -96,18 +96,18 @@ class MangaDexIntl(lang: String) {
|
||||
BRAZILIAN_PORTUGUESE, PORTUGUESE ->
|
||||
"Ative para fazer requisições em somente servidores de imagem que usem a porta 443. " +
|
||||
"Isso permite com que usuários com regras mais restritas de firewall possam acessar " +
|
||||
"as imagens do MangaDex."
|
||||
"as imagens do $MANGADEX_NAME."
|
||||
SPANISH_LATAM, SPANISH ->
|
||||
"Habilite esta opción solicitar las imágenes a los servidores que usan el puerto 443. " +
|
||||
"Esto permite a los usuarios con restricciones estrictas de firewall acceder " +
|
||||
"a las imagenes en MangaDex"
|
||||
"a las imagenes en $MANGADEX_NAME"
|
||||
RUSSIAN ->
|
||||
"Запрашивает изображения только с серверов которые используют порт 443. " +
|
||||
"Это позволяет пользователям со строгими правилами брандмауэра загружать " +
|
||||
"изображения с Mangadex."
|
||||
"изображения с $MANGADEX_NAME."
|
||||
else ->
|
||||
"Enable to only request image servers that use port 443. This allows users with " +
|
||||
"stricter firewall restrictions to access MangaDex images"
|
||||
"stricter firewall restrictions to access $MANGADEX_NAME images"
|
||||
}
|
||||
|
||||
val contentRating: String = when (availableLang) {
|
||||
@ -265,6 +265,20 @@ class MangaDexIntl(lang: String) {
|
||||
"Enter as a Comma-separated list of uploader UUIDs"
|
||||
}
|
||||
|
||||
val tryUsingFirstVolumeCover: String = when (availableLang) {
|
||||
BRAZILIAN_PORTUGUESE, PORTUGUESE -> "Tentar usar a capa do primeiro volume como capa"
|
||||
else -> "Attempt to use the first volume cover as cover"
|
||||
}
|
||||
|
||||
val tryUsingFirstVolumeCoverSummary: String = when (availableLang) {
|
||||
BRAZILIAN_PORTUGUESE, PORTUGUESE ->
|
||||
"Pode ser necessário atualizar os itens já adicionados na biblioteca. " +
|
||||
"Alternativamente, limpe o banco de dados para as novas capas aparecerem."
|
||||
else ->
|
||||
"May need to manually refresh entries already in library. " +
|
||||
"Otherwise, clear database to have new covers to show up."
|
||||
}
|
||||
|
||||
val publicationDemographic: String = when (availableLang) {
|
||||
BRAZILIAN_PORTUGUESE, PORTUGUESE -> "Demografia da publicação"
|
||||
SPANISH_LATAM, SPANISH -> "Demografía"
|
||||
@ -748,7 +762,7 @@ class MangaDexIntl(lang: String) {
|
||||
BRAZILIAN_PORTUGUESE, PORTUGUESE -> "Pós-apocalíptico"
|
||||
SPANISH_LATAM, SPANISH -> "Post-Apocalíptico"
|
||||
RUSSIAN -> "Постапокалиптика"
|
||||
else -> "Post-Apocalypytic"
|
||||
else -> "Post-Apocalyptic"
|
||||
}
|
||||
|
||||
val themePsychological: String = when (availableLang) {
|
||||
|
@ -0,0 +1,22 @@
|
||||
package eu.kanade.tachiyomi.extension.all.mangadex.dto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class CoverListDto(
|
||||
val data: List<CoverDto> = emptyList()
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CoverDto(
|
||||
val id: String,
|
||||
val attributes: CoverAttributesDto? = null,
|
||||
val relationships: List<RelationshipDto> = emptyList()
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class CoverAttributesDto(
|
||||
val name: String? = null,
|
||||
val fileName: String? = null,
|
||||
val locale: String? = null
|
||||
)
|
@ -1,6 +1,7 @@
|
||||
package eu.kanade.tachiyomi.extension.all.mangadex.dto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.contentOrNull
|
||||
@ -45,7 +46,7 @@ data class MangaDataDto(
|
||||
@Serializable
|
||||
data class MangaAttributesDto(
|
||||
val title: JsonElement,
|
||||
val altTitles: JsonElement,
|
||||
val altTitles: JsonArray,
|
||||
val description: JsonElement,
|
||||
val originalLanguage: String?,
|
||||
val lastVolume: String?,
|
||||
@ -67,8 +68,14 @@ data class TagAttributesDto(
|
||||
val group: String
|
||||
)
|
||||
|
||||
fun JsonElement.asMdMap(): Map<String, String> {
|
||||
return runCatching {
|
||||
(this as JsonObject).map { it.key to (it.value.jsonPrimitive.contentOrNull ?: "") }.toMap()
|
||||
}.getOrElse { emptyMap() }
|
||||
typealias LocalizedString = Map<String, String>
|
||||
|
||||
/**
|
||||
* Temporary workaround while Dex API still returns arrays instead of objects
|
||||
* in the places that uses [LocalizedString].
|
||||
*/
|
||||
fun JsonElement.toLocalizedString(): LocalizedString {
|
||||
return (this as? JsonObject)?.entries
|
||||
?.associate { (key, value) -> key to (value.jsonPrimitive.contentOrNull ?: "") }
|
||||
.orEmpty()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user