Replace usages of Gson (#10080)

This commit is contained in:
arkon 2021-12-12 16:33:20 -05:00 committed by GitHub
parent 1f6027dd67
commit fa6be0f1c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 572 additions and 575 deletions

View File

@ -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 |
| ----- | ----------- |

View File

@ -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<ContentTypeSelectFilter>()!!
val albumSizeFilter = filters.findInstance<AlbumSizeSelectFilter>()!!
val restrictGenresFilter = filters.findInstance<RestrictGenresSelectFilter>()!!
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<JsonObject>(response.body!!.string())
with(data["data"]["album"]["list"]) {
val data = json.decodeFromString<JsonObject>(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<JsonObject>(it)["input"]["filters"].asJsonArray }
.let { it.first { f -> f["name"].asString == "album_id" } }
.let { it["value"].asString }
.let { json.decodeFromString<JsonObject>(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<JsonObject>(response.body!!.string())
.let { it["data"]["picture"]["list"].asJsonObject }
var data = json.decodeFromString<JsonObject>(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<JsonObject>(newPage.body!!.string())
.let { it["data"]["picture"]["list"].asJsonObject }
data = json.decodeFromString<JsonObject>(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<JsonObject>(it)["input"]["filters"].asJsonArray }
.let { it.first { f -> f["name"].asString == "album_id" } }
.let { it["value"].asString }
.let { json.decodeFromString<JsonObject>(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<JsonObject>(response.body!!.string())
.let { it["data"]["picture"]["list"].asJsonObject }
var data = json.decodeFromString<JsonObject>(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<JsonObject>(newPage.body!!.string())
.let { it["data"]["picture"]["list"].asJsonObject }
data = json.decodeFromString<JsonObject>(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<JsonObject>(it.body!!.string()).let { data ->
data["data"]["picture"]["list"].asJsonObject
val data = json.decodeFromString<JsonObject>(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<JsonObject>(response.body!!.string())
with(data["data"]["album"]["get"]) {
val data = json.decodeFromString<JsonObject>(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)
}
}

View File

@ -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<JsonObject>(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<Pair<String, String>>()
emptyList()
}
/**
@ -95,7 +98,7 @@ abstract class MMRCMS(
open fun mapToPairs(array: JsonArray): List<Pair<String, String>> = 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<JsonObject>(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"

View File

@ -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)
}

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'GMANGA'

View File

@ -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<JsonArray> = buildList {
val allChapters: ArrayList<JsonArray> = 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<JsonArray>) -> versions.maxByOrNull { it[5].asLong }!! }
allChapters.groupBy { it.jsonArray[4].jsonPrimitive.float }
.map { (_: Float, versions: List<JsonArray>) -> 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<JsonObject>(response.asJsoup().select(".js-react-on-rails-component").html())
val data = json.decodeFromString<JsonObject>(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<JsonObject>(response.asJsoup().select(".js-react-on-rails-component").html())
val mangaData = data["mangaDataAction"]["mangaData"].asJsonObject
val data = json.decodeFromString<JsonObject>(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<Page> {
val url = response.request.url.toString()
val data = gson.fromJson<JsonObject>(response.asJsoup().select(".js-react-on-rails-component").html())
val releaseData = data["readerDataAction"]["readerData"]["release"].asJsonObject
val data = json.decodeFromString<JsonObject>(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<JsonObject>(response.body!!.string())["data"].asString
val encryptedData = json.decodeFromString<JsonObject>(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)
}
}

View File

@ -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<DateRangeFilter>()!!
val categoryFilter = filters.findInstance<CategoryFilter>()!!
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)
}
}

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Manga Tube'

View File

@ -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&parameter%5Bpage%5D=$page&parameter%5Bletter%5D=&parameter%5Bsortby%5D=popularity&parameter%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<JsonObject>(response.body!!.string())
.let { it["success"] ?: it["suggestions"].also { titleKey = "value" } }
.asJsonArray
val mangas = json.decodeFromString<JsonObject>(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&parameter%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>(jsonArray).mapIndexed { i, json ->
Page(i, "", imagePath + json.asJsonObject["file_name"].asString)
return json.decodeFromString<JsonArray>(jsonArray).mapIndexed { i, json ->
Page(i, "", imagePath + json.jsonObject["file_name"]!!.jsonPrimitive.content)
}
}

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Mangahub'

View File

@ -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<Page> {
val cdn = "https://img.mghubcdn.com/file/imghub"
return gson.fromJson<JsonObject>(response.body!!.string())["data"]["chapter"]["pages"].string
return json.decodeFromString<JsonObject>(response.body!!.string())["data"]!!
.jsonObject["chapter"]!!
.jsonObject["pages"]!!.jsonPrimitive.content
.removeSurrounding("\"").replace("\\", "")
.let { cleaned ->
val jsonObject = gson.fromJson<JsonObject>(cleaned)
jsonObject.keys().map { key -> jsonObject[key].string }
val jsonObject = json.decodeFromString<JsonObject>(cleaned)
jsonObject.keys.map { key -> jsonObject[key]!!.jsonPrimitive.content }
}
.mapIndexed { i, tail -> Page(i, "", "$cdn/$tail") }
}

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'MangaRock.es'

View File

@ -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<Page> {
val responseString = response.body!!.string()
return Regex("""mangaData = (\[.*]);""", RegexOption.IGNORE_CASE).find(responseString)?.groupValues?.get(1)?.let { array ->
gson.fromJson<JsonArray>(array)
.mapIndexed { i, jsonElement -> Page(i, "", jsonElement.asJsonObject["url"].asString) }
json.decodeFromString<JsonArray>(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]) }

View File

@ -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()
}

View File

@ -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()
}

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'ReadManhwa'

View File

@ -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<JsonObject>(response.body!!.string())
val jsonObject = json.decodeFromString<JsonObject>(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<JsonObject>(response.body!!.string())
val jsonObject = json.decodeFromString<JsonObject>(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<SChapter> {
return gson.fromJson<JsonArray>(response.body!!.string()).map { json ->
return json.decodeFromString<JsonArray>(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<Page> {
return gson.fromJson<JsonObject>(response.body!!.string())["images"].asJsonArray.mapIndexed { i, json ->
Page(i, "", json["source_url"].string)
return json.decodeFromString<JsonObject>(response.body!!.string())["images"]!!.jsonArray.mapIndexed { i, json ->
Page(i, "", json.jsonObject["source_url"]!!.jsonPrimitive.content)
}
}

View File

@ -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)
)
}

View File

@ -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

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'ComX'

View File

@ -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("</script>")
.substringBeforeLast(";")
val data = JsonParser.parseString(dataStr).obj
val chaptersList = data["chapters"].nullArray
val data = json.decodeFromString<JsonObject>(dataStr)
val chaptersList = data["chapters"]?.jsonArray
val chapters: List<SChapter>? = 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()

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'MangaLib'

View File

@ -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<Application>().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<JsonObject>(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<JsonObject>(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<SChapter>? = 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<SChapter>()
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<Int>()
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<JsonElement>? = 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<JsonElement>, 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<JsonObject>(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<JsonArray>(pagesArr)
val pages = mutableListOf<Page>()
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<JsonArray>(popup)
jsonList.forEach {
mangas.add(popularMangaFromElement(it))
}

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Mangaonlinebiz'

View File

@ -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<JsonObject>(jsonData)["results"]!!.jsonArray
val mangas = mutableListOf<SManga>()
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<SChapter>()
json.forEach {
chapterList.add(chapterFromElement(mangaName, it.asJsonObject))
json.decodeFromString<JsonArray>(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<Page> {
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<JsonObject>(jsonData)
val cdnUrl = jsonObj["srcBaseUrl"]!!.jsonPrimitive.content
val pages = jsonObj["pages"]!!.jsonObject
val resPages = mutableListOf<Page>()
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
}

View File

@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Risens Team'

View File

@ -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<JsonArray>(response.body!!.string())
val mangas = json.decodeFromString<JsonArray>(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<JsonObject>(response.body!!.string()))
return mangaFromJson(json.decodeFromString<JsonObject>(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<SChapter> {
return gson.fromJson<JsonObject>(response.body!!.string())["entities"].asJsonArray.map { json ->
return json.decodeFromString<JsonObject>(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<Page> {
return gson.fromJson<JsonArray>(response.body!!.string())
.mapIndexed { i, json -> Page(i, "", json.string) }
return json.decodeFromString<JsonArray>(response.body!!.string())
.mapIndexed { i, json -> Page(i, "", json.jsonPrimitive.content) }
}
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used")

View File

@ -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
)

View File

@ -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
)