Migrating 3 sources to kotlinx.serialization (#8463)
* HentaiHand: Migration to kotlinx.serialization * SimplyHentai: Migration to kotlinx.serialization * Kangaryu: Migration to kotlinx.serialization
This commit is contained in:
		
							parent
							
								
									5a0d513b94
								
							
						
					
					
						commit
						6470dd5245
					
				@ -1,11 +1,12 @@
 | 
				
			|||||||
apply plugin: 'com.android.application'
 | 
					apply plugin: 'com.android.application'
 | 
				
			||||||
apply plugin: 'kotlin-android'
 | 
					apply plugin: 'kotlin-android'
 | 
				
			||||||
 | 
					apply plugin: 'kotlinx-serialization'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ext {
 | 
					ext {
 | 
				
			||||||
    extName = 'HentaiHand'
 | 
					    extName = 'HentaiHand'
 | 
				
			||||||
    pkgNameSuffix = 'all.hentaihand'
 | 
					    pkgNameSuffix = 'all.hentaihand'
 | 
				
			||||||
    extClass = '.HentaiHandFactory'
 | 
					    extClass = '.HentaiHandFactory'
 | 
				
			||||||
    extVersionCode = 3
 | 
					    extVersionCode = 4
 | 
				
			||||||
    libVersion = '1.2'
 | 
					    libVersion = '1.2'
 | 
				
			||||||
    containsNsfw = true
 | 
					    containsNsfw = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,17 +1,9 @@
 | 
				
			|||||||
package eu.kanade.tachiyomi.extension.all.hentaihand
 | 
					package eu.kanade.tachiyomi.extension.all.hentaihand
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.annotation.SuppressLint
 | 
					 | 
				
			||||||
import android.app.Application
 | 
					import android.app.Application
 | 
				
			||||||
import android.content.SharedPreferences
 | 
					import android.content.SharedPreferences
 | 
				
			||||||
import android.text.InputType
 | 
					import android.text.InputType
 | 
				
			||||||
import android.widget.Toast
 | 
					import android.widget.Toast
 | 
				
			||||||
import com.github.salomonbrys.kotson.fromJson
 | 
					 | 
				
			||||||
import com.github.salomonbrys.kotson.get
 | 
					 | 
				
			||||||
import com.github.salomonbrys.kotson.nullObj
 | 
					 | 
				
			||||||
import com.github.salomonbrys.kotson.nullString
 | 
					 | 
				
			||||||
import com.google.gson.Gson
 | 
					 | 
				
			||||||
import com.google.gson.JsonArray
 | 
					 | 
				
			||||||
import com.google.gson.JsonObject
 | 
					 | 
				
			||||||
import eu.kanade.tachiyomi.annotations.Nsfw
 | 
					import eu.kanade.tachiyomi.annotations.Nsfw
 | 
				
			||||||
import eu.kanade.tachiyomi.network.GET
 | 
					import eu.kanade.tachiyomi.network.GET
 | 
				
			||||||
import eu.kanade.tachiyomi.network.POST
 | 
					import eu.kanade.tachiyomi.network.POST
 | 
				
			||||||
@ -24,20 +16,28 @@ import eu.kanade.tachiyomi.source.model.Page
 | 
				
			|||||||
import eu.kanade.tachiyomi.source.model.SChapter
 | 
					import eu.kanade.tachiyomi.source.model.SChapter
 | 
				
			||||||
import eu.kanade.tachiyomi.source.model.SManga
 | 
					import eu.kanade.tachiyomi.source.model.SManga
 | 
				
			||||||
import eu.kanade.tachiyomi.source.online.HttpSource
 | 
					import eu.kanade.tachiyomi.source.online.HttpSource
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.JsonObject
 | 
				
			||||||
 | 
					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.put
 | 
				
			||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 | 
					import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 | 
				
			||||||
import okhttp3.Interceptor
 | 
					import okhttp3.Interceptor
 | 
				
			||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
 | 
					import okhttp3.MediaType.Companion.toMediaTypeOrNull
 | 
				
			||||||
import okhttp3.OkHttpClient
 | 
					import okhttp3.OkHttpClient
 | 
				
			||||||
import okhttp3.Request
 | 
					import okhttp3.Request
 | 
				
			||||||
import okhttp3.RequestBody
 | 
					import okhttp3.RequestBody.Companion.toRequestBody
 | 
				
			||||||
import okhttp3.Response
 | 
					import okhttp3.Response
 | 
				
			||||||
import org.json.JSONException
 | 
					 | 
				
			||||||
import org.json.JSONObject
 | 
					 | 
				
			||||||
import rx.Observable
 | 
					import rx.Observable
 | 
				
			||||||
import rx.schedulers.Schedulers
 | 
					import rx.schedulers.Schedulers
 | 
				
			||||||
import uy.kohesive.injekt.Injekt
 | 
					import uy.kohesive.injekt.Injekt
 | 
				
			||||||
import uy.kohesive.injekt.api.get
 | 
					import uy.kohesive.injekt.api.get
 | 
				
			||||||
 | 
					import uy.kohesive.injekt.injectLazy
 | 
				
			||||||
import java.text.SimpleDateFormat
 | 
					import java.text.SimpleDateFormat
 | 
				
			||||||
 | 
					import java.util.Locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Nsfw
 | 
					@Nsfw
 | 
				
			||||||
abstract class HentaiHand(
 | 
					abstract class HentaiHand(
 | 
				
			||||||
@ -50,29 +50,37 @@ abstract class HentaiHand(
 | 
				
			|||||||
    override val name: String = "HentaiHand$extraName"
 | 
					    override val name: String = "HentaiHand$extraName"
 | 
				
			||||||
    override val supportsLatest = true
 | 
					    override val supportsLatest = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val gson = Gson()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val client: OkHttpClient = network.cloudflareClient.newBuilder()
 | 
					    override val client: OkHttpClient = network.cloudflareClient.newBuilder()
 | 
				
			||||||
        .addInterceptor { authIntercept(it) }
 | 
					        .addInterceptor { authIntercept(it) }
 | 
				
			||||||
        .build()
 | 
					        .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun parseGenericResponse(response: Response): MangasPage {
 | 
					    private val json: Json by injectLazy()
 | 
				
			||||||
        val data = gson.fromJson<JsonObject>(response.body!!.string())
 | 
					
 | 
				
			||||||
        return MangasPage(
 | 
					    private fun slugToUrl(json: JsonObject) = json["slug"]!!.jsonPrimitive.content.prependIndent("/en/comic/")
 | 
				
			||||||
            data.getAsJsonArray("data").map {
 | 
					
 | 
				
			||||||
                SManga.create().apply {
 | 
					    private fun jsonArrayToString(arrayKey: String, obj: JsonObject): String? {
 | 
				
			||||||
                    url = "/en/comic/${it["slug"].asString}"
 | 
					        val array = obj[arrayKey]!!.jsonArray
 | 
				
			||||||
                    title = it["title"].asString
 | 
					        if (array.isEmpty()) return null
 | 
				
			||||||
                    thumbnail_url = it["thumb_url"].asString
 | 
					        return array.joinToString(", ") {
 | 
				
			||||||
                }
 | 
					            it.jsonObject["name"]!!.jsonPrimitive.content
 | 
				
			||||||
            },
 | 
					        }
 | 
				
			||||||
            !data["next_page_url"].isJsonNull
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Popular
 | 
					    // Popular
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun popularMangaParse(response: Response): MangasPage = parseGenericResponse(response)
 | 
					    override fun popularMangaParse(response: Response): MangasPage {
 | 
				
			||||||
 | 
					        val jsonResponse = json.parseToJsonElement(response.body!!.string())
 | 
				
			||||||
 | 
					        val mangaList = jsonResponse.jsonObject["data"]!!.jsonArray.map {
 | 
				
			||||||
 | 
					            val obj = it.jsonObject
 | 
				
			||||||
 | 
					            SManga.create().apply {
 | 
				
			||||||
 | 
					                url = slugToUrl(obj)
 | 
				
			||||||
 | 
					                title = obj["title"]!!.jsonPrimitive.content
 | 
				
			||||||
 | 
					                thumbnail_url = obj["thumb_url"]!!.jsonPrimitive.content
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        val hasNextPage = jsonResponse.jsonObject["next_page_url"]!!.jsonPrimitive.content.isNotEmpty()
 | 
				
			||||||
 | 
					        return MangasPage(mangaList, hasNextPage)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun popularMangaRequest(page: Int): Request {
 | 
					    override fun popularMangaRequest(page: Int): Request {
 | 
				
			||||||
        val url = "$baseUrl/api/comics?page=$page&sort=popularity&order=desc&duration=all"
 | 
					        val url = "$baseUrl/api/comics?page=$page&sort=popularity&order=desc&duration=all"
 | 
				
			||||||
@ -81,7 +89,7 @@ abstract class HentaiHand(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Latest
 | 
					    // Latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun latestUpdatesParse(response: Response): MangasPage = parseGenericResponse(response)
 | 
					    override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun latestUpdatesRequest(page: Int): Request {
 | 
					    override fun latestUpdatesRequest(page: Int): Request {
 | 
				
			||||||
        val url = "$baseUrl/api/comics?page=$page&sort=uploaded_at&order=desc&duration=week"
 | 
					        val url = "$baseUrl/api/comics?page=$page&sort=uploaded_at&order=desc&duration=week"
 | 
				
			||||||
@ -90,17 +98,20 @@ abstract class HentaiHand(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Search
 | 
					    // Search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun searchMangaParse(response: Response): MangasPage = parseGenericResponse(response)
 | 
					    override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun lookupFilterId(query: String, uri: String): Int? {
 | 
					    private fun lookupFilterId(query: String, uri: String): Int? {
 | 
				
			||||||
        // filter query needs to be resolved to an ID
 | 
					        // filter query needs to be resolved to an ID
 | 
				
			||||||
        return client.newCall(GET("$baseUrl/api/$uri?q=$query"))
 | 
					        return client.newCall(GET("$baseUrl/api/$uri?q=$query"))
 | 
				
			||||||
            .asObservableSuccess()
 | 
					            .asObservableSuccess()
 | 
				
			||||||
            .subscribeOn(Schedulers.io())
 | 
					            .subscribeOn(Schedulers.io())
 | 
				
			||||||
            .map {
 | 
					            .map { response ->
 | 
				
			||||||
                val data = gson.fromJson<JsonObject>(it.body!!.string())
 | 
					                // Returns the first matched id, or null if there are no results
 | 
				
			||||||
                // only the first tag will be used
 | 
					                val idList = json.parseToJsonElement(response.body!!.string()).jsonObject["data"]!!.jsonArray.map {
 | 
				
			||||||
                data.getAsJsonArray("data").firstOrNull()?.let { t -> t["id"].asInt }
 | 
					                    it.jsonObject["id"]!!.jsonPrimitive.content
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (idList.isEmpty()) return@map null
 | 
				
			||||||
 | 
					                else idList.first().toInt()
 | 
				
			||||||
            }.toBlocking().first()
 | 
					            }.toBlocking().first()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -138,12 +149,6 @@ abstract class HentaiHand(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Details
 | 
					    // Details
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun tagArrayToString(array: JsonArray, key: String = "name"): String? {
 | 
					 | 
				
			||||||
        if (array.size() == 0)
 | 
					 | 
				
			||||||
            return null
 | 
					 | 
				
			||||||
        return array.joinToString { it[key].asString }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun mangaDetailsApiRequest(manga: SManga): Request {
 | 
					    private fun mangaDetailsApiRequest(manga: SManga): Request {
 | 
				
			||||||
        val slug = manga.url.removePrefix("/en/comic/")
 | 
					        val slug = manga.url.removePrefix("/en/comic/")
 | 
				
			||||||
        return GET("$baseUrl/api/comics/$slug")
 | 
					        return GET("$baseUrl/api/comics/$slug")
 | 
				
			||||||
@ -156,28 +161,26 @@ abstract class HentaiHand(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun mangaDetailsParse(response: Response): SManga {
 | 
					    override fun mangaDetailsParse(response: Response): SManga {
 | 
				
			||||||
        val data = gson.fromJson<JsonObject>(response.body!!.string())
 | 
					        val obj = json.parseToJsonElement(response.body!!.string()).jsonObject
 | 
				
			||||||
        return SManga.create().apply {
 | 
					        return SManga.create().apply {
 | 
				
			||||||
 | 
					            url = slugToUrl(obj)
 | 
				
			||||||
            artist = tagArrayToString(data.getAsJsonArray("artists"))
 | 
					            title = obj["title"]!!.jsonPrimitive.content
 | 
				
			||||||
            author = tagArrayToString(data.getAsJsonArray("authors")) ?: artist
 | 
					            thumbnail_url = obj["thumb_url"]!!.jsonPrimitive.content
 | 
				
			||||||
 | 
					            artist = jsonArrayToString("artists", obj)
 | 
				
			||||||
            genre = listOf("tags", "relationships").map {
 | 
					            author = jsonArrayToString("authors", obj) ?: artist
 | 
				
			||||||
                data.getAsJsonArray(it).map { t -> t["name"].asString }
 | 
					            genre = listOfNotNull(jsonArrayToString("tags", obj), jsonArrayToString("relationships", obj)).joinToString(", ")
 | 
				
			||||||
            }.flatten().distinct().joinToString()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            status = SManga.COMPLETED
 | 
					            status = SManga.COMPLETED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            description = listOf(
 | 
					            description = listOf(
 | 
				
			||||||
                Pair("Alternative Title", data["alternative_title"].nullString),
 | 
					                Pair("Alternative Title", obj["alternative_title"]!!.jsonPrimitive.content),
 | 
				
			||||||
                Pair("Groups", tagArrayToString(data.getAsJsonArray("groups"))),
 | 
					                Pair("Groups", jsonArrayToString("groups", obj)),
 | 
				
			||||||
                Pair("Description", data["description"].nullString),
 | 
					                Pair("Description", obj["description"]!!.jsonPrimitive.content),
 | 
				
			||||||
                Pair("Pages", data["pages"].asInt.toString()),
 | 
					                Pair("Pages", obj["pages"]!!.jsonPrimitive.content),
 | 
				
			||||||
                Pair("Category", data["category"].nullObj?.get("name")?.asString),
 | 
					                Pair("Category", obj["category"]!!.jsonObject["name"]!!.jsonPrimitive.content),
 | 
				
			||||||
                Pair("Language", data["language"].nullObj?.get("name")?.asString),
 | 
					                Pair("Language", obj["language"]!!.jsonObject["name"]!!.jsonPrimitive.content),
 | 
				
			||||||
                Pair("Parodies", tagArrayToString(data.getAsJsonArray("parodies"))),
 | 
					                Pair("Parodies", jsonArrayToString("parodies", obj)),
 | 
				
			||||||
                Pair("Characters", tagArrayToString(data.getAsJsonArray("characters")))
 | 
					                Pair("Characters", jsonArrayToString("characters", obj))
 | 
				
			||||||
            ).filter { !it.second.isNullOrEmpty() }.joinToString("\n\n") { "${it.first}:\n${it.second}" }
 | 
					            ).filter { !it.second.isNullOrEmpty() }.joinToString("\n\n") { "${it.first}: ${it.second}" }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -186,12 +189,12 @@ abstract class HentaiHand(
 | 
				
			|||||||
    override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga)
 | 
					    override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun chapterListParse(response: Response): List<SChapter> {
 | 
					    override fun chapterListParse(response: Response): List<SChapter> {
 | 
				
			||||||
        val data = gson.fromJson<JsonObject>(response.body!!.string())
 | 
					        val obj = json.parseToJsonElement(response.body!!.string()).jsonObject
 | 
				
			||||||
        return listOf(
 | 
					        return listOf(
 | 
				
			||||||
            SChapter.create().apply {
 | 
					            SChapter.create().apply {
 | 
				
			||||||
                url = "/en/comic/${data["slug"].asString}/reader/1"
 | 
					                url = "/en/comic/${obj["slug"]!!.jsonPrimitive.content}/reader/1"
 | 
				
			||||||
                name = "Chapter"
 | 
					                name = "Chapter"
 | 
				
			||||||
                date_upload = DATE_FORMAT.parse(data["uploaded_at"].asString)?.time ?: 0
 | 
					                date_upload = DATE_FORMAT.parse(obj["uploaded_at"]!!.jsonPrimitive.content)?.time ?: 0
 | 
				
			||||||
                chapter_number = 1f
 | 
					                chapter_number = 1f
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@ -204,12 +207,13 @@ abstract class HentaiHand(
 | 
				
			|||||||
        return GET("$baseUrl/api/comics/$slug/images")
 | 
					        return GET("$baseUrl/api/comics/$slug/images")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun pageListParse(response: Response): List<Page> {
 | 
					    override fun pageListParse(response: Response): List<Page> =
 | 
				
			||||||
        val data = gson.fromJson<JsonObject>(response.body!!.string())
 | 
					        json.parseToJsonElement(response.body!!.string()).jsonObject["images"]!!.jsonArray.map {
 | 
				
			||||||
        return data.getAsJsonArray("images").mapIndexed { i, it ->
 | 
					            val imgObj = it.jsonObject
 | 
				
			||||||
            Page(i, "/en/comic/${data["comic"]["slug"].asString}/reader/${it["page"].asInt}", it["source_url"].asString)
 | 
					            val index = imgObj["page"]!!.jsonPrimitive.int
 | 
				
			||||||
 | 
					            val imgUrl = imgObj["source_url"]!!.jsonPrimitive.content
 | 
				
			||||||
 | 
					            Page(index, "", imgUrl)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used")
 | 
					    override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -231,12 +235,12 @@ abstract class HentaiHand(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun login(chain: Interceptor.Chain, username: String, password: String): String {
 | 
					    private fun login(chain: Interceptor.Chain, username: String, password: String): String {
 | 
				
			||||||
        val jsonObject = JSONObject().apply {
 | 
					        val jsonObject = buildJsonObject {
 | 
				
			||||||
            this.put("username", username)
 | 
					            put("username", username)
 | 
				
			||||||
            this.put("password", password)
 | 
					            put("password", password)
 | 
				
			||||||
            this.put("remember_me", true)
 | 
					            put("remember_me", true)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        val body = RequestBody.create(MEDIA_TYPE, jsonObject.toString())
 | 
					        val body = jsonObject.toString().toRequestBody(MEDIA_TYPE)
 | 
				
			||||||
        val response = chain.proceed(POST("$baseUrl/api/login", headers, body))
 | 
					        val response = chain.proceed(POST("$baseUrl/api/login", headers, body))
 | 
				
			||||||
        if (response.code == 401) {
 | 
					        if (response.code == 401) {
 | 
				
			||||||
            throw Exception("Failed to login, check if username and password are correct")
 | 
					            throw Exception("Failed to login, check if username and password are correct")
 | 
				
			||||||
@ -245,10 +249,9 @@ abstract class HentaiHand(
 | 
				
			|||||||
        if (response.body == null)
 | 
					        if (response.body == null)
 | 
				
			||||||
            throw Exception("Login response body is empty")
 | 
					            throw Exception("Login response body is empty")
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            return JSONObject(response.body!!.string())
 | 
					            // Returns access token as a string, unless unparseable
 | 
				
			||||||
                .getJSONObject("auth")
 | 
					            return json.parseToJsonElement(response.body!!.string()).jsonObject["auth"]!!.jsonObject["access-token"]!!.jsonPrimitive.content
 | 
				
			||||||
                .getString("access_token")
 | 
					        } catch (e: IllegalArgumentException) {
 | 
				
			||||||
        } catch (e: JSONException) {
 | 
					 | 
				
			||||||
            throw Exception("Cannot parse login response body")
 | 
					            throw Exception("Cannot parse login response body")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -357,8 +360,7 @@ abstract class HentaiHand(
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        @SuppressLint("SimpleDateFormat")
 | 
					        private val DATE_FORMAT = SimpleDateFormat("yyyy-dd-MM", Locale.US)
 | 
				
			||||||
        private val DATE_FORMAT = SimpleDateFormat("yyyy-dd-MM")
 | 
					 | 
				
			||||||
        private val MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()
 | 
					        private val MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()
 | 
				
			||||||
        private const val USERNAME_TITLE = "Username"
 | 
					        private const val USERNAME_TITLE = "Username"
 | 
				
			||||||
        private const val USERNAME_DEFAULT = ""
 | 
					        private const val USERNAME_DEFAULT = ""
 | 
				
			||||||
 | 
				
			|||||||
@ -50,7 +50,7 @@ class HentaiHandFactory : SourceFactory {
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HentaiHandOther : HentaiHand("other", extraName = " (Unfiltered)")
 | 
					class HentaiHandOther : HentaiHand("all", extraName = " (Unfiltered)")
 | 
				
			||||||
class HentaiHandEn : HentaiHand("en", 1)
 | 
					class HentaiHandEn : HentaiHand("en", 1)
 | 
				
			||||||
class HentaiHandZh : HentaiHand("zh", 2)
 | 
					class HentaiHandZh : HentaiHand("zh", 2)
 | 
				
			||||||
class HentaiHandJa : HentaiHand("ja", 3)
 | 
					class HentaiHandJa : HentaiHand("ja", 3)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,12 @@
 | 
				
			|||||||
apply plugin: 'com.android.application'
 | 
					apply plugin: 'com.android.application'
 | 
				
			||||||
apply plugin: 'kotlin-android'
 | 
					apply plugin: 'kotlin-android'
 | 
				
			||||||
 | 
					apply plugin: 'kotlinx-serialization'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ext {
 | 
					ext {
 | 
				
			||||||
    extName = 'Simply Hentai'
 | 
					    extName = 'Simply Hentai'
 | 
				
			||||||
    pkgNameSuffix = 'all.simplyhentai'
 | 
					    pkgNameSuffix = 'all.simplyhentai'
 | 
				
			||||||
    extClass = '.SimplyHentaiFactory'
 | 
					    extClass = '.SimplyHentaiFactory'
 | 
				
			||||||
    extVersionCode = 3
 | 
					    extVersionCode = 4
 | 
				
			||||||
    libVersion = '1.2'
 | 
					    libVersion = '1.2'
 | 
				
			||||||
    containsNsfw = true
 | 
					    containsNsfw = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,6 @@
 | 
				
			|||||||
package eu.kanade.tachiyomi.extension.all.simplyhentai
 | 
					package eu.kanade.tachiyomi.extension.all.simplyhentai
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.annotation.SuppressLint
 | 
					import android.annotation.SuppressLint
 | 
				
			||||||
import com.github.salomonbrys.kotson.forEach
 | 
					 | 
				
			||||||
import com.github.salomonbrys.kotson.fromJson
 | 
					 | 
				
			||||||
import com.github.salomonbrys.kotson.get
 | 
					 | 
				
			||||||
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.GET
 | 
				
			||||||
import eu.kanade.tachiyomi.source.model.Filter
 | 
					import eu.kanade.tachiyomi.source.model.Filter
 | 
				
			||||||
import eu.kanade.tachiyomi.source.model.FilterList
 | 
					import eu.kanade.tachiyomi.source.model.FilterList
 | 
				
			||||||
@ -15,12 +9,16 @@ import eu.kanade.tachiyomi.source.model.SChapter
 | 
				
			|||||||
import eu.kanade.tachiyomi.source.model.SManga
 | 
					import eu.kanade.tachiyomi.source.model.SManga
 | 
				
			||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
 | 
					import eu.kanade.tachiyomi.source.online.ParsedHttpSource
 | 
				
			||||||
import eu.kanade.tachiyomi.util.asJsoup
 | 
					import eu.kanade.tachiyomi.util.asJsoup
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.jsonObject
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.jsonPrimitive
 | 
				
			||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 | 
					import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
 | 
				
			||||||
import okhttp3.OkHttpClient
 | 
					import okhttp3.OkHttpClient
 | 
				
			||||||
import okhttp3.Request
 | 
					import okhttp3.Request
 | 
				
			||||||
import okhttp3.Response
 | 
					import okhttp3.Response
 | 
				
			||||||
import org.jsoup.nodes.Document
 | 
					import org.jsoup.nodes.Document
 | 
				
			||||||
import org.jsoup.nodes.Element
 | 
					import org.jsoup.nodes.Element
 | 
				
			||||||
 | 
					import uy.kohesive.injekt.injectLazy
 | 
				
			||||||
import java.text.SimpleDateFormat
 | 
					import java.text.SimpleDateFormat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class SimplyHentai(
 | 
					abstract class SimplyHentai(
 | 
				
			||||||
@ -36,7 +34,7 @@ abstract class SimplyHentai(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    override val client: OkHttpClient = network.cloudflareClient
 | 
					    override val client: OkHttpClient = network.cloudflareClient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val gson = Gson()
 | 
					    private val json: Json by injectLazy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Popular
 | 
					    // Popular
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -158,8 +156,13 @@ abstract class SimplyHentai(
 | 
				
			|||||||
    override fun pageListParse(response: Response): List<Page> {
 | 
					    override fun pageListParse(response: Response): List<Page> {
 | 
				
			||||||
        val pages = mutableListOf<Page>()
 | 
					        val pages = mutableListOf<Page>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        gson.fromJson<JsonObject>(response.body!!.string()).forEach { _, jsonElement ->
 | 
					        json.parseToJsonElement(response.body!!.string()).jsonObject.forEach {
 | 
				
			||||||
            pages.add(Page(pages.size, "", jsonElement["sizes"]["full"].string))
 | 
					            pages.add(
 | 
				
			||||||
 | 
					                Page(
 | 
				
			||||||
 | 
					                    pages.size, "",
 | 
				
			||||||
 | 
					                    it.value.jsonObject["sizes"]!!.jsonObject["full"]!!.jsonPrimitive.content
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return pages
 | 
					        return pages
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,12 @@
 | 
				
			|||||||
apply plugin: 'com.android.application'
 | 
					apply plugin: 'com.android.application'
 | 
				
			||||||
apply plugin: 'kotlin-android'
 | 
					apply plugin: 'kotlin-android'
 | 
				
			||||||
 | 
					apply plugin: 'kotlinx-serialization'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ext {
 | 
					ext {
 | 
				
			||||||
    extName = 'Kangaryu'
 | 
					    extName = 'Kangaryu'
 | 
				
			||||||
    pkgNameSuffix = 'fr.kangaryu'
 | 
					    pkgNameSuffix = 'fr.kangaryu'
 | 
				
			||||||
    extClass = '.Kangaryu'
 | 
					    extClass = '.Kangaryu'
 | 
				
			||||||
    extVersionCode = 2
 | 
					    extVersionCode = 3
 | 
				
			||||||
    libVersion = '1.2'
 | 
					    libVersion = '1.2'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,5 @@
 | 
				
			|||||||
package eu.kanade.tachiyomi.extension.fr.kangaryu
 | 
					package eu.kanade.tachiyomi.extension.fr.kangaryu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.github.salomonbrys.kotson.array
 | 
					 | 
				
			||||||
import com.github.salomonbrys.kotson.fromJson
 | 
					 | 
				
			||||||
import com.github.salomonbrys.kotson.get
 | 
					 | 
				
			||||||
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.GET
 | 
				
			||||||
import eu.kanade.tachiyomi.source.model.FilterList
 | 
					import eu.kanade.tachiyomi.source.model.FilterList
 | 
				
			||||||
import eu.kanade.tachiyomi.source.model.MangasPage
 | 
					import eu.kanade.tachiyomi.source.model.MangasPage
 | 
				
			||||||
@ -13,11 +7,16 @@ import eu.kanade.tachiyomi.source.model.Page
 | 
				
			|||||||
import eu.kanade.tachiyomi.source.model.SChapter
 | 
					import eu.kanade.tachiyomi.source.model.SChapter
 | 
				
			||||||
import eu.kanade.tachiyomi.source.model.SManga
 | 
					import eu.kanade.tachiyomi.source.model.SManga
 | 
				
			||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
 | 
					import eu.kanade.tachiyomi.source.online.ParsedHttpSource
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.Json
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.jsonArray
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.jsonObject
 | 
				
			||||||
 | 
					import kotlinx.serialization.json.jsonPrimitive
 | 
				
			||||||
import okhttp3.OkHttpClient
 | 
					import okhttp3.OkHttpClient
 | 
				
			||||||
import okhttp3.Request
 | 
					import okhttp3.Request
 | 
				
			||||||
import okhttp3.Response
 | 
					import okhttp3.Response
 | 
				
			||||||
import org.jsoup.nodes.Document
 | 
					import org.jsoup.nodes.Document
 | 
				
			||||||
import org.jsoup.nodes.Element
 | 
					import org.jsoup.nodes.Element
 | 
				
			||||||
 | 
					import uy.kohesive.injekt.injectLazy
 | 
				
			||||||
import java.text.SimpleDateFormat
 | 
					import java.text.SimpleDateFormat
 | 
				
			||||||
import java.util.Locale
 | 
					import java.util.Locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -87,14 +86,15 @@ class Kangaryu : ParsedHttpSource() {
 | 
				
			|||||||
        return GET("$baseUrl/search?query=$query", headers)
 | 
					        return GET("$baseUrl/search?query=$query", headers)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val gson by lazy { Gson() }
 | 
					    private val json: Json by injectLazy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun searchMangaParse(response: Response): MangasPage {
 | 
					    override fun searchMangaParse(response: Response): MangasPage {
 | 
				
			||||||
        val mangas = gson.fromJson<JsonObject>(response.body!!.string())["suggestions"].array.map { json ->
 | 
					        val mangas = json.parseToJsonElement(response.body!!.string()).jsonObject["suggestions"]!!.jsonArray.map {
 | 
				
			||||||
 | 
					            val data = it.jsonObject["data"]!!.jsonPrimitive.content
 | 
				
			||||||
            SManga.create().apply {
 | 
					            SManga.create().apply {
 | 
				
			||||||
                url = "/manga/${json["data"].string}"
 | 
					                url = "/manga/$data"
 | 
				
			||||||
                title = json["value"].string
 | 
					                title = it.jsonObject["value"]!!.jsonPrimitive.content
 | 
				
			||||||
                thumbnail_url = "https://kangaryu-team.fr/uploads/manga/${json["data"].string}/cover/cover_250x350.jpg"
 | 
					                thumbnail_url = "https://kangaryu-team.fr/uploads/manga/$data/cover/cover_250x350.jpg"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return MangasPage(mangas, false)
 | 
					        return MangasPage(mangas, false)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user