diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 76b539622..c8ff25548 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -123,25 +123,26 @@ dependencies { #### Additional dependencies -You may find yourself needing additional functionality and wanting to add more dependencies to your `build.gradle` file. Since extensions are run within the main Tachiyomi app, you can make use of [its dependencies](https://github.com/tachiyomiorg/tachiyomi/blob/master/app/build.gradle). +You may find yourself needing additional functionality and wanting to add more dependencies to your `build.gradle` file. Since extensions are run within the main Tachiyomi app, you can make use of [its dependencies](https://github.com/tachiyomiorg/tachiyomi/blob/master/app/build.gradle.kts). -For example, an extension that needs Gson could add the following: +For example, an extension that needs coroutines, it could add the following: ```gradle dependencies { - compileOnly 'com.google.code.gson:gson:2.8.2' + compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2' + compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2' } ``` -(Note that Gson, and several other dependencies, are already exposed to all extensions via `common.gradle`.) +(Note that several dependencies are already exposed to all extensions via `common-dependencies.gradle`.) Notice that we're using `compileOnly` instead of `implementation`, since the app already contains it. You could use `implementation` instead for a new dependency, or you prefer not to rely on whatever the main app has at the expense of app size. -Note that using `compileOnly` restricts you to versions that must be compatible with those used in [Tachiyomi v0.8.5+](https://github.com/tachiyomiorg/tachiyomi/blob/82141cec6e612885fef4fa70092e29e99d60adbb/app/build.gradle#L104) for proper backwards compatibility. +Note that using `compileOnly` restricts you to versions that must be compatible with those used in [Tachiyomi v0.10.12+](https://github.com/tachiyomiorg/tachiyomi/blob/v0.10.12/app/build.gradle.kts) for proper backwards compatibility. ### Extension main class -The class which is refrenced and defined by `extClass` in `build.gradle`. This class should implement either `SourceFactory` or extend one of the `Source` implementations: `HttpSource` or `ParsedHttpSource`. +The class which is referenced and defined by `extClass` in `build.gradle`. This class should implement either `SourceFactory` or extend one of the `Source` implementations: `HttpSource` or `ParsedHttpSource`. | Class | Description | | ----- | ----------- | diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/luscious/Luscious.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/luscious/Luscious.kt index 42755f397..5e802bd29 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/luscious/Luscious.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/luscious/Luscious.kt @@ -5,13 +5,6 @@ import android.content.SharedPreferences import androidx.preference.CheckBoxPreference import androidx.preference.ListPreference import androidx.preference.PreferenceScreen -import com.github.salomonbrys.kotson.addProperty -import com.github.salomonbrys.kotson.fromJson -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.set -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.ConfigurableSource @@ -22,6 +15,20 @@ 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.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.boolean +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.int +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.long +import kotlinx.serialization.json.put +import kotlinx.serialization.json.putJsonArray +import kotlinx.serialization.json.putJsonObject import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.OkHttpClient import okhttp3.Request @@ -29,6 +36,7 @@ import okhttp3.Response import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import uy.kohesive.injekt.injectLazy import java.util.Calendar abstract class Luscious( @@ -44,7 +52,7 @@ abstract class Luscious( private val apiBaseUrl: String = "$baseUrl/graphql/nobatch/" - private val gson = Gson() + private val json: Json by injectLazy() override val client: OkHttpClient = network.cloudflareClient @@ -86,90 +94,91 @@ abstract class Luscious( val contentTypeFilter = filters.findInstance()!! val albumSizeFilter = filters.findInstance()!! val restrictGenresFilter = filters.findInstance()!! - return JsonObject().apply { - add( - "input", - JsonObject().apply { - addProperty("display", sortByFilter.selected) - addProperty("page", page) - add( - "filters", - JsonArray().apply { + return buildJsonObject { + putJsonObject("input") { + put("display", sortByFilter.selected) + put("page", page) + putJsonArray("filters") { + if (contentTypeFilter.selected != FILTER_VALUE_IGNORE) + add(contentTypeFilter.toJsonObject("content_id")) - if (contentTypeFilter.selected != FILTER_VALUE_IGNORE) - add(contentTypeFilter.toJsonObject("content_id")) + if (albumTypeFilter.selected != FILTER_VALUE_IGNORE) + add(albumTypeFilter.toJsonObject("album_type")) - if (albumTypeFilter.selected != FILTER_VALUE_IGNORE) - add(albumTypeFilter.toJsonObject("album_type")) + if (selectionFilter.selected != FILTER_VALUE_IGNORE) + add(selectionFilter.toJsonObject("selection")) - if (selectionFilter.selected != FILTER_VALUE_IGNORE) - add(selectionFilter.toJsonObject("selection")) + if (albumSizeFilter.selected != FILTER_VALUE_IGNORE) + add(albumSizeFilter.toJsonObject("picture_count_rank")) - if (albumSizeFilter.selected != FILTER_VALUE_IGNORE) - add(albumSizeFilter.toJsonObject("picture_count_rank")) + if (restrictGenresFilter.selected != FILTER_VALUE_IGNORE) + add(restrictGenresFilter.toJsonObject("restrict_genres")) - if (restrictGenresFilter.selected != FILTER_VALUE_IGNORE) - add(restrictGenresFilter.toJsonObject("restrict_genres")) - - with(interestsFilter) { - if (this.selected.isEmpty()) { - throw Exception("Please select an Interest") - } - add(this.toJsonObject("audience_ids")) - } - - if (lusLang != FILTER_VALUE_IGNORE) { - add( - languagesFilter.toJsonObject("language_ids").apply { - set("value", "+$lusLang${get("value").asString}") - } - ) - } - - if (tagsFilter.state.isNotEmpty()) { - val tags = "+${tagsFilter.state.toLowerCase()}".replace(" ", "_").replace("_,", "+").replace(",_", "+").replace(",", "+").replace("+-", "-").replace("-_", "-").trim() - add( - JsonObject().apply { - addProperty("name", "tagged") - addProperty("value", tags) - } - ) - } - - if (creatorFilter.state.isNotEmpty()) { - add( - JsonObject().apply { - addProperty("name", "created_by_id") - addProperty("value", creatorFilter.state) - } - ) - } - - if (favoriteFilter.state.isNotEmpty()) { - add( - JsonObject().apply { - addProperty("name", "favorite_by_user_id") - addProperty("value", favoriteFilter.state) - } - ) - } - - if (genreFilter.anyNotIgnored()) { - add(genreFilter.toJsonObject("genre_ids")) - } - - if (query != "") { - add( - JsonObject().apply { - addProperty("name", "search_query") - addProperty("value", query) - } - ) - } + with(interestsFilter) { + if (this.selected.isEmpty()) { + throw Exception("Please select an Interest") } - ) + add(this.toJsonObject("audience_ids")) + } + + if (lusLang != FILTER_VALUE_IGNORE) { + val languageIds = languagesFilter.toJsonObject("language_ids") + add( + JsonObject( + languageIds.toMutableMap().apply { + put( + "value", + JsonPrimitive ("+$lusLang${languageIds["value"]!!.jsonPrimitive.content}") + ) + } + ) + ) + } + + if (tagsFilter.state.isNotEmpty()) { + val tags = "+${tagsFilter.state.toLowerCase()}".replace(" ", "_") + .replace("_,", "+").replace(",_", "+").replace(",", "+") + .replace("+-", "-").replace("-_", "-").trim() + add( + buildJsonObject { + put("name", "tagged") + put("value", tags) + } + ) + } + + if (creatorFilter.state.isNotEmpty()) { + add( + buildJsonObject { + put("name", "created_by_id") + put("value", creatorFilter.state) + } + ) + } + + if (favoriteFilter.state.isNotEmpty()) { + add( + buildJsonObject { + put("name", "favorite_by_user_id") + put("value", favoriteFilter.state) + } + ) + } + + if (genreFilter.anyNotIgnored()) { + add(genreFilter.toJsonObject("genre_ids")) + } + + if (query != "") { + add( + buildJsonObject { + put("name", "search_query") + put("value", query) + } + ) + } } - ) + } } } @@ -184,24 +193,24 @@ abstract class Luscious( } private fun parseAlbumListResponse(response: Response): MangasPage { - val data = gson.fromJson(response.body!!.string()) - with(data["data"]["album"]["list"]) { + val data = json.decodeFromString(response.body!!.string()) + with(data["data"]!!.jsonObject["album"]!!.jsonObject["list"]) { return MangasPage( - this["items"].asJsonArray.map { + this!!.jsonObject["items"]!!.jsonArray.map { SManga.create().apply { - url = it["url"].asString - title = it["title"].asString - thumbnail_url = it["cover"]["url"].asString + url = it.jsonObject["url"]!!.jsonPrimitive.content + title = it.jsonObject["title"]!!.jsonPrimitive.content + thumbnail_url = it.jsonObject["cover"]!!.jsonObject["url"]!!.jsonPrimitive.content } }, - this["info"]["has_next_page"].asBoolean + this.jsonObject["info"]!!.jsonObject["has_next_page"]!!.jsonPrimitive.boolean ) } } private fun buildAlbumInfoRequestInput(id: String): JsonObject { - return JsonObject().apply { - addProperty("id", id) + return buildJsonObject { + put("id", id) } } @@ -246,34 +255,34 @@ abstract class Luscious( var nextPage = true var page = 2 val id = response.request.url.queryParameter("variables").toString() - .let { gson.fromJson(it)["input"]["filters"].asJsonArray } - .let { it.first { f -> f["name"].asString == "album_id" } } - .let { it["value"].asString } + .let { json.decodeFromString(it)["input"]!!.jsonObject["filters"]!!.jsonArray } + .let { it.first { f -> f.jsonObject["name"]!!.jsonPrimitive.content == "album_id" } } + .let { it.jsonObject["value"]!!.jsonPrimitive.content } - var data = gson.fromJson(response.body!!.string()) - .let { it["data"]["picture"]["list"].asJsonObject } + var data = json.decodeFromString(response.body!!.string()) + .let { it.jsonObject["data"]!!.jsonObject["picture"]!!.jsonObject["list"]!!.jsonObject } while (nextPage) { - nextPage = data["info"]["has_next_page"].asBoolean - data["items"].asJsonArray.map { + nextPage = data["info"]!!.jsonObject["has_next_page"]!!.jsonPrimitive.boolean + data["items"]!!.jsonArray.map { val chapter = SChapter.create() val url = when (getResolutionPref()) { - "-1" -> it["url_to_original"].asString - else -> it["thumbnails"][getResolutionPref()?.toInt()!!]["url"].asString + "-1" -> it.jsonObject["url_to_original"]!!.jsonPrimitive.content + else -> it.jsonObject["thumbnails"]!!.jsonObject[getResolutionPref()?.toInt()!!]!!.jsonObject["url"]!!.jsonPrimitive.content } when { url.startsWith("//") -> chapter.url = "https:$url" else -> chapter.url = url } - chapter.chapter_number = it["position"].asInt.toFloat() - chapter.name = chapter.chapter_number.toInt().toString() + " - " + it["title"].asString - chapter.date_upload = "${it["created"].asLong}000".toLong() + chapter.chapter_number = it.jsonObject["position"]!!.jsonPrimitive.int.toFloat() + chapter.name = chapter.chapter_number.toInt().toString() + " - " + it.jsonObject["title"]!!.jsonPrimitive.content + chapter.date_upload = "${it.jsonObject["created"]!!.jsonPrimitive.long}000".toLong() chapters.add(chapter) } if (nextPage) { val newPage = client.newCall(GET(buildAlbumPicturesPageUrl(id, page))).execute() - data = gson.fromJson(newPage.body!!.string()) - .let { it["data"]["picture"]["list"].asJsonObject } + data = json.decodeFromString(newPage.body!!.string()) + .let { it["data"]!!.jsonObject["picture"]!!.jsonObject["list"]!!.jsonObject } } page++ } @@ -288,25 +297,17 @@ abstract class Luscious( // Pages private fun buildAlbumPicturesRequestInput(id: String, page: Int): JsonObject { - return JsonObject().apply { - addProperty( - "input", - JsonObject().apply { - addProperty( - "filters", - JsonArray().apply { - add( - JsonObject().apply { - addProperty("name", "album_id") - addProperty("value", id) - } - ) - } - ) - addProperty("display", getSortPref()) - addProperty("page", page) + return buildJsonObject { + putJsonObject("input") { + putJsonArray("filters") { + add(buildJsonObject { + put("name", "album_id") + put("value", id) + }) } - ) + put("display", getSortPref()) + put("page", page) + } } } @@ -324,20 +325,20 @@ abstract class Luscious( var nextPage = true var page = 2 val id = response.request.url.queryParameter("variables").toString() - .let { gson.fromJson(it)["input"]["filters"].asJsonArray } - .let { it.first { f -> f["name"].asString == "album_id" } } - .let { it["value"].asString } + .let { json.decodeFromString(it)["input"]!!.jsonObject["filters"]!!.jsonArray } + .let { it.first { f -> f.jsonObject["name"]!!.jsonPrimitive.content == "album_id" } } + .let { it.jsonObject["value"]!!.jsonPrimitive.content } - var data = gson.fromJson(response.body!!.string()) - .let { it["data"]["picture"]["list"].asJsonObject } + var data = json.decodeFromString(response.body!!.string()) + .let { it["data"]!!.jsonObject["picture"]!!.jsonObject["list"]!!.jsonObject } while (nextPage) { - nextPage = data["info"]["has_next_page"].asBoolean - data["items"].asJsonArray.map { - val index = it["position"].asInt + nextPage = data["info"]!!.jsonObject["has_next_page"]!!.jsonPrimitive.boolean + data["items"]!!.jsonArray.map { + val index = it.jsonObject["position"]!!.jsonPrimitive.int val url = when (getResolutionPref()) { - "-1" -> it["url_to_original"].asString - else -> it["thumbnails"][getResolutionPref()?.toInt()!!]["url"].asString + "-1" -> it.jsonObject["url_to_original"]!!.jsonPrimitive.content + else -> it.jsonObject["thumbnails"]!!.jsonObject[getResolutionPref()?.toInt()!!]!!.jsonObject["url"]!!.jsonPrimitive.content } when { url.startsWith("//") -> pages.add(Page(index, "https:$url", "https:$url")) @@ -346,8 +347,8 @@ abstract class Luscious( } if (nextPage) { val newPage = client.newCall(GET(buildAlbumPicturesPageUrl(id, page))).execute() - data = gson.fromJson(newPage.body!!.string()) - .let { it["data"]["picture"]["list"].asJsonObject } + data = json.decodeFromString(newPage.body!!.string()) + .let { it["data"]!!.jsonObject["picture"]!!.jsonObject["list"]!!.jsonObject } } page++ } @@ -381,12 +382,12 @@ abstract class Luscious( return client.newCall(GET(page.url, headers)) .asObservableSuccess() .map { - val data = gson.fromJson(it.body!!.string()).let { data -> - data["data"]["picture"]["list"].asJsonObject + val data = json.decodeFromString(it.body!!.string()).let { data -> + data["data"]!!.jsonObject["picture"]!!.jsonObject["list"]!!.jsonObject } when (getResolutionPref()) { - "-1" -> data["items"].asJsonArray[page.index % 50].asJsonObject["url_to_original"].asString - else -> data["items"].asJsonArray[page.index % 50].asJsonObject["thumbnails"][getResolutionPref()?.toInt()!!]["url"].asString + "-1" -> data["items"]!!.jsonArray[page.index % 50].jsonObject["url_to_original"]!!.jsonPrimitive.content + else -> data["items"]!!.jsonArray[page.index % 50].jsonObject["thumbnails"]!!.jsonObject[getResolutionPref()?.toInt()!!]!!.jsonObject["url"]!!.jsonPrimitive.content } } } @@ -405,32 +406,32 @@ abstract class Luscious( } private fun detailsParse(response: Response): SManga { - val data = gson.fromJson(response.body!!.string()) - with(data["data"]["album"]["get"]) { + val data = json.decodeFromString(response.body!!.string()) + with(data["data"]!!.jsonObject["album"]!!.jsonObject["get"]!!.jsonObject) { val manga = SManga.create() - manga.url = this["url"].asString - manga.title = this["title"].asString - manga.thumbnail_url = this["cover"]["url"].asString + manga.url = this["url"]!!.jsonPrimitive.content + manga.title = this["title"]!!.jsonPrimitive.content + manga.thumbnail_url = this["cover"]!!.jsonObject["url"]!!.jsonPrimitive.content manga.status = 0 - manga.description = "${this["description"].asString}\n\nPictures: ${this["number_of_pictures"].asString}\nAnimated Pictures: ${this["number_of_animated_pictures"].asString}" - var genreList = this["language"]["title"].asString - for ((i, _) in this["labels"].asJsonArray.withIndex()) { - genreList = "$genreList, ${this["labels"][i].asString}" + manga.description = "${this["description"]!!.jsonPrimitive.content}\n\nPictures: ${this["number_of_pictures"]!!.jsonPrimitive.content}\nAnimated Pictures: ${this["number_of_animated_pictures"]!!.jsonPrimitive.content}" + var genreList = this["language"]!!.jsonObject["title"]!!.jsonPrimitive.content + for ((i, _) in this["labels"]!!.jsonArray.withIndex()) { + genreList = "$genreList, ${this["labels"]!!.jsonArray[i].jsonPrimitive.content}" } - for ((i, _) in this["genres"].asJsonArray.withIndex()) { - genreList = "$genreList, ${this["genres"][i]["title"].asString}" + for ((i, _) in this["genres"]!!.jsonArray.withIndex()) { + genreList = "$genreList, ${this["genres"]!!.jsonArray[i].jsonObject["title"]!!.jsonPrimitive.content}" } - for ((i, _) in this["audiences"].asJsonArray.withIndex()) { - genreList = "$genreList, ${this["audiences"][i]["title"].asString}" + for ((i, _) in this["audiences"]!!.jsonArray.withIndex()) { + genreList = "$genreList, ${this["audiences"]!!.jsonArray[i].jsonObject["title"]!!.jsonPrimitive.content}" } - for ((i, _) in this["tags"].asJsonArray.withIndex()) { - genreList = "$genreList, ${this["tags"][i]["text"].asString}" - if (this["tags"][i]["text"].asString.contains("Artist:")) { - manga.artist = this["tags"][i]["text"].asString.substringAfter(":").trim() + for ((i, _) in this["tags"]!!.jsonArray.withIndex()) { + genreList = "$genreList, ${this["tags"]!!.jsonArray[i].jsonObject["text"]!!.jsonPrimitive.content}" + if (this["tags"]!!.jsonArray[i].jsonObject["text"]!!.jsonPrimitive.content.contains("Artist:")) { + manga.artist = this["tags"]!!.jsonArray[i].jsonObject["text"]!!.jsonPrimitive.content.substringAfter(":").trim() manga.author = manga.artist } } - genreList = "$genreList, ${this["content"]["title"].asString}" + genreList = "$genreList, ${this["content"]!!.jsonObject["title"]!!.jsonPrimitive.content}" manga.genre = genreList return manga @@ -483,9 +484,9 @@ abstract class Luscious( private fun Filter<*>.toJsonObject(key: String): JsonObject { val value = this.toString() - return JsonObject().apply { - addProperty("name", key) - addProperty("value", value) + return buildJsonObject { + put("name", key) + put("value", value) } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMS.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMS.kt index ff453eacd..1847fbadc 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMS.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMS.kt @@ -2,13 +2,6 @@ package eu.kanade.tachiyomi.multisrc.mmrcms import android.annotation.SuppressLint import android.net.Uri -import com.github.salomonbrys.kotson.array -import com.github.salomonbrys.kotson.bool -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.string -import com.google.gson.JsonArray -import com.google.gson.JsonObject -import com.google.gson.JsonParser import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.model.Filter @@ -19,11 +12,20 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.boolean +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Element import rx.Observable +import uy.kohesive.injekt.injectLazy import java.text.ParseException import java.text.SimpleDateFormat import java.util.Locale @@ -33,7 +35,7 @@ abstract class MMRCMS( override val name: String, override val baseUrl: String, override val lang: String, - private val sourceInfo: String = "", + sourceInfo: String = "", ) : HttpSource() { open val jsonData = if (sourceInfo == "") { SourceData.giveMetaData(baseUrl) @@ -72,14 +74,15 @@ abstract class MMRCMS( * * */ - open val jsonObject = JsonParser.parseString(jsonData) as JsonObject - override val supportsLatest = jsonObject["supports_latest"].bool - open val itemUrl = jsonObject["item_url"].string - open val categoryMappings = mapToPairs(jsonObject["categories"].array) - open var tagMappings = if (jsonObject["tags"].isJsonArray) { - mapToPairs(jsonObject["tags"].asJsonArray) + private val json: Json by injectLazy() + val jsonObject = json.decodeFromString(jsonData) + override val supportsLatest = jsonObject["supports_latest"]!!.jsonPrimitive.boolean + open val itemUrl = jsonObject["item_url"]!!.jsonPrimitive.content + open val categoryMappings = mapToPairs(jsonObject["categories"]!!.jsonArray) + open var tagMappings = if (jsonObject["tags"] is JsonArray) { + mapToPairs(jsonObject["tags"]!!.jsonArray) } else { - emptyList>() + emptyList() } /** @@ -95,7 +98,7 @@ abstract class MMRCMS( open fun mapToPairs(array: JsonArray): List> = array.map { it as JsonObject - it["id"].string to it["name"].string + it["id"]!!.jsonPrimitive.content to it["name"]!!.jsonPrimitive.content } private val itemUrlPath = Uri.parse(itemUrl).pathSegments.firstOrNull() @@ -153,16 +156,16 @@ abstract class MMRCMS( override fun searchMangaParse(response: Response): MangasPage { return if (listOf("query", "q").any { it in response.request.url.queryParameterNames }) { // If a search query was specified, use search instead! - val jsonArray = JsonParser.parseString(response.body!!.string()).let { - it["suggestions"].array + val jsonArray = json.decodeFromString(response.body!!.string()).let { + it["suggestions"]!!.jsonArray } MangasPage( jsonArray .map { SManga.create().apply { - val segment = it["data"].string + val segment = it.jsonObject["data"]!!.jsonPrimitive.content url = getUrlWithoutBaseUrl(itemUrl + segment) - title = it["value"].string + title = it.jsonObject["value"]!!.jsonPrimitive.content // Guess thumbnails // thumbnail_url = "$baseUrl/uploads/manga/$segment/cover/cover_250x350.jpg" diff --git a/src/all/toomics/src/eu/kanade/tachiyomi/extension/all/toomics/ToomicsGlobal.kt b/src/all/toomics/src/eu/kanade/tachiyomi/extension/all/toomics/ToomicsGlobal.kt index 8d6e69244..fe245a359 100644 --- a/src/all/toomics/src/eu/kanade/tachiyomi/extension/all/toomics/ToomicsGlobal.kt +++ b/src/all/toomics/src/eu/kanade/tachiyomi/extension/all/toomics/ToomicsGlobal.kt @@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable @@ -73,7 +73,7 @@ abstract class ToomicsGlobal( .add("Content-Type", "application/x-www-form-urlencoded") .build() - val rbody = RequestBody.create(null, "toonData=$query&offset=0&limit=20") + val rbody = "toonData=$query&offset=0&limit=20".toRequestBody(null) return POST("$baseUrl/$siteLang/webtoon/ajax_search", newHeaders, rbody) } diff --git a/src/ar/gmanga/build.gradle b/src/ar/gmanga/build.gradle index ad435ab75..98163747e 100644 --- a/src/ar/gmanga/build.gradle +++ b/src/ar/gmanga/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'GMANGA' diff --git a/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/Gmanga.kt b/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/Gmanga.kt index 2abf35991..bda21d9b8 100644 --- a/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/Gmanga.kt +++ b/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/Gmanga.kt @@ -1,13 +1,6 @@ package eu.kanade.tachiyomi.extension.ar.gmanga import androidx.preference.PreferenceScreen -import com.github.salomonbrys.kotson.fromJson -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.nullString -import com.github.salomonbrys.kotson.toJsonArray -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonObject import eu.kanade.tachiyomi.extension.ar.gmanga.GmangaPreferences.Companion.PREF_CHAPTER_LISTING import eu.kanade.tachiyomi.extension.ar.gmanga.GmangaPreferences.Companion.PREF_CHAPTER_LISTING_SHOW_POPULAR import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor @@ -21,12 +14,24 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.float +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.long import okhttp3.Headers import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response +import uy.kohesive.injekt.injectLazy class Gmanga : ConfigurableSource, HttpSource() { @@ -40,7 +45,7 @@ class Gmanga : ConfigurableSource, HttpSource() { override val supportsLatest: Boolean = true - private val gson = Gson() + private val json: Json by injectLazy() private val preferences = GmangaPreferences(id) @@ -67,18 +72,18 @@ class Gmanga : ConfigurableSource, HttpSource() { val chapters: List = buildList { val allChapters: ArrayList = ArrayList() - data["rows"][0]["rows"].asJsonArray.forEach { release -> - val chapter = data["rows"][2]["rows"].asJsonArray.filter { it[0] == release[4] }.toJsonArray() - chapter.asJsonArray.forEach { release.asJsonArray.addAll(it.asJsonArray) } - val team = data["rows"][1]["rows"].asJsonArray.filter { it[0] == release[5] }.toJsonArray() - team.asJsonArray.forEach { release.asJsonArray.addAll(it.asJsonArray) } - allChapters.add(release.asJsonArray) + data["rows"]!!.jsonArray[0].jsonObject["rows"]!!.jsonArray.forEach { release -> + val chapter = data["rows"]!!.jsonArray[2].jsonObject["rows"]!!.jsonArray.filter { it.jsonArray[0] == release.jsonArray[4] } + allChapters.addAll(chapter.map { it.jsonArray }) + val team = data["rows"]!!.jsonArray[1].jsonObject["rows"]!!.jsonArray.filter { it.jsonArray[0] == release.jsonArray[5] } + allChapters.addAll(team.map { it.jsonArray }) + allChapters.add(release.jsonArray) } when (preferences.getString(PREF_CHAPTER_LISTING)) { PREF_CHAPTER_LISTING_SHOW_POPULAR -> addAll( - allChapters.groupBy { it.asJsonArray[4].asFloat } - .map { (_: Float, versions: List) -> versions.maxByOrNull { it[5].asLong }!! } + allChapters.groupBy { it.jsonArray[4].jsonPrimitive.float } + .map { (_: Float, versions: List) -> versions.maxByOrNull { it[5].jsonPrimitive.float }!! } ) else -> addAll(allChapters) } @@ -86,14 +91,14 @@ class Gmanga : ConfigurableSource, HttpSource() { return chapters.map { SChapter.create().apply { - chapter_number = it[8].asFloat + chapter_number = it[8].jsonPrimitive.float - val chapterName = it[10].asString.let { if (it.trim() != "") " - $it" else "" } + val chapterName = it[10].jsonPrimitive.content.let { if (it.trim() != "") " - $it" else "" } url = "/r/${it[0]}" name = "${chapter_number.let { if (it % 1 > 0) it else it.toInt() }}$chapterName" - date_upload = it[2].asLong * 1000 - scanlator = it[13].asString + date_upload = it[2].jsonPrimitive.long * 1000 + scanlator = it[13].jsonPrimitive.content } } } @@ -101,16 +106,16 @@ class Gmanga : ConfigurableSource, HttpSource() { override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used") override fun latestUpdatesParse(response: Response): MangasPage { - val data = gson.fromJson(response.asJsoup().select(".js-react-on-rails-component").html()) + val data = json.decodeFromString(response.asJsoup().select(".js-react-on-rails-component").html()) return MangasPage( - data["mangaDataAction"]["newMangas"].asJsonArray.map { + data["mangaDataAction"]!!.jsonObject["newMangas"]!!.jsonArray.map { SManga.create().apply { - url = "/mangas/${it["id"].asString}" - title = it["title"].asString + url = "/mangas/${it.jsonObject["id"]!!.jsonPrimitive.content}" + title = it.jsonObject["title"]!!.jsonPrimitive.content - thumbnail_url = it["cover"].nullString?.let { coverFileName -> + thumbnail_url = it.jsonObject["cover"]!!.jsonPrimitive.contentOrNull?.let { coverFileName -> val thumbnail = "medium_${coverFileName.substringBeforeLast(".")}.webp" - "https://media.$domain/uploads/manga/cover/${it["id"].asString}/$thumbnail" + "https://media.$domain/uploads/manga/cover/${it.jsonObject["id"]!!.jsonPrimitive.content}/$thumbnail" } } }, @@ -123,27 +128,27 @@ class Gmanga : ConfigurableSource, HttpSource() { } override fun mangaDetailsParse(response: Response): SManga { - val data = gson.fromJson(response.asJsoup().select(".js-react-on-rails-component").html()) - val mangaData = data["mangaDataAction"]["mangaData"].asJsonObject + val data = json.decodeFromString(response.asJsoup().select(".js-react-on-rails-component").html()) + val mangaData = data["mangaDataAction"]!!.jsonObject["mangaData"]!!.jsonObject return SManga.create().apply { - description = mangaData["summary"].nullString ?: "" - artist = mangaData["artists"].asJsonArray.joinToString(", ") { it.asJsonObject["name"].asString } - author = mangaData["authors"].asJsonArray.joinToString(", ") { it.asJsonObject["name"].asString } - genre = mangaData["categories"].asJsonArray.joinToString(", ") { it.asJsonObject["name"].asString } + description = mangaData["summary"]!!.jsonPrimitive.contentOrNull ?: "" + artist = mangaData["artists"]!!.jsonArray.joinToString(", ") { it.jsonObject["name"]!!.jsonPrimitive.content } + author = mangaData["authors"]!!.jsonArray.joinToString(", ") { it.jsonObject["name"]!!.jsonPrimitive.content } + genre = mangaData["categories"]!!.jsonArray.joinToString(", ") { it.jsonObject["name"]!!.jsonPrimitive.content } } } override fun pageListParse(response: Response): List { val url = response.request.url.toString() - val data = gson.fromJson(response.asJsoup().select(".js-react-on-rails-component").html()) - val releaseData = data["readerDataAction"]["readerData"]["release"].asJsonObject + val data = json.decodeFromString(response.asJsoup().select(".js-react-on-rails-component").html()) + val releaseData = data["readerDataAction"]!!.jsonObject["readerData"]!!.jsonObject["release"]!!.jsonObject - val hasWebP = releaseData["webp_pages"].asJsonArray.size() > 0 - return releaseData[if (hasWebP) "webp_pages" else "pages"].asJsonArray.map { it.asString }.mapIndexed { index, pageUri -> + val hasWebP = releaseData["webp_pages"]!!.jsonArray.size > 0 + return releaseData[if (hasWebP) "webp_pages" else "pages"]!!.jsonArray.map { it.jsonPrimitive.content }.mapIndexed { index, pageUri -> Page( index, "$url#page_$index", - "https://media.$domain/uploads/releases/${releaseData["storage_key"].asString}/hq${if (hasWebP) "_webp" else ""}/$pageUri" + "https://media.$domain/uploads/releases/${releaseData["storage_key"]!!.jsonPrimitive.content}/hq${if (hasWebP) "_webp" else ""}/$pageUri" ) } } @@ -154,29 +159,29 @@ class Gmanga : ConfigurableSource, HttpSource() { override fun searchMangaParse(response: Response): MangasPage { val data = decryptResponse(response) - val mangas = data["mangas"].asJsonArray + val mangas = data["mangas"]!!.jsonArray return MangasPage( - mangas.asJsonArray.map { + mangas.jsonArray.map { SManga.create().apply { - url = "/mangas/${it["id"].asString}" - title = it["title"].asString - val thumbnail = "medium_${it["cover"].asString.substringBeforeLast(".")}.webp" - thumbnail_url = "https://media.$domain/uploads/manga/cover/${it["id"].asString}/$thumbnail" + url = "/mangas/${it.jsonObject["id"]!!.jsonPrimitive.content}" + title = it.jsonObject["title"]!!.jsonPrimitive.content + val thumbnail = "medium_${it.jsonObject["cover"]!!.jsonPrimitive.content.substringBeforeLast(".")}.webp" + thumbnail_url = "https://media.$domain/uploads/manga/cover/${it.jsonObject["id"]!!.jsonPrimitive.content}/$thumbnail" } }, - mangas.size() == 50 + mangas.size == 50 ) } private fun decryptResponse(response: Response): JsonObject { - val encryptedData = gson.fromJson(response.body!!.string())["data"].asString + val encryptedData = json.decodeFromString(response.body!!.string())["data"]!!.jsonPrimitive.content val decryptedData = decrypt(encryptedData) - return gson.fromJson(decryptedData) + return json.decodeFromString(decryptedData) } override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { return GmangaFilters.buildSearchPayload(page, query, if (filters.isEmpty()) getFilterList() else filters).let { - val body = RequestBody.create(MEDIA_TYPE, it.toString()) + val body = it.toString().toRequestBody(MEDIA_TYPE) POST("$baseUrl/api/mangas/search", headers, body) } } diff --git a/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/GmangaFilters.kt b/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/GmangaFilters.kt index 6c816697c..b77f09532 100644 --- a/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/GmangaFilters.kt +++ b/src/ar/gmanga/src/eu/kanade/tachiyomi/extension/ar/gmanga/GmangaFilters.kt @@ -1,14 +1,16 @@ package eu.kanade.tachiyomi.extension.ar.gmanga import android.annotation.SuppressLint -import com.github.salomonbrys.kotson.addAll -import com.github.salomonbrys.kotson.addProperty -import com.google.gson.JsonArray -import com.google.gson.JsonNull -import com.google.gson.JsonObject import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList -import java.lang.Exception +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonObjectBuilder +import kotlinx.serialization.json.add +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.put +import kotlinx.serialization.json.putJsonArray +import kotlinx.serialization.json.putJsonObject import java.text.ParseException import java.text.SimpleDateFormat @@ -35,139 +37,90 @@ class GmangaFilters() { val dateRangeFilter = filters.findInstance()!! val categoryFilter = filters.findInstance()!! - return JsonObject().apply { - + return buildJsonObject { oneShotFilter.state.first().let { when { - it.isIncluded() -> addProperty("oneshot", true) - it.isExcluded() -> addProperty("oneshot", false) - else -> addProperty("oneshot", JsonNull.INSTANCE) + it.isIncluded() -> put("oneshot", true) + it.isExcluded() -> put("oneshot", false) + else -> put("oneshot", JsonNull) } } - addProperty("title", query) - addProperty("page", page) - addProperty( - "manga_types", - JsonObject().apply { - - addProperty( - "include", - JsonArray().apply { - addAll(mangaTypeFilter.state.filter { it.isIncluded() }.map { it.id }) - } - ) - - addProperty( - "exclude", - JsonArray().apply { - addAll(mangaTypeFilter.state.filter { it.isExcluded() }.map { it.id }) - } - ) + put("title", query) + put("page", page) + putJsonObject("manga_types") { + putJsonArray("include") { + mangaTypeFilter.state.filter { it.isIncluded() }.map { it.id }.forEach { add(it) } } - ) - addProperty( - "story_status", - JsonObject().apply { - addProperty( - "include", - JsonArray().apply { - addAll(storyStatusFilter.state.filter { it.isIncluded() }.map { it.id }) - } - ) - - addProperty( - "exclude", - JsonArray().apply { - addAll(storyStatusFilter.state.filter { it.isExcluded() }.map { it.id }) - } - ) + putJsonArray("exclude") { + mangaTypeFilter.state.filter { it.isExcluded() }.map { it.id }.forEach { add(it) } } - ) - addProperty( - "translation_status", - JsonObject().apply { - - addProperty( - "include", - JsonArray().apply { - addAll(translationStatusFilter.state.filter { it.isIncluded() }.map { it.id }) - } - ) - - addProperty( - "exclude", - JsonArray().apply { - addAll(translationStatusFilter.state.filter { it.isExcluded() }.map { it.id }) - } - ) + } + putJsonObject("story_status") { + putJsonArray("include") { + storyStatusFilter.state.filter { it.isIncluded() }.map { it.id }.forEach { add(it) } } - ) - addProperty( - "categories", - JsonObject().apply { - addProperty( - "include", - JsonArray().apply { - add(JsonNull.INSTANCE) // always included, maybe to avoid shifting index in the backend - addAll(categoryFilter.state.filter { it.isIncluded() }.map { it.id }) - } - ) - - addProperty( - "exclude", - JsonArray().apply { - addAll(categoryFilter.state.filter { it.isExcluded() }.map { it.id }) - } - ) + putJsonArray("exclude") { + storyStatusFilter.state.filter { it.isExcluded() }.map { it.id }.forEach { add(it) } } - ) - addProperty( - "chapters", - JsonObject().apply { - - addPropertyFromValidatingTextFilter( - chapterCountFilter.state.first { - it.id == FILTER_ID_MIN_CHAPTER_COUNT - }, - "min", - ERROR_INVALID_MIN_CHAPTER_COUNT, - "" - ) - - addPropertyFromValidatingTextFilter( - chapterCountFilter.state.first { - it.id == FILTER_ID_MAX_CHAPTER_COUNT - }, - "max", - ERROR_INVALID_MAX_CHAPTER_COUNT, - "" - ) + } + putJsonObject("translation_status") { + putJsonArray("include") { + translationStatusFilter.state.filter { it.isIncluded() }.map { it.id }.forEach { add(it) } } - ) - addProperty( - "dates", - JsonObject().apply { - addPropertyFromValidatingTextFilter( - dateRangeFilter.state.first { - it.id == FILTER_ID_START_DATE - }, - "start", - ERROR_INVALID_START_DATE - ) - - addPropertyFromValidatingTextFilter( - dateRangeFilter.state.first { - it.id == FILTER_ID_END_DATE - }, - "end", - ERROR_INVALID_END_DATE - ) + putJsonArray("exclude") { + translationStatusFilter.state.filter { it.isExcluded() }.map { it.id }.forEach { add(it) } } - ) + } + putJsonObject("categories") { + putJsonArray("include") { + add(JsonNull) // always included, maybe to avoid shifting index in the backend + categoryFilter.state.filter { it.isIncluded() }.map { it.id }.forEach { add(it) } + } + + putJsonArray("exclude") { + categoryFilter.state.filter { it.isExcluded() }.map { it.id }.forEach { add(it) } + } + } + putJsonObject("chapters") { + putFromValidatingTextFilter( + chapterCountFilter.state.first { + it.id == FILTER_ID_MIN_CHAPTER_COUNT + }, + "min", + ERROR_INVALID_MIN_CHAPTER_COUNT, + "" + ) + + putFromValidatingTextFilter( + chapterCountFilter.state.first { + it.id == FILTER_ID_MAX_CHAPTER_COUNT + }, + "max", + ERROR_INVALID_MAX_CHAPTER_COUNT, + "" + ) + } + putJsonObject("dates") { + putFromValidatingTextFilter( + dateRangeFilter.state.first { + it.id == FILTER_ID_START_DATE + }, + "start", + ERROR_INVALID_START_DATE + ) + + putFromValidatingTextFilter( + dateRangeFilter.state.first { + it.id == FILTER_ID_END_DATE + }, + "end", + ERROR_INVALID_END_DATE + ) + } } } @@ -298,7 +251,7 @@ class GmangaFilters() { } } - private fun JsonObject.addPropertyFromValidatingTextFilter( + private fun JsonObjectBuilder.putFromValidatingTextFilter( filter: ValidatingTextFilter, property: String, invalidErrorMessage: String, @@ -307,9 +260,9 @@ class GmangaFilters() { filter.let { when { it.state == "" -> if (default == null) { - addProperty(property, JsonNull.INSTANCE) - } else addProperty(property, default) - it.isValid() -> addProperty(property, it.state) + put(property, JsonNull) + } else put(property, default) + it.isValid() -> put(property, it.state) else -> throw Exception(invalidErrorMessage) } } diff --git a/src/de/mangatube/build.gradle b/src/de/mangatube/build.gradle index c7bc04b1b..2f2eeef89 100644 --- a/src/de/mangatube/build.gradle +++ b/src/de/mangatube/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'Manga Tube' diff --git a/src/de/mangatube/src/eu/kanade/tachiyomi/extension/de/mangatube/MangaTube.kt b/src/de/mangatube/src/eu/kanade/tachiyomi/extension/de/mangatube/MangaTube.kt index 0b506b185..d1fe108f1 100644 --- a/src/de/mangatube/src/eu/kanade/tachiyomi/extension/de/mangatube/MangaTube.kt +++ b/src/de/mangatube/src/eu/kanade/tachiyomi/extension/de/mangatube/MangaTube.kt @@ -1,10 +1,5 @@ package eu.kanade.tachiyomi.extension.de.mangatube -import com.github.salomonbrys.kotson.fromJson -import com.github.salomonbrys.kotson.get -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.asObservableSuccess @@ -14,14 +9,22 @@ 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.ParsedHttpSource +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable +import uy.kohesive.injekt.injectLazy import java.text.ParseException import java.text.SimpleDateFormat import java.util.Locale @@ -45,7 +48,7 @@ class MangaTube : ParsedHttpSource() { private val xhrHeaders: Headers = headersBuilder().add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8").build() - private val gson by lazy { Gson() } + private val json: Json by injectLazy() // Popular @@ -59,21 +62,21 @@ class MangaTube : ParsedHttpSource() { override fun popularMangaRequest(page: Int): Request { val rbodyContent = "action=load_series_list_entries¶meter%5Bpage%5D=$page¶meter%5Bletter%5D=¶meter%5Bsortby%5D=popularity¶meter%5Border%5D=asc" - return POST("$baseUrl/ajax", xhrHeaders, RequestBody.create(null, rbodyContent)) + return POST("$baseUrl/ajax", xhrHeaders, rbodyContent.toRequestBody(null)) } // popular uses "success" as a key, search uses "suggestions" // for future reference: if adding filters, advanced search might use a different key private fun parseMangaFromJson(response: Response, hasNextPage: Boolean): MangasPage { var titleKey = "manga_title" - val mangas = gson.fromJson(response.body!!.string()) - .let { it["success"] ?: it["suggestions"].also { titleKey = "value" } } - .asJsonArray + val mangas = json.decodeFromString(response.body!!.string()) + .let { it["success"] ?: it["suggestions"].also { titleKey = "value" } }!! + .jsonArray .map { json -> SManga.create().apply { - title = json[titleKey].asString - url = "/series/${json["manga_slug"].asString}" - thumbnail_url = json["covers"][0]["img_name"].asString + title = json.jsonObject[titleKey]!!.jsonPrimitive.content + url = "/series/${json.jsonObject["manga_slug"]!!.jsonPrimitive.content}" + thumbnail_url = json.jsonObject["covers"]!!.jsonArray[0].jsonObject["img_name"]!!.jsonPrimitive.content } } return MangasPage(mangas, hasNextPage) @@ -109,7 +112,7 @@ class MangaTube : ParsedHttpSource() { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val rbodyContent = "action=search_query¶meter%5Bquery%5D=$query" - return POST("$baseUrl/ajax", xhrHeaders, RequestBody.create(null, rbodyContent)) + return POST("$baseUrl/ajax", xhrHeaders, rbodyContent.toRequestBody(null)) } override fun searchMangaParse(response: Response): MangasPage { @@ -173,8 +176,8 @@ class MangaTube : ParsedHttpSource() { val jsonArray = Regex("""pages: (\[.*]),""").find(script)?.groupValues?.get(1) ?: throw Exception("Couldn't find JSON array") - return gson.fromJson(jsonArray).mapIndexed { i, json -> - Page(i, "", imagePath + json.asJsonObject["file_name"].asString) + return json.decodeFromString(jsonArray).mapIndexed { i, json -> + Page(i, "", imagePath + json.jsonObject["file_name"]!!.jsonPrimitive.content) } } diff --git a/src/en/mangahub/build.gradle b/src/en/mangahub/build.gradle index 92d734c22..eb775bce2 100644 --- a/src/en/mangahub/build.gradle +++ b/src/en/mangahub/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'Mangahub' diff --git a/src/en/mangahub/src/eu/kanade/tachiyomi/extension/en/mangahub/Mangahub.kt b/src/en/mangahub/src/eu/kanade/tachiyomi/extension/en/mangahub/Mangahub.kt index e4969dba8..1a12c3f2c 100644 --- a/src/en/mangahub/src/eu/kanade/tachiyomi/extension/en/mangahub/Mangahub.kt +++ b/src/en/mangahub/src/eu/kanade/tachiyomi/extension/en/mangahub/Mangahub.kt @@ -1,11 +1,5 @@ package eu.kanade.tachiyomi.extension.en.mangahub -import com.github.salomonbrys.kotson.fromJson -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.keys -import com.github.salomonbrys.kotson.string -import com.google.gson.Gson -import com.google.gson.JsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.model.Filter @@ -14,12 +8,18 @@ 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.ParsedHttpSource +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import uy.kohesive.injekt.injectLazy import java.net.URL import java.text.ParseException import java.text.SimpleDateFormat @@ -156,21 +156,26 @@ class Mangahub : ParsedHttpSource() { val slug = chapter.url.substringAfter("chapter/").substringBefore("/") val number = chapter.url.substringAfter("chapter-").removeSuffix("/") - val body = RequestBody.create(null, "{\"query\":\"{chapter(x:m01,slug:\\\"$slug\\\",number:$number){id,title,mangaID,number,slug,date,pages,noAd,manga{id,title,slug,mainSlug,author,isWebtoon,isYaoi,isPorn,isSoftPorn,unauthFile,isLicensed}}}\"}") + val body = + "{\"query\":\"{chapter(x:m01,slug:\\\"$slug\\\",number:$number){id,title,mangaID,number,slug,date,pages,noAd,manga{id,title,slug,mainSlug,author,isWebtoon,isYaoi,isPorn,isSoftPorn,unauthFile,isLicensed}}}\"}".toRequestBody( + null + ) return POST("https://api.mghubcdn.com/graphql", jsonHeaders, body) } - private val gson = Gson() + private val json: Json by injectLazy() override fun pageListParse(response: Response): List { val cdn = "https://img.mghubcdn.com/file/imghub" - return gson.fromJson(response.body!!.string())["data"]["chapter"]["pages"].string + return json.decodeFromString(response.body!!.string())["data"]!! + .jsonObject["chapter"]!! + .jsonObject["pages"]!!.jsonPrimitive.content .removeSurrounding("\"").replace("\\", "") .let { cleaned -> - val jsonObject = gson.fromJson(cleaned) - jsonObject.keys().map { key -> jsonObject[key].string } + val jsonObject = json.decodeFromString(cleaned) + jsonObject.keys.map { key -> jsonObject[key]!!.jsonPrimitive.content } } .mapIndexed { i, tail -> Page(i, "", "$cdn/$tail") } } diff --git a/src/en/mangarockes/build.gradle b/src/en/mangarockes/build.gradle index 8a277a004..3c4b6acc5 100644 --- a/src/en/mangarockes/build.gradle +++ b/src/en/mangarockes/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'MangaRock.es' diff --git a/src/en/mangarockes/src/eu/kanade/tachiyomi/extension/en/mangarockes/MangaRockEs.kt b/src/en/mangarockes/src/eu/kanade/tachiyomi/extension/en/mangarockes/MangaRockEs.kt index 3395fb19b..ae18d53b5 100644 --- a/src/en/mangarockes/src/eu/kanade/tachiyomi/extension/en/mangarockes/MangaRockEs.kt +++ b/src/en/mangarockes/src/eu/kanade/tachiyomi/extension/en/mangarockes/MangaRockEs.kt @@ -1,8 +1,5 @@ package eu.kanade.tachiyomi.extension.en.mangarockes -import com.github.salomonbrys.kotson.fromJson -import com.google.gson.Gson -import com.google.gson.JsonArray import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList @@ -10,6 +7,11 @@ 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.ParsedHttpSource +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient @@ -18,6 +20,7 @@ import okhttp3.Response import okhttp3.ResponseBody.Companion.toResponseBody import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale @@ -160,13 +163,13 @@ class MangaRockEs : ParsedHttpSource() { // Pages - private val gson by lazy { Gson() } + private val json: Json by injectLazy() override fun pageListParse(response: Response): List { val responseString = response.body!!.string() return Regex("""mangaData = (\[.*]);""", RegexOption.IGNORE_CASE).find(responseString)?.groupValues?.get(1)?.let { array -> - gson.fromJson(array) - .mapIndexed { i, jsonElement -> Page(i, "", jsonElement.asJsonObject["url"].asString) } + json.decodeFromString(array) + .mapIndexed { i, jsonElement -> Page(i, "", jsonElement.jsonObject["url"]!!.jsonPrimitive.content) } } ?: Regex("""getManga\(\d+, '(http.*)',""").findAll(responseString).toList() .mapIndexed { i, mr -> Page(i, "", mr.groupValues[1]) } diff --git a/src/en/manhuamanga/src/eu/kanade/tachiyomi/extension/en/manhuamanga/ManhuaManga.kt b/src/en/manhuamanga/src/eu/kanade/tachiyomi/extension/en/manhuamanga/ManhuaManga.kt index 84f915762..c5e279b02 100644 --- a/src/en/manhuamanga/src/eu/kanade/tachiyomi/extension/en/manhuamanga/ManhuaManga.kt +++ b/src/en/manhuamanga/src/eu/kanade/tachiyomi/extension/en/manhuamanga/ManhuaManga.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.util.asJsoup import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -69,7 +69,7 @@ class ManhuaManga : ParsedHttpSource() { protected fun getXhrChapters(mangaId: String): Document { val xhrHeaders = headersBuilder().add("Content-Type: application/x-www-form-urlencoded; charset=UTF-8") .build() - val body = RequestBody.create(null, "action=tw_ajax&type=list_chap&id=$mangaId") + val body = "action=tw_ajax&type=list_chap&id=$mangaId".toRequestBody(null) return client.newCall(POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, body)).execute().asJsoup() } diff --git a/src/en/manhwamanga/src/eu/kanade/tachiyomi/extension/en/manhwamanga/ManhwaManga.kt b/src/en/manhwamanga/src/eu/kanade/tachiyomi/extension/en/manhwamanga/ManhwaManga.kt index 1b68aff43..2100f5c70 100644 --- a/src/en/manhwamanga/src/eu/kanade/tachiyomi/extension/en/manhwamanga/ManhwaManga.kt +++ b/src/en/manhwamanga/src/eu/kanade/tachiyomi/extension/en/manhwamanga/ManhwaManga.kt @@ -11,7 +11,7 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.util.asJsoup import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -69,7 +69,7 @@ class ManhwaManga : ParsedHttpSource() { protected fun getXhrChapters(mangaId: String): Document { val xhrHeaders = headersBuilder().add("Content-Type: application/x-www-form-urlencoded; charset=UTF-8") .build() - val body = RequestBody.create(null, "action=tw_ajax&type=list_chap&id=$mangaId") + val body = "action=tw_ajax&type=list_chap&id=$mangaId".toRequestBody(null) return client.newCall(POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, body)).execute().asJsoup() } diff --git a/src/en/readmanhwa/build.gradle b/src/en/readmanhwa/build.gradle index 8d6ce23d1..eaefd9446 100644 --- a/src/en/readmanhwa/build.gradle +++ b/src/en/readmanhwa/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'ReadManhwa' diff --git a/src/en/readmanhwa/src/eu/kanade/tachiyomi/extension/en/readmanhwa/ReadManhwa.kt b/src/en/readmanhwa/src/eu/kanade/tachiyomi/extension/en/readmanhwa/ReadManhwa.kt index 0f6125c4b..e775756ce 100644 --- a/src/en/readmanhwa/src/eu/kanade/tachiyomi/extension/en/readmanhwa/ReadManhwa.kt +++ b/src/en/readmanhwa/src/eu/kanade/tachiyomi/extension/en/readmanhwa/ReadManhwa.kt @@ -2,14 +2,6 @@ package eu.kanade.tachiyomi.extension.en.readmanhwa import android.app.Application import android.content.SharedPreferences -import com.github.salomonbrys.kotson.fromJson -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.int -import com.github.salomonbrys.kotson.nullString -import com.github.salomonbrys.kotson.string -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.ConfigurableSource @@ -20,6 +12,15 @@ 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.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.int +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.OkHttpClient @@ -28,6 +29,7 @@ import okhttp3.Response import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale @@ -54,20 +56,20 @@ class ReadManhwa : ConfigurableSource, HttpSource() { override val client: OkHttpClient = network.cloudflareClient - private val gson = Gson() + private val json: Json by injectLazy() private fun parseMangaFromJson(response: Response): MangasPage { - val jsonObject = gson.fromJson(response.body!!.string()) + val jsonObject = json.decodeFromString(response.body!!.string()) - val mangas = jsonObject["data"].asJsonArray.map { json -> + val mangas = jsonObject["data"]!!.jsonArray.map { json -> SManga.create().apply { - title = json["title"].string - thumbnail_url = json["image_url"].string - url = json["slug"].string + title = json.jsonObject["title"]!!.jsonPrimitive.content + thumbnail_url = json.jsonObject["image_url"]!!.jsonPrimitive.content + url = json.jsonObject["slug"]!!.jsonPrimitive.content } } - return MangasPage(mangas, jsonObject["current_page"].int < jsonObject["last_page"].int) + return MangasPage(mangas, jsonObject["current_page"]!!.jsonPrimitive.int < jsonObject["last_page"]!!.jsonPrimitive.int) } private fun getMangaUrl(url: String): String { return url.toHttpUrlOrNull()!!.newBuilder() @@ -159,15 +161,15 @@ class ReadManhwa : ConfigurableSource, HttpSource() { } override fun mangaDetailsParse(response: Response): SManga { - val jsonObject = gson.fromJson(response.body!!.string()) + val jsonObject = json.decodeFromString(response.body!!.string()) return SManga.create().apply { - description = jsonObject["description"].nullString - status = jsonObject["status"].nullString.toStatus() - thumbnail_url = jsonObject["image_url"].nullString - genre = try { jsonObject["tags"].asJsonArray.joinToString { it["name"].string } } catch (_: Exception) { null } - artist = try { jsonObject["artists"].asJsonArray.joinToString { it["name"].string } } catch (_: Exception) { null } - author = try { jsonObject["authors"].asJsonArray.joinToString { it["name"].string } } catch (_: Exception) { null } + description = jsonObject["description"]!!.jsonPrimitive.contentOrNull + status = jsonObject["status"]!!.jsonPrimitive.contentOrNull.toStatus() + thumbnail_url = jsonObject["image_url"]!!.jsonPrimitive.contentOrNull + genre = try { jsonObject["tags"]!!.jsonArray.joinToString { it.jsonObject["name"]!!.jsonPrimitive.content } } catch (_: Exception) { null } + artist = try { jsonObject["artists"]!!.jsonArray.joinToString { it.jsonObject["name"]!!.jsonPrimitive.content } } catch (_: Exception) { null } + author = try { jsonObject["authors"]!!.jsonArray.joinToString { it.jsonObject["name"]!!.jsonPrimitive.content } } catch (_: Exception) { null } } } @@ -193,11 +195,11 @@ class ReadManhwa : ConfigurableSource, HttpSource() { } private fun chapterListParse(response: Response, titleSlug: String): List { - return gson.fromJson(response.body!!.string()).map { json -> + return json.decodeFromString(response.body!!.string()).map { json -> SChapter.create().apply { - name = json["name"].string - url = "$titleSlug/${json["slug"].string}" - date_upload = json["added_at"].string.let { dateString -> + name = json.jsonObject["name"]!!.jsonPrimitive.content + url = "$titleSlug/${json.jsonObject["slug"]!!.jsonPrimitive.content}" + date_upload = json.jsonObject["added_at"]!!.jsonPrimitive.content.let { dateString -> if (dateString.contains("ago")) { val trimmedDate = dateString.substringBefore(" ago").removeSuffix("s").split(" ") val calendar = Calendar.getInstance() @@ -225,8 +227,8 @@ class ReadManhwa : ConfigurableSource, HttpSource() { } override fun pageListParse(response: Response): List { - return gson.fromJson(response.body!!.string())["images"].asJsonArray.mapIndexed { i, json -> - Page(i, "", json["source_url"].string) + return json.decodeFromString(response.body!!.string())["images"]!!.jsonArray.mapIndexed { i, json -> + Page(i, "", json.jsonObject["source_url"]!!.jsonPrimitive.content) } } diff --git a/src/es/doujinyang/src/eu/kanade/tachiyomi/extension/es/doujinyang/DoujinYang.kt b/src/es/doujinyang/src/eu/kanade/tachiyomi/extension/es/doujinyang/DoujinYang.kt index d11bce40c..073c8ea75 100644 --- a/src/es/doujinyang/src/eu/kanade/tachiyomi/extension/es/doujinyang/DoujinYang.kt +++ b/src/es/doujinyang/src/eu/kanade/tachiyomi/extension/es/doujinyang/DoujinYang.kt @@ -12,7 +12,7 @@ import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.util.asJsoup import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -131,7 +131,7 @@ class DoujinYang : ParsedHttpSource() { return POST( baseUrl + chapter.url, headersBuilder().add("Content-Type", "application/x-www-form-urlencoded").build(), - RequestBody.create(null, "info") + "info".toRequestBody(null) ) } diff --git a/src/es/kumanga/src/eu/kanade/tachiyomi/extension/es/kumanga/Kumanga.kt b/src/es/kumanga/src/eu/kanade/tachiyomi/extension/es/kumanga/Kumanga.kt index cd169397c..3a4ea4084 100755 --- a/src/es/kumanga/src/eu/kanade/tachiyomi/extension/es/kumanga/Kumanga.kt +++ b/src/es/kumanga/src/eu/kanade/tachiyomi/extension/es/kumanga/Kumanga.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.extension.es.kumanga import android.util.Base64 -import com.github.salomonbrys.kotson.jsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.model.Filter diff --git a/src/ru/comx/build.gradle b/src/ru/comx/build.gradle index f6a6373d1..420a183e7 100644 --- a/src/ru/comx/build.gradle +++ b/src/ru/comx/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'ComX' diff --git a/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt b/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt index 860f5a997..e0691b3f2 100644 --- a/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt +++ b/src/ru/comx/src/eu/kanade/tachiyomi/extension/ru/comx/ComX.kt @@ -1,9 +1,5 @@ package eu.kanade.tachiyomi.extension.ru.comx -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.nullArray -import com.github.salomonbrys.kotson.obj -import com.google.gson.JsonParser import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST @@ -15,6 +11,12 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.FormBody import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrlOrNull @@ -23,12 +25,16 @@ import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.concurrent.TimeUnit class ComX : ParsedHttpSource() { + + private val json: Json by injectLazy() + override val name = "Com-x" override val baseUrl = "https://com-x.life" @@ -186,13 +192,13 @@ class ComX : ParsedHttpSource() { .substringBefore("") .substringBeforeLast(";") - val data = JsonParser.parseString(dataStr).obj - val chaptersList = data["chapters"].nullArray + val data = json.decodeFromString(dataStr) + val chaptersList = data["chapters"]?.jsonArray val chapters: List? = chaptersList?.map { val chapter = SChapter.create() - chapter.name = it["title"].asString - chapter.date_upload = parseDate(it["date"].asString) - chapter.setUrlWithoutDomain("/readcomix/" + data["news_id"] + "/" + it["id"] + ".html") + chapter.name = it.jsonObject["title"]!!.jsonPrimitive.content + chapter.date_upload = parseDate(it.jsonObject["date"]!!.jsonPrimitive.content) + chapter.setUrlWithoutDomain("/readcomix/" + data["news_id"] + "/" + it.jsonObject["id"]!!.jsonPrimitive.content + ".html") chapter } return chapters ?: emptyList() diff --git a/src/ru/libmanga/build.gradle b/src/ru/libmanga/build.gradle index d8604de3f..142032cff 100644 --- a/src/ru/libmanga/build.gradle +++ b/src/ru/libmanga/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'MangaLib' diff --git a/src/ru/libmanga/src/eu/kanade/tachiyomi/extension/ru/libmanga/LibManga.kt b/src/ru/libmanga/src/eu/kanade/tachiyomi/extension/ru/libmanga/LibManga.kt index 01548c165..9b6b6b497 100644 --- a/src/ru/libmanga/src/eu/kanade/tachiyomi/extension/ru/libmanga/LibManga.kt +++ b/src/ru/libmanga/src/eu/kanade/tachiyomi/extension/ru/libmanga/LibManga.kt @@ -5,18 +5,6 @@ import android.content.SharedPreferences import android.widget.Toast import androidx.preference.ListPreference import androidx.preference.PreferenceScreen -import com.github.salomonbrys.kotson.array -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.int -import com.github.salomonbrys.kotson.nullArray -import com.github.salomonbrys.kotson.nullInt -import com.github.salomonbrys.kotson.nullString -import com.github.salomonbrys.kotson.obj -import com.github.salomonbrys.kotson.string -import com.github.salomonbrys.kotson.toMap -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonParser import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST @@ -30,6 +18,17 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.int +import kotlinx.serialization.json.intOrNull +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.OkHttpClient @@ -39,12 +38,15 @@ import org.jsoup.nodes.Element import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Locale import java.util.concurrent.TimeUnit class LibManga : ConfigurableSource, HttpSource() { + private val json: Json by injectLazy() + private val preferences: SharedPreferences by lazy { Injekt.get().getSharedPreferences("source_${id}_2", 0x0000) } @@ -72,8 +74,6 @@ class LibManga : ConfigurableSource, HttpSource() { add("Referer", baseUrl) } - private val jsonParser = JsonParser() - override fun latestUpdatesRequest(page: Int) = GET(baseUrl, headers) private val latestUpdatesSelector = "div.updates__item" @@ -135,21 +135,21 @@ class LibManga : ConfigurableSource, HttpSource() { override fun popularMangaParse(response: Response): MangasPage { val resBody = response.body!!.string() - val result = jsonParser.parse(resBody).obj - val items = result["items"] - val popularMangas = items["data"].nullArray?.map { popularMangaFromElement(it) } + val result = json.decodeFromString(resBody) + val items = result["items"]!!.jsonObject + val popularMangas = items["data"]?.jsonArray?.map { popularMangaFromElement(it) } if (popularMangas != null) { - val hasNextPage = items["next_page_url"].nullString != null + val hasNextPage = items["next_page_url"]?.jsonPrimitive?.contentOrNull != null return MangasPage(popularMangas, hasNextPage) } return MangasPage(emptyList(), false) } private fun popularMangaFromElement(el: JsonElement) = SManga.create().apply { - val slug = el["slug"].string - val cover = el["cover"].string - title = if (titleLanguage.equals("rus")) el["rus_name"].string else el["name"].string + val slug = el.jsonObject["slug"]!!.jsonPrimitive.content + val cover = el.jsonObject["cover"]!!.jsonPrimitive.content + title = if (titleLanguage.equals("rus")) el.jsonObject["rus_name"]!!.jsonPrimitive.content else el.jsonObject["name"]!!.jsonPrimitive.content thumbnail_url = "$COVER_URL/uploads/cover/$slug/cover/${cover}_250x350.jpg" url = "/$slug" } @@ -232,17 +232,17 @@ class LibManga : ConfigurableSource, HttpSource() { .substringBefore("window._SITE_COLOR_") .substringBeforeLast(";") - val data = jsonParser.parse(dataStr).obj - val chaptersList = data["chapters"]["list"].nullArray - val slug = data["manga"]["slug"].string - val branches = data["chapters"]["branches"].array.reversed() + val data = json.decodeFromString(dataStr) + val chaptersList = data["chapters"]!!.jsonObject["list"]?.jsonArray + val slug = data["manga"]!!.jsonObject["slug"]!!.jsonPrimitive.content + val branches = data["chapters"]!!.jsonObject["branches"]!!.jsonArray.reversed() val sortingList = preferences.getString(SORTING_PREF, "ms_mixing") val chapters: List? = if (branches.isNotEmpty() && !sortingList.equals("ms_mixing")) { sortChaptersByTranslator(sortingList, chaptersList, slug, branches) } else { chaptersList - ?.filter { it["status"].nullInt != 2 } + ?.filter { it.jsonObject["status"]?.jsonPrimitive?.intOrNull != 2 } ?.map { chapterFromElement(it, sortingList, slug) } } @@ -256,9 +256,9 @@ class LibManga : ConfigurableSource, HttpSource() { "ms_combining" -> { val tempChaptersList = mutableListOf() for (currentBranch in branches.withIndex()) { - val teamId = branches[currentBranch.index]["id"].int + val teamId = branches[currentBranch.index].jsonObject["id"]!!.jsonPrimitive.int chapters = chaptersList - ?.filter { it["branch_id"].nullInt == teamId && it["status"].nullInt != 2 } + ?.filter { it.jsonObject["branch_id"]?.jsonPrimitive?.intOrNull == teamId && it.jsonObject["status"]?.jsonPrimitive?.intOrNull != 2 } ?.map { chapterFromElement(it, sortingList, slug, teamId, branches) } chapters?.let { tempChaptersList.addAll(it) } } @@ -267,26 +267,26 @@ class LibManga : ConfigurableSource, HttpSource() { "ms_largest" -> { val sizesChaptersLists = mutableListOf() for (currentBranch in branches.withIndex()) { - val teamId = branches[currentBranch.index]["id"].int + val teamId = branches[currentBranch.index].jsonObject["id"]!!.jsonPrimitive.int val chapterSize = chaptersList - ?.filter { it["branch_id"].nullInt == teamId }!!.size + ?.filter { it.jsonObject["branch_id"]?.jsonPrimitive?.intOrNull == teamId }!!.size sizesChaptersLists.add(chapterSize) } val max = sizesChaptersLists.indexOfFirst { it == sizesChaptersLists.maxOrNull() ?: 0 } - val teamId = branches[max]["id"].int + val teamId = branches[max].jsonObject["id"]!!.jsonPrimitive.int chapters = chaptersList - ?.filter { it["branch_id"].nullInt == teamId && it["status"].nullInt != 2 } + ?.filter { it.jsonObject["branch_id"]?.jsonPrimitive?.intOrNull == teamId && it.jsonObject["status"]?.jsonPrimitive?.intOrNull != 2 } ?.map { chapterFromElement(it, sortingList, slug, teamId, branches) } } "ms_active" -> { for (currentBranch in branches.withIndex()) { - val teams = branches[currentBranch.index]["teams"].array + val teams = branches[currentBranch.index].jsonObject["teams"]!!.jsonArray for (currentTeam in teams.withIndex()) { - if (teams[currentTeam.index]["is_active"].int == 1) { - val teamId = branches[currentBranch.index]["id"].int + if (teams[currentTeam.index].jsonObject["is_active"]!!.jsonPrimitive.int == 1) { + val teamId = branches[currentBranch.index].jsonObject["id"]!!.jsonPrimitive.int chapters = chaptersList - ?.filter { it["branch_id"].nullInt == teamId && it["status"].nullInt != 2 } + ?.filter { it.jsonObject["branch_id"]?.jsonPrimitive?.intOrNull == teamId && it.jsonObject["status"]?.jsonPrimitive?.intOrNull != 2 } ?.map { chapterFromElement(it, sortingList, slug, teamId, branches) } break } @@ -303,23 +303,23 @@ class LibManga : ConfigurableSource, HttpSource() { (chapterItem: JsonElement, sortingList: String?, slug: String, teamIdParam: Int? = null, branches: List? = null): SChapter { val chapter = SChapter.create() - val volume = chapterItem["chapter_volume"].int - val number = chapterItem["chapter_number"].string + val volume = chapterItem.jsonObject["chapter_volume"]!!.jsonPrimitive.int + val number = chapterItem.jsonObject["chapter_number"]!!.jsonPrimitive.content val teamId = if (teamIdParam != null) "?bid=$teamIdParam" else "" val url = "$baseUrl/$slug/v$volume/c$number$teamId" chapter.setUrlWithoutDomain(url) - val nameChapter = chapterItem["chapter_name"].nullString + val nameChapter = chapterItem.jsonObject["chapter_name"]?.jsonPrimitive?.contentOrNull val fullNameChapter = "Том $volume. Глава $number" if (!sortingList.equals("ms_mixing")) { - chapter.scanlator = branches?.let { getScanlatorTeamName(it, chapterItem) } ?: chapterItem["username"].string + chapter.scanlator = branches?.let { getScanlatorTeamName(it, chapterItem) } ?: chapterItem.jsonObject["username"]!!.jsonPrimitive.content } chapter.name = if (nameChapter.isNullOrBlank()) fullNameChapter else "$fullNameChapter - $nameChapter" chapter.date_upload = SimpleDateFormat("yyyy-MM-dd", Locale.US) - .parse(chapterItem["chapter_created_at"].string.substringBefore(" "))?.time ?: 0L + .parse(chapterItem.jsonObject["chapter_created_at"]!!.jsonPrimitive.content.substringBefore(" "))?.time ?: 0L return chapter } @@ -327,15 +327,15 @@ class LibManga : ConfigurableSource, HttpSource() { private fun getScanlatorTeamName(branches: List, chapterItem: JsonElement): String? { var scanlatorData: String? = null for (currentBranch in branches.withIndex()) { - val branch = branches[currentBranch.index] - val teams = branch["teams"].array - if (chapterItem["branch_id"].int == branch["id"].int) { + val branch = branches[currentBranch.index].jsonObject + val teams = branch["teams"]!!.jsonArray + if (chapterItem.jsonObject["branch_id"]!!.jsonPrimitive.int == branch["id"]!!.jsonPrimitive.int) { for (currentTeam in teams.withIndex()) { - val team = teams[currentTeam.index] - val scanlatorId = chapterItem["chapter_scanlator_id"].int - scanlatorData = if ((scanlatorId == team["id"].int) || - (scanlatorId == 0 && team["is_active"].int == 1) - ) team["name"].string else branch["teams"][0]["name"].string + val team = teams[currentTeam.index].jsonObject + val scanlatorId = chapterItem.jsonObject["chapter_scanlator_id"]!!.jsonPrimitive.int + scanlatorData = if ((scanlatorId == team.jsonObject["id"]!!.jsonPrimitive.int) || + (scanlatorId == 0 && team["is_active"]!!.jsonPrimitive.int == 1) + ) team["name"]!!.jsonPrimitive.content else branch["teams"]!!.jsonArray[0].jsonObject["name"]!!.jsonPrimitive.content } } } @@ -371,11 +371,11 @@ class LibManga : ConfigurableSource, HttpSource() { .split(";") .first() - val chapInfoJson = jsonParser.parse(chapInfo).obj - val servers = chapInfoJson["servers"].asJsonObject.toMap() - val defaultServer: String = chapInfoJson["img"]["server"].string + val chapInfoJson = json.decodeFromString(chapInfo) + val servers = chapInfoJson["servers"]!!.jsonObject.toMap() + val defaultServer: String = chapInfoJson["img"]!!.jsonObject["server"]!!.jsonPrimitive.content val autoServer = setOf("secondary", "fourth", defaultServer, "compress") - val imgUrl: String = chapInfoJson["img"]["url"].string + val imgUrl: String = chapInfoJson["img"]!!.jsonObject["url"]!!.jsonPrimitive.content val serverToUse = when (this.server) { null -> autoServer @@ -392,15 +392,15 @@ class LibManga : ConfigurableSource, HttpSource() { .removePrefix("window.__pg = ") .removeSuffix(";") - val pagesJson = jsonParser.parse(pagesArr).array + val pagesJson = json.decodeFromString(pagesArr) val pages = mutableListOf() pagesJson.forEach { page -> val keys = servers.keys.filter { serverToUse.indexOf(it) >= 0 }.sortedBy { serverToUse.indexOf(it) } val serversUrls = keys.map { - servers[it]?.string + imgUrl + page["u"].string + servers[it]?.jsonPrimitive?.contentOrNull + imgUrl + page.jsonObject["u"]!!.jsonPrimitive.content }.joinToString(separator = ",,") { it } - pages.add(Page(page["p"].int, serversUrls)) + pages.add(Page(page.jsonObject["p"]!!.jsonPrimitive.int, serversUrls)) } return pages @@ -523,7 +523,7 @@ class LibManga : ConfigurableSource, HttpSource() { ) .execute().body!!.string() - val jsonList = jsonParser.parse(popup).array + val jsonList = json.decodeFromString(popup) jsonList.forEach { mangas.add(popularMangaFromElement(it)) } diff --git a/src/ru/mangaonlinebiz/build.gradle b/src/ru/mangaonlinebiz/build.gradle index 90419d33a..72407e832 100644 --- a/src/ru/mangaonlinebiz/build.gradle +++ b/src/ru/mangaonlinebiz/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'Mangaonlinebiz' diff --git a/src/ru/mangaonlinebiz/src/eu/kanade/tachiyomi/extension/ru/mangaonlinebiz/MangaOnlineBiz.kt b/src/ru/mangaonlinebiz/src/eu/kanade/tachiyomi/extension/ru/mangaonlinebiz/MangaOnlineBiz.kt index a78755e95..ad3983747 100644 --- a/src/ru/mangaonlinebiz/src/eu/kanade/tachiyomi/extension/ru/mangaonlinebiz/MangaOnlineBiz.kt +++ b/src/ru/mangaonlinebiz/src/eu/kanade/tachiyomi/extension/ru/mangaonlinebiz/MangaOnlineBiz.kt @@ -1,10 +1,5 @@ package eu.kanade.tachiyomi.extension.ru.mangaonlinebiz -import com.github.salomonbrys.kotson.float -import com.github.salomonbrys.kotson.forEach -import com.github.salomonbrys.kotson.string -import com.google.gson.JsonObject -import com.google.gson.JsonParser import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList @@ -13,15 +8,27 @@ 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.ParsedHttpSource +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.float +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.Headers import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Locale class MangaOnlineBiz : ParsedHttpSource() { + + private val json: Json by injectLazy() + override val name = "MangaOnlineBiz" override val baseUrl = "https://manga-online.biz" @@ -68,15 +75,14 @@ class MangaOnlineBiz : ParsedHttpSource() { return popularMangaParse(response) } val jsonData = response.body!!.string() - val json = JsonParser().parse(jsonData).asJsonObject - val results = json.getAsJsonArray("results") + val results = json.decodeFromString(jsonData)["results"]!!.jsonArray val mangas = mutableListOf() results.forEach { - val element = it.asJsonObject + val element = it.jsonObject val manga = SManga.create() - manga.setUrlWithoutDomain(element.get("url").string) - manga.title = element.get("title").string.split("/").first() - val image = element.get("image").string + manga.setUrlWithoutDomain(element["url"]!!.jsonPrimitive.content) + manga.title = element["title"]!!.jsonPrimitive.content.split("/").first() + val image = element["image"]!!.jsonPrimitive.content if (image.startsWith("http")) { manga.thumbnail_url = image } else { @@ -130,10 +136,9 @@ class MangaOnlineBiz : ParsedHttpSource() { val jsonData = html.split("App.Collection.MangaChapter(").last().split("]);").first() + "]" val mangaName = html.split("mangaName: '").last().split("' });").first() - val json = JsonParser().parse(jsonData).asJsonArray val chapterList = mutableListOf() - json.forEach { - chapterList.add(chapterFromElement(mangaName, it.asJsonObject)) + json.decodeFromString(jsonData).forEach { + chapterList.add(chapterFromElement(mangaName, it.jsonObject)) } return chapterList } @@ -142,22 +147,22 @@ class MangaOnlineBiz : ParsedHttpSource() { private fun chapterFromElement(mangaName: String, element: JsonObject): SChapter { val chapter = SChapter.create() - chapter.setUrlWithoutDomain("/$mangaName/${element.get("volume").string}/${element.get("number").string})/1") - chapter.name = "Том ${element.get("volume").string} - Глава ${element.get("number").string} ${element.get("title").string}" - chapter.chapter_number = element.get("number").float - chapter.date_upload = SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(element.get("date").string)?.time ?: 0L + chapter.setUrlWithoutDomain("/$mangaName/${element["volume"]!!.jsonPrimitive.content}/${element["number"]!!.jsonPrimitive.content})/1") + chapter.name = "Том ${element["volume"]!!.jsonPrimitive.content} - Глава ${element["number"]!!.jsonPrimitive.content} ${element["title"]!!.jsonPrimitive.content}" + chapter.chapter_number = element["number"]!!.jsonPrimitive.float + chapter.date_upload = SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(element["date"]!!.jsonPrimitive.content)?.time ?: 0L return chapter } override fun pageListParse(response: Response): List { val html = response.body!!.string() val jsonData = html.split("new App.Router.Chapter(").last().split("});").first() + "}" - val json = JsonParser().parse(jsonData).asJsonObject - val cdnUrl = json.get("srcBaseUrl").string - val pages = json.get("pages").asJsonObject + val jsonObj = json.decodeFromString(jsonData) + val cdnUrl = jsonObj["srcBaseUrl"]!!.jsonPrimitive.content + val pages = jsonObj["pages"]!!.jsonObject val resPages = mutableListOf() - pages.forEach { page, jsonElement -> - resPages.add(Page(page.toInt(), imageUrl = "$cdnUrl/${jsonElement.asJsonObject.get("src").string}")) + pages.entries.forEach { (page, jsonElement) -> + resPages.add(Page(page.toInt(), imageUrl = "$cdnUrl/${jsonElement.jsonObject["src"]!!.jsonPrimitive.content}")) } return resPages } diff --git a/src/ru/risensteam/build.gradle b/src/ru/risensteam/build.gradle index 0091a0d05..f96cf4b19 100644 --- a/src/ru/risensteam/build.gradle +++ b/src/ru/risensteam/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' ext { extName = 'Risens Team' diff --git a/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt b/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt index ee8ff6b84..cb2584d98 100644 --- a/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt +++ b/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt @@ -1,14 +1,5 @@ package eu.kanade.tachiyomi.extension.ru.risensteam -import com.github.salomonbrys.kotson.fromJson -import com.github.salomonbrys.kotson.get -import com.github.salomonbrys.kotson.int -import com.github.salomonbrys.kotson.nullString -import com.github.salomonbrys.kotson.string -import com.google.gson.Gson -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.asObservableSuccess @@ -18,11 +9,22 @@ 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.decodeFromString +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.int +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import rx.Observable +import uy.kohesive.injekt.injectLazy import java.text.ParseException import java.text.SimpleDateFormat import java.util.Locale @@ -39,7 +41,7 @@ class RisensTeam : HttpSource() { override val versionId: Int = 2 - private val gson by lazy { Gson() } + private val json: Json by injectLazy() // Popular (source only returns manga sorted by latest) @@ -49,16 +51,16 @@ class RisensTeam : HttpSource() { private fun mangaFromJson(json: JsonElement): SManga { return SManga.create().apply { - url = "${json["id"].int}/${json["furl"].string}" - title = json["title"].string - thumbnail_url = baseUrl + json["poster"].string - description = json["description"].nullString - status = try { if (json["active"].int == 1) SManga.ONGOING else SManga.UNKNOWN } catch (_: Exception) { SManga.UNKNOWN } + url = "${json.jsonObject["id"]!!.jsonPrimitive.int}/${json.jsonObject["furl"]!!.jsonPrimitive.content}" + title = json.jsonObject["title"]!!.jsonPrimitive.content + thumbnail_url = baseUrl + json.jsonObject["poster"]!!.jsonPrimitive.content + description = json.jsonObject["description"]!!.jsonPrimitive.contentOrNull + status = try { if (json.jsonObject["active"]!!.jsonPrimitive.int == 1) SManga.ONGOING else SManga.UNKNOWN } catch (_: Exception) { SManga.UNKNOWN } } } override fun popularMangaParse(response: Response): MangasPage { - val mangas = gson.fromJson(response.body!!.string()) + val mangas = json.decodeFromString(response.body!!.string()) .map { json -> mangaFromJson(json) } return MangasPage(mangas, false) @@ -98,7 +100,7 @@ class RisensTeam : HttpSource() { } override fun mangaDetailsParse(response: Response): SManga { - return mangaFromJson(gson.fromJson(response.body!!.string())) + return mangaFromJson(json.decodeFromString(response.body!!.string())) } // Chapters @@ -106,11 +108,11 @@ class RisensTeam : HttpSource() { override fun chapterListRequest(manga: SManga): Request = apiMangaDetailsRequest(manga) override fun chapterListParse(response: Response): List { - return gson.fromJson(response.body!!.string())["entities"].asJsonArray.map { json -> + return json.decodeFromString(response.body!!.string())["entities"]!!.jsonArray.map { json -> SChapter.create().apply { - url = json["id"].int.toString() - name = listOfNotNull(json["label"].nullString, json["name"].nullString).joinToString(" - ") - date_upload = json["updated_at"].toDate() + url = json.jsonObject["id"]!!.jsonPrimitive.int.toString() + name = listOfNotNull(json.jsonObject["label"]!!.jsonPrimitive.contentOrNull, json.jsonObject["name"]!!.jsonPrimitive.contentOrNull).joinToString(" - ") + date_upload = json.jsonObject["updated_at"]!!.toDate() } } } @@ -120,7 +122,7 @@ class RisensTeam : HttpSource() { } private fun JsonElement.toDate(): Long { - val date = this.nullString ?: return 0 + val date = this.jsonPrimitive.contentOrNull ?: return 0 return try { simpleDateFormat.parse(date)?.time ?: 0 } catch (e: ParseException) { @@ -135,8 +137,8 @@ class RisensTeam : HttpSource() { } override fun pageListParse(response: Response): List { - return gson.fromJson(response.body!!.string()) - .mapIndexed { i, json -> Page(i, "", json.string) } + return json.decodeFromString(response.body!!.string()) + .mapIndexed { i, json -> Page(i, "", json.jsonPrimitive.content) } } override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used") diff --git a/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectChapter.kt b/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectChapter.kt index 0f9825608..fcaeb1823 100644 --- a/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectChapter.kt +++ b/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectChapter.kt @@ -1,24 +1,24 @@ package eu.kanade.tachiyomi.extension.th.nekopost.model -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable data class RawProjectChapter( - @SerializedName("cu_displayname") + @SerialName("cu_displayname") val cuDisplayname: String, - @SerializedName("nc_chapter_id") + @SerialName("nc_chapter_id") val ncChapterId: String, - @SerializedName("nc_chapter_name") + @SerialName("nc_chapter_name") val ncChapterName: String, - @SerializedName("nc_chapter_no") + @SerialName("nc_chapter_no") val ncChapterNo: String, - @SerializedName("nc_created_date") + @SerialName("nc_created_date") val ncCreatedDate: String, - @SerializedName("nc_data_file") + @SerialName("nc_data_file") val ncDataFile: String, - @SerializedName("nc_owner_id") + @SerialName("nc_owner_id") val ncOwnerId: String, - @SerializedName("nc_provider") + @SerialName("nc_provider") val ncProvider: String ) diff --git a/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectInfoData.kt b/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectInfoData.kt index 55f19a8cf..e83720ac4 100644 --- a/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectInfoData.kt +++ b/src/th/nekopost/src/eu/kanade/tachiyomi/extension/th/nekopost/model/RawProjectInfoData.kt @@ -1,38 +1,38 @@ package eu.kanade.tachiyomi.extension.th.nekopost.model -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable data class RawProjectInfoData( - @SerializedName("artist_name") + @SerialName("artist_name") val artistName: String, - @SerializedName("author_name") + @SerialName("author_name") val authorName: String, - @SerializedName("np_comment") + @SerialName("np_comment") val npComment: String, - @SerializedName("np_created_date") + @SerialName("np_created_date") val npCreatedDate: String, - @SerializedName("np_flag_mature") + @SerialName("np_flag_mature") val npFlagMature: String, - @SerializedName("np_info") + @SerialName("np_info") val npInfo: String, - @SerializedName("np_licenced_by") + @SerialName("np_licenced_by") val npLicencedBy: String, - @SerializedName("np_name") + @SerialName("np_name") val npName: String, - @SerializedName("np_name_link") + @SerialName("np_name_link") val npNameLink: String, - @SerializedName("np_project_id") + @SerialName("np_project_id") val npProjectId: String, - @SerializedName("np_status") + @SerialName("np_status") val npStatus: String, - @SerializedName("np_type") + @SerialName("np_type") val npType: String, - @SerializedName("np_updated_date") + @SerialName("np_updated_date") val npUpdatedDate: String, - @SerializedName("np_view") + @SerialName("np_view") val npView: String, - @SerializedName("np_web") + @SerialName("np_web") val npWeb: String )