Refactor json utilities

master
Koitharu 2 years ago
parent 166c5be5d6
commit 08fe54c36d
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -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<JSONObject>().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<String>()?.joinToString()
scanlator = jo.optJSONArray("group_name")?.asTypedList<String>()?.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<MangaTag> {
val ja = webClient.httpGet("https://api.${domain}/genre").parseJsonArray()
val tags = SparseArrayCompat<MangaTag>(ja.length())
for (jo in ja.JSONIterator()) {
for (jo in ja.asTypedList<JSONObject>()) {
tags.append(
jo.getInt("id"),
MangaTag(

@ -86,7 +86,7 @@ internal abstract class LineWebtoonsParser(
val episodes = firstResult
.getJSONObject("episodeList")
.getJSONArray("episode")
.toJSONList()
.asTypedList<JSONObject>()
.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<JSONObject>()
episodes.addAll(page)
}

@ -320,7 +320,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
)
}
private fun JSONObject.firstStringValue() = values().next() as String
private fun JSONObject.firstStringValue() = entries<String>().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<String>().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<JSONObject>().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<String, JSONObject> {
val destination = LinkedHashMap<String, JSONObject>(length())
repeat(length()) { i ->
val item = getJSONObject(i)
val keyValue = item.getString(key)
destination[keyValue] = item
}
return destination
}
private class Chapters(
val data: List<JSONObject>,
val total: Int,

@ -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<JSONObject>()
.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<JSONObject>() }
.flatten()
}
@ -169,10 +169,10 @@ internal abstract class MangaPlusParser(
private fun parseChapters(chapterListGroup: JSONArray, language: String): List<MangaChapter> {
val chapterList = chapterListGroup
.toJSONList()
.asTypedList<JSONObject>()
.flatMap {
it.optJSONArray("firstChapterList")?.toJSONList().orEmpty() +
it.optJSONArray("lastChapterList")?.toJSONList().orEmpty()
it.optJSONArray("firstChapterList")?.asTypedList<JSONObject>().orEmpty() +
it.optJSONArray("lastChapterList")?.asTypedList<JSONObject>().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<JSONObject>()
.firstOrNull { it.getStringOrNull("language") == null }
if (reason?.getStringOrNull("subject") == "Not Found" && url.contains("manga_viewer")) {

@ -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<JSONObject>()
val picsS = pages.getJSONArray("picsS").asTypedList<JSONObject>()
return pics.zip(picsS).map {
val img = it.first.getString("url")

@ -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<MangaTag>(length())
stringIterator().forEach {
asTypedList<String>().forEach {
result.add(
MangaTag(
title = toTitle(it),

@ -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<String, MangaTag>()
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<JSONObject>()
for (el in json) {
if (el.getString("name").isEmpty()) continue
tagMap[el.getString("name")] = MangaTag(

@ -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<JSONObject>().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")

@ -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<JSONObject>()
val dateFormat = SimpleDateFormat(datePattern, Locale.ENGLISH)
return manga.copy(
chapters = data.mapChapters(reversed = true) { i, it ->

@ -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<JSONObject>()
val dateFormat = SimpleDateFormat(datePattern, Locale.ENGLISH)
return manga.copy(
chapters = data.mapChapters(reversed = true) { i, it ->

@ -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<JSONObject>()?.mapChapters { _, it ->
MangaChapter(
id = generateUid(it.getLong("id")),
name = it.getString("full_title"),

@ -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<JSONObject>().reversed(),
)
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:SS", sourceLocale)

@ -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<JSONObject>().reversed())
manga.copy(
tags = json.getJSONArray("genres").toJSONList().mapNotNullToSet {
tags = json.getJSONArray("genres").mapJSONToSet {
MangaTag(
key = it.getString("slug"),
title = it.getString("name"),

@ -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<JSONObject>().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"),

@ -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<JSONObject>()
}
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("hentaiukr.com")

@ -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<JSONObject>()
.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<String>()
.asTypedList<String>()
.map { url ->
MangaPage(
id = generateUid(url),

@ -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<Manga> {
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<JSONObject>().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<JSONObject>()
.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<JSONObject>().first { it.getString("rel") == "alternate" }
.getString("href")
val dateText = j.getJSONObject("published").getString("\$t").substringBefore("T")
val slug = mangaUrl.substringAfterLast('/')
val slugChapter = href.substringAfterLast('/')

@ -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<JSONObject>()
.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<JSONObject>().first { it.getString("rel") == "alternate" }
.getString("href")
val dateText = j.getJSONObject("published").getString("\$t").substringBefore("T")
val slug = mangaUrl.substringAfterLast('/')
val slugChapter = href.substringAfterLast('/')

@ -0,0 +1,25 @@
package org.koitharu.kotatsu.parsers.util.json
import org.json.JSONArray
internal class JSONArrayTypedIterator<T : Any>(
private val array: JSONArray,
private val typeClass: Class<T>,
startIndex: Int,
) : ListIterator<T> {
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
}

@ -0,0 +1,53 @@
package org.koitharu.kotatsu.parsers.util.json
import org.json.JSONArray
internal class JSONArrayTypedListWrapper<T : Any>(
private val jsonArray: JSONArray,
private val typeClass: Class<T>,
) : List<T> {
override fun contains(element: T): Boolean = indexOf(element) != -1
override fun containsAll(elements: Collection<T>): 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<T> = 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<T> = listIterator(0)
override fun listIterator(index: Int): ListIterator<T> = JSONArrayTypedIterator(jsonArray, typeClass, index)
override fun subList(fromIndex: Int, toIndex: Int): List<T> {
val result = ArrayList<T>(toIndex - fromIndex + 1)
for (i in fromIndex..toIndex) {
result.add(get(i))
}
return result
}
override val size: Int
get() = jsonArray.length()
}

@ -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<JSONObject> {
private val total = array.length()
private var index = 0
override fun hasNext() = index < total
override fun next(): JSONObject = array.getJSONObject(index++)
}

@ -0,0 +1,24 @@
package org.koitharu.kotatsu.parsers.util.json
import org.json.JSONObject
internal class JSONObjectTypedIterableWrapper<T : Any>(
private val json: JSONObject,
private val typeClass: Class<T>,
) : Iterable<Map.Entry<String, T>> {
override fun iterator(): Iterator<Map.Entry<String, T>> = IteratorImpl()
private inner class IteratorImpl : Iterator<Map.Entry<String, T>> {
private val keyIterator = json.keys().iterator()
override fun hasNext(): Boolean = keyIterator.hasNext()
override fun next(): Map.Entry<String, T> = keyIterator.next().let { key ->
JSONEntry(key, typeClass.cast(json.get(key)))
}
}
private class JSONEntry<T : Any>(override val key: String, override val value: T) : Map.Entry<String, T>
}

@ -1,13 +0,0 @@
package org.koitharu.kotatsu.parsers.util.json
import org.json.JSONArray
class JSONStringIterator(private val array: JSONArray) : Iterator<String> {
private val total = array.length()
private var index = 0
override fun hasNext() = index < total
override fun next(): String = array.getString(index++)
}

@ -1,18 +0,0 @@
package org.koitharu.kotatsu.parsers.util.json
import org.json.JSONArray
class JSONTypedIterator<T>(
private val array: JSONArray,
private val cls: Class<T>,
) : Iterator<T> {
private val total = array.length()
private var index = 0
override fun hasNext() = index < total
override fun next(): T {
return cls.cast(array.get(index++))
}
}

@ -1,17 +0,0 @@
package org.koitharu.kotatsu.parsers.util.json
import org.json.JSONObject
class JSONValuesIterator(
private val jo: JSONObject,
) : Iterator<Any> {
private val keyIterator = jo.keys()
override fun hasNext(): Boolean = keyIterator.hasNext()
override fun next(): Any {
val key = keyIterator.next()
return jo.get(key)
}
}

@ -38,6 +38,10 @@ public inline fun <T> JSONArray.mapJSONNotNull(block: (JSONObject) -> T?): List<
return mapJSONNotNullTo(ArrayList(length()), block)
}
public inline fun <T> JSONArray.mapJSONToSet(mapper: (JSONObject) -> T): Set<T> {
return mapJSONTo(ArraySet<T>(length()), mapper)
}
public fun <T> JSONArray.mapJSONIndexed(block: (Int, JSONObject) -> T): List<T> {
val len = length()
val result = ArrayList<T>(len)
@ -104,30 +108,6 @@ public fun JSONObject.getFloatOrDefault(name: String, defaultValue: Float): Floa
}
}
@Deprecated("")
public fun JSONArray.JSONIterator(): Iterator<JSONObject> = JSONIterator(this)
@Deprecated("")
public fun JSONArray.stringIterator(): Iterator<String> = JSONStringIterator(this)
public inline fun <T> JSONArray.mapJSONToSet(mapper: (JSONObject) -> T): Set<T> {
return mapJSONTo(ArraySet<T>(length()), mapper)
}
@Deprecated("")
public fun JSONObject.values(): Iterator<Any> = JSONValuesIterator(this)
@Deprecated("")
public fun JSONArray.associateByKey(key: String): Map<String, JSONObject> {
val destination = LinkedHashMap<String, JSONObject>(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<JSONObject> {
return List(length()) { i -> getJSONObject(i) }
public fun <T : Any> JSONArray.asTypedList(typeClass: Class<T>): List<T> {
return JSONArrayTypedListWrapper(this, typeClass)
}
@Deprecated("")
public inline fun <reified T> JSONArray.asIterable(): Iterable<T> = Iterable {
JSONTypedIterator(this, T::class.java)
public inline fun <reified T : Any> JSONArray.asTypedList(): List<T> = asTypedList(T::class.java)
public fun <T : Any> JSONObject.entries(typeClass: Class<T>): Iterable<Map.Entry<String, T>> {
return JSONObjectTypedIterableWrapper(this, typeClass)
}
public inline fun <reified T : Any> JSONObject.entries(): Iterable<Map.Entry<String, T>> = entries(T::class.java)

Loading…
Cancel
Save