Kotlinx.serialization migration for several sources (#7723)

* en.MangaPark: kotlinx.serialization migration

* Bato.to: Kotlinx.serialization migration

* Dynasty: Kotlinx.serialization

* ReadM: kotlinx.serialization migration

* Bato.to: Comment out code that was untested
This commit is contained in:
h-hyuuga 2021-06-20 08:28:26 -04:00 committed by GitHub
parent 8a7122a2fc
commit 759a2123c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 389 additions and 380 deletions

View File

@ -1,11 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext { ext {
extName = 'Bato.to' extName = 'Bato.to'
pkgNameSuffix = 'all.batoto' pkgNameSuffix = 'all.batoto'
extClass = '.BatoToFactory' extClass = '.BatoToFactory'
extVersionCode = 12 extVersionCode = 13
libVersion = '1.2' libVersion = '1.2'
containsNsfw = true containsNsfw = true
} }

View File

@ -11,17 +11,20 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.json.JSONArray import okhttp3.Response
import org.json.JSONObject
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.util.Calendar import java.util.Calendar
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import okhttp3.Response
import rx.Observable
open class BatoTo( open class BatoTo(
override val lang: String, override val lang: String,
@ -32,7 +35,7 @@ open class BatoTo(
override val baseUrl: String = "https://bato.to" override val baseUrl: String = "https://bato.to"
override val supportsLatest = true override val supportsLatest = true
private val json: Json by injectLazy()
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS) .connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS)
@ -110,7 +113,8 @@ open class BatoTo(
} }
with(genreFilter) { with(genreFilter) {
url.addQueryParameter("genres", included.joinToString(",") + "|" + excluded.joinToString(",") url.addQueryParameter(
"genres", included.joinToString(",") + "|" + excluded.joinToString(",")
) )
} }
@ -294,16 +298,14 @@ open class BatoTo(
val script = document.select("script").html() val script = document.select("script").html()
if (script.contains("var images =")) { if (script.contains("var images =")) {
val imgJson = JSONObject(script.substringAfter("var images = ").substringBefore(";")) /*
val imgNames = imgJson.names() * During kotlinx.serialization migration, the pre-existing code seemed to not work
* Could not find a case where code would run in practice, so it was commented out.
*/
throw RuntimeException("Unexpected Branch: Please File A Bug Report describing this issue")
// val imgJson = json.parseToJsonElement(script.substringAfter("var images = ").substringBefore(";")).jsonObject
// imgJson.keys.forEachIndexed { i, s -> pages.add(Page(i, imageUrl = imgJson[s]!!.jsonPrimitive.content)) }
if (imgNames != null) {
for (i in 0 until imgNames.length()) {
val imgKey = imgNames.getString(i)
val imgUrl = imgJson.getString(imgKey)
pages.add(Page(i, "", imgUrl))
}
}
} else if (script.contains("const server =")) { // bato.to } else if (script.contains("const server =")) { // bato.to
val duktape = Duktape.create() val duktape = Duktape.create()
val encryptedServer = script.substringAfter("const server = ").substringBefore(";") val encryptedServer = script.substringAfter("const server = ").substringBefore(";")
@ -312,21 +314,13 @@ open class BatoTo(
val server = duktape.evaluate(decryptScript).toString().replace("\"", "") val server = duktape.evaluate(decryptScript).toString().replace("\"", "")
duktape.close() duktape.close()
val imgArray = JSONArray(script.substringAfter("const images = ").substringBefore(";")) json.parseToJsonElement(script.substringAfter("const images = ").substringBefore(";")).jsonArray
if (imgArray != null) { .forEachIndexed { i, it ->
val imgUrl = it.jsonPrimitive.content
if (script.contains("bato.to/images")) { if (script.contains("bato.to/images")) {
for (i in 0 until imgArray.length()) { pages.add(Page(i, imageUrl = imgUrl))
val imgUrl = imgArray.get(i)
pages.add(Page(i, "", "$imgUrl"))
}
} else { } else {
for (i in 0 until imgArray.length()) { pages.add(Page(i, imageUrl = if (server.startsWith("http")) "${server}$imgUrl" else "https:${server}$imgUrl"))
val imgUrl = imgArray.get(i)
if (server.startsWith("http"))
pages.add(Page(i, "", "${server}$imgUrl"))
else
pages.add(Page(i, "", "https:${server}$imgUrl"))
}
} }
} }
} }
@ -367,10 +361,12 @@ open class BatoTo(
val selected: String val selected: String
get() = options[state].value get() = options[state].value
} }
abstract class CheckboxGroupFilter(name: String, options: List<CheckboxFilterOption>) : Filter.Group<CheckboxFilterOption>(name, options) { abstract class CheckboxGroupFilter(name: String, options: List<CheckboxFilterOption>) : Filter.Group<CheckboxFilterOption>(name, options) {
val selected: List<String> val selected: List<String>
get() = state.filter { it.state }.map { it.value } get() = state.filter { it.state }.map { it.value }
} }
abstract class TriStateGroupFilter(name: String, options: List<TriStateFilterOption>) : Filter.Group<TriStateFilterOption>(name, options) { abstract class TriStateGroupFilter(name: String, options: List<TriStateFilterOption>) : Filter.Group<TriStateFilterOption>(name, options) {
val included: List<String> val included: List<String>
get() = state.filter { it.isIncluded() }.map { it.value } get() = state.filter { it.isIncluded() }.map { it.value }
@ -378,6 +374,7 @@ open class BatoTo(
val excluded: List<String> val excluded: List<String>
get() = state.filter { it.isExcluded() }.map { it.value } get() = state.filter { it.isExcluded() }.map { it.value }
} }
abstract class TextFilter(name: String) : Filter.Text(name) abstract class TextFilter(name: String) : Filter.Text(name)
class SortFilter(options: List<SelectFilterOption>, default: Int) : SelectFilter("Sort By", options, default) class SortFilter(options: List<SelectFilterOption>, default: Int) : SelectFilter("Sort By", options, default)

View File

@ -1,11 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext { ext {
extName = 'Dynasty' extName = 'Dynasty'
pkgNameSuffix = 'en.dynasty' pkgNameSuffix = 'en.dynasty'
extClass = '.DynastyFactory' extClass = '.DynastyFactory'
extVersionCode = 13 extVersionCode = 14
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -10,15 +10,19 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.json.JSONArray
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.nodes.Node import org.jsoup.nodes.Node
import org.jsoup.nodes.TextNode import org.jsoup.nodes.TextNode
import org.jsoup.select.Elements import org.jsoup.select.Elements
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.ArrayList import java.util.ArrayList
import java.util.Locale import java.util.Locale
@ -43,6 +47,8 @@ abstract class DynastyScans : ParsedHttpSource() {
private var _valid: Validate = Validate(false, -1) private var _valid: Validate = Validate(false, -1)
private val json: Json by injectLazy()
override fun popularMangaRequest(page: Int): Request { override fun popularMangaRequest(page: Int): Request {
return GET(popularMangaInitialUrl(), headers) return GET(popularMangaInitialUrl(), headers)
} }
@ -189,19 +195,16 @@ abstract class DynastyScans : ParsedHttpSource() {
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>() return try {
try {
val imageUrl = document.select("script").last().html().substringAfter("var pages = [").substringBefore("];") val imageUrl = document.select("script").last().html().substringAfter("var pages = [").substringBefore("];")
val imageUrls = JSONArray("[$imageUrl]")
(0 until imageUrls.length()) json.parseToJsonElement("[$imageUrl]").jsonArray.mapIndexed { index, it ->
.map { imageUrls.getJSONObject(it) } Page(index, imageUrl = "$baseUrl${it.jsonObject["image"]!!.jsonPrimitive.content}")
.map { baseUrl + it.get("image") } }
.forEach { pages.add(Page(pages.size, "", it)) }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
emptyList()
} }
return pages
} }
class InternalList(nodes: List<Node>, type: String) : ArrayList<String>() { class InternalList(nodes: List<Node>, type: String) : ArrayList<String>() {

View File

@ -1,11 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext { ext {
extName = 'MangaPark' extName = 'MangaPark'
pkgNameSuffix = 'en.mangapark' pkgNameSuffix = 'en.mangapark'
extClass = '.MangaPark' extClass = '.MangaPark'
extVersionCode = 20 extVersionCode = 21
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -13,14 +13,18 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.json.JSONArray
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
@ -36,7 +40,7 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
override val baseUrl = "https://v2.mangapark.net" override val baseUrl = "https://v2.mangapark.net"
private val nextPageSelector = ".paging:not(.order) > li:last-child > a" private val nextPageSelector = ".paging:not(.order) > li:last-child > a"
private val json: Json by injectLazy()
private val dateFormat = SimpleDateFormat("MMM d, yyyy, HH:mm a", Locale.ENGLISH) private val dateFormat = SimpleDateFormat("MMM d, yyyy, HH:mm a", Locale.ENGLISH)
private val dateFormatTimeOnly = SimpleDateFormat("HH:mm a", Locale.ENGLISH) private val dateFormatTimeOnly = SimpleDateFormat("HH:mm a", Locale.ENGLISH)
@ -278,9 +282,11 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
override fun pageListParse(response: Response): List<Page> { override fun pageListParse(response: Response): List<Page> {
val obj = objRegex.find(response.body!!.string())?.groupValues?.get(1) val obj = objRegex.find(response.body!!.string())?.groupValues?.get(1)
?: throw Exception("_load_pages not found - ${response.request.url}") ?: throw Exception("_load_pages not found - ${response.request.url}")
val jsonArray = JSONArray(obj)
return (0 until jsonArray.length()).map { i -> jsonArray.getJSONObject(i).getString("u") } return json.parseToJsonElement(obj).jsonArray.mapIndexed { i, it ->
.mapIndexed { i, url -> Page(i, "", if (url.startsWith("//")) "https://$url" else url) } val url = it.jsonObject["u"]!!.jsonPrimitive.content
Page(i, imageUrl = if (url.startsWith("//")) "https://$url" else url)
}
} }
override fun pageListParse(document: Document): List<Page> = throw UnsupportedOperationException("Not used") override fun pageListParse(document: Document): List<Page> = throw UnsupportedOperationException("Not used")

View File

@ -1,11 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext { ext {
extName = 'ReadM' extName = 'ReadM'
pkgNameSuffix = 'en.readm' pkgNameSuffix = 'en.readm'
extClass = '.ReadM' extClass = '.ReadM'
extVersionCode = 5 extVersionCode = 6
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -8,13 +8,17 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.json.JSONObject
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.injectLazy
import java.util.Calendar import java.util.Calendar
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -32,6 +36,7 @@ class ReadM : ParsedHttpSource() {
.followRedirects(true) .followRedirects(true)
.build() .build()
private val json: Json by injectLazy()
// Popular // Popular
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/popular-manga/$page", headers) override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/popular-manga/$page", headers)
@ -76,20 +81,14 @@ class ReadM : ParsedHttpSource() {
override fun searchMangaSelector(): String = throw Exception("Not used") override fun searchMangaSelector(): String = throw Exception("Not used")
override fun searchMangaFromElement(element: Element): SManga = throw Exception("Not used") override fun searchMangaFromElement(element: Element): SManga = throw Exception("Not used")
override fun searchMangaParse(response: Response): MangasPage { override fun searchMangaParse(response: Response) = json.parseToJsonElement(response.body!!.string()).jsonObject["manga"]?.jsonArray?.map {
val json = JSONObject(response.body!!.string()).getJSONArray("manga") val obj = it.jsonObject
val manga = (0 until json.length()).asSequence().toList().map { it ->
SManga.create().apply { SManga.create().apply {
val jsonObject = json.getJSONObject(it) title = obj["title"]!!.jsonPrimitive.content
title = jsonObject.getString("title") url = obj["url"]!!.jsonPrimitive.content
url = jsonObject.getString("url") thumbnail_url = "$baseUrl${obj["image"]!!.jsonPrimitive.content}"
thumbnail_url = jsonObject.getString("image")
}
}
return MangasPage(manga, false)
} }
}.let { MangasPage(it ?: emptyList(), false) }
// Details // Details