diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt index b0a61443..efd52efd 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt @@ -202,7 +202,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : url = "https://api.${domain}/comic/$hid/chapters?limit=$CHAPTERS_LIMIT", ).parseJson().getJSONArray("chapters") val dateFormat = SimpleDateFormat("yyyy-MM-dd") - return ja.toJSONList().reversed().mapChapters { _, jo -> + return ja.asTypedList().reversed().mapChapters { _, jo -> val vol = jo.getIntOrDefault("vol", 0) val chap = jo.getFloatOrDefault("chap", 0f) val locale = Locale.forLanguageTag(jo.getString("lang")) @@ -227,7 +227,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : number = chap, volume = vol, url = jo.getString("hid"), - scanlator = jo.optJSONArray("group_name")?.asIterable()?.joinToString() + scanlator = jo.optJSONArray("group_name")?.asTypedList()?.joinToString() ?.takeUnless { it.isBlank() }, uploadDate = dateFormat.tryParse(jo.getString("created_at").substringBefore('T')), branch = branch, @@ -270,7 +270,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : private suspend fun loadTags(): SparseArrayCompat { val ja = webClient.httpGet("https://api.${domain}/genre").parseJsonArray() val tags = SparseArrayCompat(ja.length()) - for (jo in ja.JSONIterator()) { + for (jo in ja.asTypedList()) { tags.append( jo.getInt("id"), MangaTag( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt index 9a91442c..f915f6ad 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt @@ -86,7 +86,7 @@ internal abstract class LineWebtoonsParser( val episodes = firstResult .getJSONObject("episodeList") .getJSONArray("episode") - .toJSONList() + .asTypedList() .toMutableList() while (episodes.count() < totalEpisodeCount) { @@ -94,7 +94,7 @@ internal abstract class LineWebtoonsParser( url = "/lineWebtoon/webtoon/challengeEpisodeList.json?v=2&titleNo=$titleNo&startIndex=${episodes.count()}&pageSize=30", ).getJSONObject("episodeList") .getJSONArray("episode") - .toJSONList() + .asTypedList() episodes.addAll(page) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt index 9c02e92a..78333fef 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt @@ -320,7 +320,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context ) } - private fun JSONObject.firstStringValue() = values().next() as String + private fun JSONObject.firstStringValue() = entries().first().value private fun JSONObject.selectByLocale(): String? { val preferredLocales = context.getPreferredLocales() @@ -328,7 +328,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context getStringOrNull(locale.language)?.let { return it } getStringOrNull(locale.toLanguageTag())?.let { return it } } - return getStringOrNull(LOCALE_FALLBACK) ?: values().nextOrNull() as? String + return getStringOrNull(LOCALE_FALLBACK) ?: entries().firstOrNull()?.value } private fun JSONArray.flatten(): JSONObject { @@ -387,7 +387,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context val json = webClient.httpGet(url).parseJson() if (json.getString("result") == "ok") { return Chapters( - data = json.optJSONArray("data")?.toJSONList().orEmpty(), + data = json.optJSONArray("data")?.asTypedList().orEmpty(), total = json.getInt("total"), ) } else { @@ -443,6 +443,16 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context return chaptersBuilder.toList() } + private fun JSONArray.associateByKey(key: String): Map { + val destination = LinkedHashMap(length()) + repeat(length()) { i -> + val item = getJSONObject(i) + val keyValue = item.getString(key) + destination[keyValue] = item + } + return destination + } + private class Chapters( val data: List, val total: Int, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt index ef20be77..a79b5725 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt @@ -14,10 +14,10 @@ import org.koitharu.kotatsu.parsers.SinglePageMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getStringOrNull import org.koitharu.kotatsu.parsers.util.json.mapJSON import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull -import org.koitharu.kotatsu.parsers.util.json.toJSONList import java.util.* internal abstract class MangaPlusParser( @@ -68,7 +68,7 @@ internal abstract class MangaPlusParser( return json.getJSONObject("titleRankingView") .getJSONArray("titles") - .toJSONList() + .asTypedList() .toMangaList() } @@ -86,7 +86,7 @@ internal abstract class MangaPlusParser( apiCall("/title_list/allV2") .getJSONObject("allTitlesViewV2") .getJSONArray("AllTitlesGroup") - .mapJSON { it.getJSONArray("titles").toJSONList() } + .mapJSON { it.getJSONArray("titles").asTypedList() } .flatten() } @@ -169,10 +169,10 @@ internal abstract class MangaPlusParser( private fun parseChapters(chapterListGroup: JSONArray, language: String): List { val chapterList = chapterListGroup - .toJSONList() + .asTypedList() .flatMap { - it.optJSONArray("firstChapterList")?.toJSONList().orEmpty() + - it.optJSONArray("lastChapterList")?.toJSONList().orEmpty() + it.optJSONArray("firstChapterList")?.asTypedList().orEmpty() + + it.optJSONArray("lastChapterList")?.asTypedList().orEmpty() } return chapterList.mapChapters { _, chapter -> @@ -254,7 +254,7 @@ internal abstract class MangaPlusParser( return checkNotNull(success) { val error = response.getJSONObject("error") val reason = error.getJSONArray("popups") - .toJSONList() + .asTypedList() .firstOrNull { it.getStringOrNull("language") == null } if (reason?.getStringOrNull("subject") == "Not Found" && url.contains("manga_viewer")) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt index 28c1a2bc..7bbd3d0a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt @@ -11,10 +11,10 @@ import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getStringOrNull import org.koitharu.kotatsu.parsers.util.json.mapJSON import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet -import org.koitharu.kotatsu.parsers.util.json.toJSONList import java.text.SimpleDateFormat import java.util.* @@ -364,8 +364,8 @@ internal class NineNineNineHentaiParser(context: MangaLoaderContext) : } } - val pics = pages.getJSONArray("pics").toJSONList() - val picsS = pages.getJSONArray("picsS").toJSONList() + val pics = pages.getJSONArray("pics").asTypedList() + val picsS = pages.getJSONArray("picsS").asTypedList() return pics.zip(picsS).map { val img = it.first.getString("url") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt index 357cce50..b6967688 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt @@ -12,10 +12,10 @@ import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.domain import org.koitharu.kotatsu.parsers.util.generateUid import org.koitharu.kotatsu.parsers.util.getDomain +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.mapJSON import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull -import org.koitharu.kotatsu.parsers.util.json.stringIterator import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl import java.util.* @@ -281,7 +281,7 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context, } val result = ArraySet(length()) - stringIterator().forEach { + asTypedList().forEach { result.add( MangaTag( title = toTitle(it), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt index 4c7d012c..ef4269c9 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt @@ -3,13 +3,14 @@ package org.koitharu.kotatsu.parsers.site.en import androidx.collection.ArrayMap import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import org.json.JSONObject import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* -import org.koitharu.kotatsu.parsers.util.json.toJSONList +import org.koitharu.kotatsu.parsers.util.json.asTypedList import java.text.SimpleDateFormat import java.util.* @@ -135,7 +136,8 @@ internal class AsuraScansParser(context: MangaLoaderContext) : tagCache?.let { return@withLock it } val tagMap = ArrayMap() val json = - webClient.httpGet("https://gg.$domain/api/series/filters").parseJson().getJSONArray("genres").toJSONList() + webClient.httpGet("https://gg.$domain/api/series/filters").parseJson().getJSONArray("genres") + .asTypedList() for (el in json) { if (el.getString("name").isEmpty()) continue tagMap[el.getString("name")] = MangaTag( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt index 58f6311d..0782dd4a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt @@ -3,6 +3,7 @@ package org.koitharu.kotatsu.parsers.site.en import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import org.json.JSONArray +import org.json.JSONObject import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.ErrorMessages import org.koitharu.kotatsu.parsers.MangaLoaderContext @@ -11,8 +12,8 @@ import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.mapJSON -import org.koitharu.kotatsu.parsers.util.json.toJSONList import java.text.SimpleDateFormat import java.util.* @@ -167,7 +168,7 @@ internal class FlixScansOrg(context: MangaLoaderContext) : val seriesKey = baseUrl.substringAfterLast("/").substringBefore("-") val json = JSONArray( webClient.httpGet("https://api.$domain/api/v1/webtoon/chapters/$key-desc").parseRaw(), - ).toJSONList().reversed() + ).asTypedList().reversed() return json.mapChapters { i, j -> val url = "https://$domain/read/webtoon/$seriesKey-${j.getString("id")}-${j.getString("slug")}" val date = j.getString("createdAt").substringBeforeLast("T") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt index 33828e80..2dd507b2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt @@ -7,9 +7,9 @@ import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getFloatOrDefault import org.koitharu.kotatsu.parsers.util.json.mapJSON -import org.koitharu.kotatsu.parsers.util.json.toJSONList import org.koitharu.kotatsu.parsers.util.json.unescapeJson import java.text.SimpleDateFormat import java.util.* @@ -151,7 +151,7 @@ internal abstract class HeanCms( val seriesId = manga.id val url = "https://$apiPath/chapter/query?page=1&perPage=9999&series_id=$seriesId" val response = webClient.httpGet(url).parseJson() - val data = response.getJSONArray("data").toJSONList() + val data = response.getJSONArray("data").asTypedList() val dateFormat = SimpleDateFormat(datePattern, Locale.ENGLISH) return manga.copy( chapters = data.mapChapters(reversed = true) { i, it -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt index 805384a8..113f04af 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt @@ -6,9 +6,9 @@ import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getBooleanOrDefault import org.koitharu.kotatsu.parsers.util.json.mapJSON -import org.koitharu.kotatsu.parsers.util.json.toJSONList import java.text.SimpleDateFormat import java.util.* @@ -132,7 +132,7 @@ internal abstract class IkenParser( val url = "https://$domain/api/chapters?postId=$seriesId&skip=0&take=1000&order=desc&userid=" val json = webClient.httpGet(url).parseJson().getJSONObject("post") val slug = json.getString("slug") - val data = json.getJSONArray("chapters").toJSONList() + val data = json.getJSONArray("chapters").asTypedList() val dateFormat = SimpleDateFormat(datePattern, Locale.ENGLISH) return manga.copy( chapters = data.mapChapters(reversed = true) { i, it -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt index 293cbd2f..d4a8d329 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt @@ -131,7 +131,7 @@ internal abstract class MangAdventureParser( "hiatus" -> MangaState.PAUSED else -> null }, - chapters = chapters?.optJSONArray("results")?.toJSONList()?.mapChapters { _, it -> + chapters = chapters?.optJSONArray("results")?.asTypedList()?.mapChapters { _, it -> MangaChapter( id = generateUid(it.getLong("id")), name = it.getString("full_title"), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt index 90d99dea..7da4a179 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt @@ -8,9 +8,9 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.network.UserAgents import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getStringOrNull import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed -import org.koitharu.kotatsu.parsers.util.json.toJSONList import java.text.SimpleDateFormat import java.util.* @@ -177,7 +177,7 @@ internal abstract class NepnepParser( doc.selectFirstOrThrow("script:containsData(MainFunction)").data() .substringAfter("vm.Chapters = ") .substringBefore(';'), - ).toJSONList().reversed(), + ).asTypedList().reversed(), ) val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:SS", sourceLocale) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt index b3462790..720c3a78 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt @@ -8,9 +8,10 @@ import org.koitharu.kotatsu.parsers.SinglePageMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getStringOrNull import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed -import org.koitharu.kotatsu.parsers.util.json.toJSONList +import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet import java.text.SimpleDateFormat import java.util.* @@ -209,10 +210,10 @@ internal abstract class PizzaReaderParser( val fullUrl = manga.url.toAbsoluteUrl(domain) val json = webClient.httpGet(fullUrl).parseJson().getJSONObject("comic") val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US) - val chapters = JSONArray(json.getJSONArray("chapters").toJSONList().reversed()) + val chapters = JSONArray(json.getJSONArray("chapters").asTypedList().reversed()) manga.copy( - tags = json.getJSONArray("genres").toJSONList().mapNotNullToSet { + tags = json.getJSONArray("genres").mapJSONToSet { MangaTag( key = it.getString("slug"), title = it.getString("name"), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt index c3c22057..0ea0762b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt @@ -137,13 +137,13 @@ internal class MangaWtfParser( tags = jo.getJSONArray("labels").mapJSONToSet { it.toMangaTag() }, state = jo.getStringOrNull("status")?.toMangaState(), author = - jo.getJSONArray("relations").toJSONList().firstNotNullOfOrNull { - if (it.getStringOrNull("type") == "AUTHOR") { - it.getJSONObject("publisher").getStringOrNull("name") - } else { - null - } - }, + jo.getJSONArray("relations").asTypedList().firstNotNullOfOrNull { + if (it.getStringOrNull("type") == "AUTHOR") { + it.getJSONObject("publisher").getStringOrNull("name") + } else { + null + } + }, source = source, largeCoverUrl = null, description = jo.getString("description").nl2br(), @@ -209,10 +209,10 @@ internal class MangaWtfParser( MangaChapter( id = generateUid(jo.getString("id")), name = - jo.getStringOrNull("name") ?: buildString { - if (volume > 0) append("Том ").append(volume).append(' ') - if (number > 0) append("Глава ").append(number) else append("Без имени") - }, + jo.getStringOrNull("name") ?: buildString { + if (volume > 0) append("Том ").append(volume).append(' ') + if (number > 0) append("Глава ").append(number) else append("Без имени") + }, number = number, volume = volume, url = jo.getString("id"), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt index 6c6a10ea..a3d7e42d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt @@ -13,9 +13,9 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getStringOrNull import org.koitharu.kotatsu.parsers.util.json.mapJSON -import org.koitharu.kotatsu.parsers.util.json.toJSONList import java.text.SimpleDateFormat import java.util.* @@ -36,7 +36,7 @@ internal class HentaiUkrParser(context: MangaLoaderContext) : MangaParser(contex webClient.httpGet("https://$domain/search/objects2.json").parseJson() }.recoverCatchingCancellable { webClient.httpGet("https://$domain/search/objects69.json").parseJson() - }.getOrThrow().getJSONArray("manga").toJSONList() + }.getOrThrow().getJSONArray("manga").asTypedList() } override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("hentaiukr.com") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt index fe49b6be..057aaa7d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt @@ -7,7 +7,10 @@ import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* -import org.koitharu.kotatsu.parsers.util.json.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList +import org.koitharu.kotatsu.parsers.util.json.getStringOrNull +import org.koitharu.kotatsu.parsers.util.json.mapJSON +import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet import java.text.SimpleDateFormat import java.util.* @@ -93,7 +96,7 @@ internal class YurinekoParser(context: MangaLoaderContext) : PagedMangaParser(co val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US) return manga.copy( chapters = response.getJSONArray("chapters") - .toJSONList() + .asTypedList() .mapChapters(true) { i, jo -> val mangaId = jo.getInt("mangaID") val chapterId = jo.getInt("id") @@ -120,7 +123,7 @@ internal class YurinekoParser(context: MangaLoaderContext) : PagedMangaParser(co .getJSONObject("pageProps") .getJSONObject("chapterData") .getJSONArray("url") - .asIterable() + .asTypedList() .map { url -> MangaPage( id = generateUid(url), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt index 5dbf1196..54552b43 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt @@ -3,6 +3,7 @@ package org.koitharu.kotatsu.parsers.site.zeistmanga import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import org.json.JSONArray +import org.json.JSONObject import org.jsoup.Jsoup import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.ErrorMessages @@ -11,8 +12,9 @@ import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import org.koitharu.kotatsu.parsers.util.json.asTypedList import org.koitharu.kotatsu.parsers.util.json.getStringOrNull -import org.koitharu.kotatsu.parsers.util.json.toJSONList +import org.koitharu.kotatsu.parsers.util.json.mapJSON import java.text.SimpleDateFormat import java.util.* @@ -150,10 +152,11 @@ internal abstract class ZeistMangaParser( } protected open fun parseMangaList(json: JSONArray): List { - return json.toJSONList().map { j -> + return json.mapJSON { j -> val name = j.getJSONObject("title").getString("\$t") val href = - j.getJSONArray("link").toJSONList().first { it.getString("rel") == "alternate" }.getString("href") + j.getJSONArray("link").asTypedList().first { it.getString("rel") == "alternate" } + .getString("href") val urlImg = if (j.toString().contains("media\$thumbnail")) { j.getJSONObject("media\$thumbnail").getStringOrNull("url") ?.replace("""/s.+?-c/""".toRegex(), "/w600/") @@ -274,12 +277,14 @@ internal abstract class ZeistMangaParser( append("?alt=json&orderby=published&max-results=9999") } val json = - webClient.httpGet(url).parseJson().getJSONObject("feed").getJSONArray("entry").toJSONList().reversed() + webClient.httpGet(url).parseJson().getJSONObject("feed").getJSONArray("entry").asTypedList() + .reversed() val dateFormat = SimpleDateFormat(datePattern, sourceLocale) return json.mapIndexedNotNull { i, j -> val name = j.getJSONObject("title").getString("\$t") val href = - j.getJSONArray("link").toJSONList().first { it.getString("rel") == "alternate" }.getString("href") + j.getJSONArray("link").asTypedList().first { it.getString("rel") == "alternate" } + .getString("href") val dateText = j.getJSONObject("published").getString("\$t").substringBefore("T") val slug = mangaUrl.substringAfterLast('/') val slugChapter = href.substringAfterLast('/') diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/id/KomikGes.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/id/KomikGes.kt index 43014bca..e7fe306b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/id/KomikGes.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/id/KomikGes.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.parsers.site.zeistmanga.id +import org.json.JSONObject import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser @@ -8,7 +9,7 @@ import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.site.zeistmanga.ZeistMangaParser import org.koitharu.kotatsu.parsers.util.* -import org.koitharu.kotatsu.parsers.util.json.toJSONList +import org.koitharu.kotatsu.parsers.util.json.asTypedList import java.text.SimpleDateFormat @MangaSourceParser("KOMIKGES", "KomikGes", "id") @@ -25,12 +26,14 @@ internal class KomikGes(context: MangaLoaderContext) : append("?alt=json&orderby=published&max-results=9999") } val json = - webClient.httpGet(url).parseJson().getJSONObject("feed").getJSONArray("entry").toJSONList().reversed() + webClient.httpGet(url).parseJson().getJSONObject("feed").getJSONArray("entry").asTypedList() + .reversed() val dateFormat = SimpleDateFormat(datePattern, sourceLocale) return json.mapIndexedNotNull { i, j -> val name = j.getJSONObject("title").getString("\$t") val href = - j.getJSONArray("link").toJSONList().first { it.getString("rel") == "alternate" }.getString("href") + j.getJSONArray("link").asTypedList().first { it.getString("rel") == "alternate" } + .getString("href") val dateText = j.getJSONObject("published").getString("\$t").substringBefore("T") val slug = mangaUrl.substringAfterLast('/') val slugChapter = href.substringAfterLast('/') diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONArrayTypedIterator.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONArrayTypedIterator.kt new file mode 100644 index 00000000..9991e0bc --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONArrayTypedIterator.kt @@ -0,0 +1,25 @@ +package org.koitharu.kotatsu.parsers.util.json + +import org.json.JSONArray + +internal class JSONArrayTypedIterator( + private val array: JSONArray, + private val typeClass: Class, + startIndex: Int, +) : ListIterator { + + private val total = array.length() + private var index = startIndex + + override fun hasNext() = index < total + + override fun next(): T = typeClass.cast(array[index++]) + + override fun hasPrevious(): Boolean = index > 0 + + override fun nextIndex(): Int = index + 1 + + override fun previous(): T = typeClass.cast(array[index--]) + + override fun previousIndex(): Int = index - 1 +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONArrayTypedListWrapper.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONArrayTypedListWrapper.kt new file mode 100644 index 00000000..2caa8d75 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONArrayTypedListWrapper.kt @@ -0,0 +1,53 @@ +package org.koitharu.kotatsu.parsers.util.json + +import org.json.JSONArray + +internal class JSONArrayTypedListWrapper( + private val jsonArray: JSONArray, + private val typeClass: Class, +) : List { + + override fun contains(element: T): Boolean = indexOf(element) != -1 + + override fun containsAll(elements: Collection): Boolean = elements.all { contains(it) } + + override fun get(index: Int): T = typeClass.cast(jsonArray[index]) + + override fun indexOf(element: T): Int { + repeat(jsonArray.length()) { i -> + if (jsonArray[i] == element) { + return i + } + } + return -1 + } + + override fun isEmpty(): Boolean = jsonArray.length() == 0 + + override fun iterator(): Iterator = listIterator(0) + + override fun lastIndexOf(element: T): Int { + val total = jsonArray.length() + repeat(total) { i -> + if (jsonArray[total - i - 1] == element) { + return i + } + } + return -1 + } + + override fun listIterator(): ListIterator = listIterator(0) + + override fun listIterator(index: Int): ListIterator = JSONArrayTypedIterator(jsonArray, typeClass, index) + + override fun subList(fromIndex: Int, toIndex: Int): List { + val result = ArrayList(toIndex - fromIndex + 1) + for (i in fromIndex..toIndex) { + result.add(get(i)) + } + return result + } + + override val size: Int + get() = jsonArray.length() +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONIterator.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONIterator.kt deleted file mode 100644 index 66c05e2e..00000000 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONIterator.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.koitharu.kotatsu.parsers.util.json - -import org.json.JSONArray -import org.json.JSONObject - -class JSONIterator(private val array: JSONArray) : Iterator { - - private val total = array.length() - private var index = 0 - - override fun hasNext() = index < total - - override fun next(): JSONObject = array.getJSONObject(index++) -} \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONObjectTypedIterableWrapper.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONObjectTypedIterableWrapper.kt new file mode 100644 index 00000000..32c94c97 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONObjectTypedIterableWrapper.kt @@ -0,0 +1,24 @@ +package org.koitharu.kotatsu.parsers.util.json + +import org.json.JSONObject + +internal class JSONObjectTypedIterableWrapper( + private val json: JSONObject, + private val typeClass: Class, +) : Iterable> { + + override fun iterator(): Iterator> = IteratorImpl() + + private inner class IteratorImpl : Iterator> { + + private val keyIterator = json.keys().iterator() + + override fun hasNext(): Boolean = keyIterator.hasNext() + + override fun next(): Map.Entry = keyIterator.next().let { key -> + JSONEntry(key, typeClass.cast(json.get(key))) + } + } + + private class JSONEntry(override val key: String, override val value: T) : Map.Entry +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONStringIterator.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONStringIterator.kt deleted file mode 100644 index 5a04afd1..00000000 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONStringIterator.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.koitharu.kotatsu.parsers.util.json - -import org.json.JSONArray - -class JSONStringIterator(private val array: JSONArray) : Iterator { - - private val total = array.length() - private var index = 0 - - override fun hasNext() = index < total - - override fun next(): String = array.getString(index++) -} \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONTypedIterator.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONTypedIterator.kt deleted file mode 100644 index f4bcb5e1..00000000 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONTypedIterator.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.koitharu.kotatsu.parsers.util.json - -import org.json.JSONArray - -class JSONTypedIterator( - private val array: JSONArray, - private val cls: Class, -) : Iterator { - - private val total = array.length() - private var index = 0 - - override fun hasNext() = index < total - - override fun next(): T { - return cls.cast(array.get(index++)) - } -} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONValuesIterator.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONValuesIterator.kt deleted file mode 100644 index 5c5c2c6a..00000000 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JSONValuesIterator.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.koitharu.kotatsu.parsers.util.json - -import org.json.JSONObject - -class JSONValuesIterator( - private val jo: JSONObject, -) : Iterator { - - private val keyIterator = jo.keys() - - override fun hasNext(): Boolean = keyIterator.hasNext() - - override fun next(): Any { - val key = keyIterator.next() - return jo.get(key) - } -} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JsonExt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JsonExt.kt index 813e9039..695eb6c1 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JsonExt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/json/JsonExt.kt @@ -38,6 +38,10 @@ public inline fun JSONArray.mapJSONNotNull(block: (JSONObject) -> T?): List< return mapJSONNotNullTo(ArrayList(length()), block) } +public inline fun JSONArray.mapJSONToSet(mapper: (JSONObject) -> T): Set { + return mapJSONTo(ArraySet(length()), mapper) +} + public fun JSONArray.mapJSONIndexed(block: (Int, JSONObject) -> T): List { val len = length() val result = ArrayList(len) @@ -104,30 +108,6 @@ public fun JSONObject.getFloatOrDefault(name: String, defaultValue: Float): Floa } } -@Deprecated("") -public fun JSONArray.JSONIterator(): Iterator = JSONIterator(this) - -@Deprecated("") -public fun JSONArray.stringIterator(): Iterator = JSONStringIterator(this) - -public inline fun JSONArray.mapJSONToSet(mapper: (JSONObject) -> T): Set { - return mapJSONTo(ArraySet(length()), mapper) -} - -@Deprecated("") -public fun JSONObject.values(): Iterator = JSONValuesIterator(this) - -@Deprecated("") -public fun JSONArray.associateByKey(key: String): Map { - val destination = LinkedHashMap(length()) - repeat(length()) { i -> - val item = getJSONObject(i) - val keyValue = item.getString(key) - destination[keyValue] = item - } - return destination -} - public fun JSONArray?.isNullOrEmpty(): Boolean { contract { returns(false) implies (this@isNullOrEmpty != null) @@ -136,12 +116,14 @@ public fun JSONArray?.isNullOrEmpty(): Boolean { return this == null || this.length() == 0 } -@Deprecated("") -public fun JSONArray.toJSONList(): List { - return List(length()) { i -> getJSONObject(i) } +public fun JSONArray.asTypedList(typeClass: Class): List { + return JSONArrayTypedListWrapper(this, typeClass) } -@Deprecated("") -public inline fun JSONArray.asIterable(): Iterable = Iterable { - JSONTypedIterator(this, T::class.java) +public inline fun JSONArray.asTypedList(): List = asTypedList(T::class.java) + +public fun JSONObject.entries(typeClass: Class): Iterable> { + return JSONObjectTypedIterableWrapper(this, typeClass) } + +public inline fun JSONObject.entries(): Iterable> = entries(T::class.java)