Replace Gson usage with kotlinx.serialization in some sources (#7372)
* Replace Gson usage with kotlinx.serialization in some sources. * Add kotlinx.serialization to common-dependencies. * Add missing dependencies.
This commit is contained in:
parent
3d0119f2b8
commit
e8b6a225aa
@ -12,6 +12,8 @@ dependencies {
|
|||||||
compileOnly 'org.jsoup:jsoup:1.13.1'
|
compileOnly 'org.jsoup:jsoup:1.13.1'
|
||||||
compileOnly 'com.google.code.gson:gson:2.8.6'
|
compileOnly 'com.google.code.gson:gson:2.8.6'
|
||||||
compileOnly 'com.github.salomonbrys.kotson:kotson:2.5.0'
|
compileOnly 'com.github.salomonbrys.kotson:kotson:2.5.0'
|
||||||
|
compileOnly 'org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.2.0'
|
||||||
|
compileOnly 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0'
|
||||||
|
|
||||||
implementation project(":annotations")
|
implementation project(":annotations")
|
||||||
compileOnly project(':duktape-stub')
|
compileOnly project(':duktape-stub')
|
||||||
|
@ -6,12 +6,8 @@ ext {
|
|||||||
extName = 'MANGA Plus by SHUEISHA'
|
extName = 'MANGA Plus by SHUEISHA'
|
||||||
pkgNameSuffix = 'all.mangaplus'
|
pkgNameSuffix = 'all.mangaplus'
|
||||||
extClass = '.MangaPlusFactory'
|
extClass = '.MangaPlusFactory'
|
||||||
extVersionCode = 18
|
extVersionCode = 19
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.2.0'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -18,4 +18,3 @@ class MangaPlusIndonesian : MangaPlus("id", "eng", Language.INDONESIAN)
|
|||||||
class MangaPlusPortuguese : MangaPlus("pt-BR", "eng", Language.PORTUGUESE_BR)
|
class MangaPlusPortuguese : MangaPlus("pt-BR", "eng", Language.PORTUGUESE_BR)
|
||||||
class MangaPlusSpanish : MangaPlus("es", "esp", Language.SPANISH)
|
class MangaPlusSpanish : MangaPlus("es", "esp", Language.SPANISH)
|
||||||
class MangaPlusThai : MangaPlus("th", "eng", Language.THAI)
|
class MangaPlusThai : MangaPlus("th", "eng", Language.THAI)
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
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 = 'Bruttal'
|
extName = 'Bruttal'
|
||||||
pkgNameSuffix = 'pt.bruttal'
|
pkgNameSuffix = 'pt.bruttal'
|
||||||
extClass = '.Bruttal'
|
extClass = '.Bruttal'
|
||||||
extVersionCode = 2
|
extVersionCode = 3
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':lib-ratelimit')
|
implementation project(':lib-ratelimit')
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.extension.pt.bruttal
|
package eu.kanade.tachiyomi.extension.pt.bruttal
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.get
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonElement
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
@ -16,11 +9,14 @@ 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.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class Bruttal : HttpSource() {
|
class Bruttal : HttpSource() {
|
||||||
@ -41,6 +37,8 @@ class Bruttal : HttpSource() {
|
|||||||
.add("Referer", "$baseUrl/bruttal/")
|
.add("Referer", "$baseUrl/bruttal/")
|
||||||
.add("User-Agent", USER_AGENT)
|
.add("User-Agent", USER_AGENT)
|
||||||
|
|
||||||
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
val newHeaders = headersBuilder()
|
val newHeaders = headersBuilder()
|
||||||
.add("Accept", "application/json, text/plain, */*")
|
.add("Accept", "application/json, text/plain, */*")
|
||||||
@ -50,19 +48,17 @@ class Bruttal : HttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val json = response.asJson().obj
|
val homeDto = json.decodeFromString<BruttalHomeDto>(response.body!!.string())
|
||||||
|
|
||||||
val titles = json["list"].array.map { jsonEl ->
|
val titles = homeDto.list.map(::popularMangaFromObject)
|
||||||
popularMangaFromObject(jsonEl.obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
return MangasPage(titles, false)
|
return MangasPage(titles, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun popularMangaFromObject(obj: JsonObject): SManga = SManga.create().apply {
|
private fun popularMangaFromObject(comicbook: BruttalComicBookDto): SManga = SManga.create().apply {
|
||||||
title = obj["title"].string
|
title = comicbook.title
|
||||||
thumbnail_url = "$baseUrl/bruttal/" + obj["image_mobile"].string.removePrefix("./")
|
thumbnail_url = "$baseUrl/bruttal/" + comicbook.imageMobile.removePrefix("./")
|
||||||
url = "/bruttal" + obj["url"].string
|
url = "/bruttal" + comicbook.url
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||||
@ -96,20 +92,20 @@ class Bruttal : HttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val json = response.asJson().array
|
val comicBooks = json.decodeFromString<List<BruttalComicBookDto>>(response.body!!.string())
|
||||||
|
|
||||||
val titleUrl = response.request.header("Referer")!!.substringAfter("/bruttal")
|
val comicBookUrl = response.request.header("Referer")!!
|
||||||
val titleObj = json.first { it.obj["url"].string == titleUrl }.obj
|
.substringAfter("/bruttal")
|
||||||
val soonText = titleObj["soon_text"].string
|
val currentComicBook = comicBooks.first { it.url == comicBookUrl }
|
||||||
|
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = titleObj["title"].string
|
title = currentComicBook.title
|
||||||
thumbnail_url = "$baseUrl/bruttal/" + titleObj["image_mobile"].string.removePrefix("./")
|
thumbnail_url = "$baseUrl/bruttal/" + currentComicBook.imageMobile.removePrefix("./")
|
||||||
description = titleObj["synopsis"].string +
|
description = currentComicBook.synopsis +
|
||||||
(if (soonText.isEmpty()) "" else "\n\n$soonText")
|
(if (currentComicBook.soonText.isEmpty()) "" else "\n\n${currentComicBook.soonText}")
|
||||||
artist = titleObj["illustrator"].string
|
artist = currentComicBook.illustrator
|
||||||
author = titleObj["author"].string
|
author = currentComicBook.author
|
||||||
genre = titleObj["keywords"].string.replace("; ", ", ")
|
genre = currentComicBook.keywords.replace("; ", ", ")
|
||||||
status = SManga.ONGOING
|
status = SManga.ONGOING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,21 +114,24 @@ class Bruttal : HttpSource() {
|
|||||||
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 json = response.asJson().array
|
val comicBooks = json.decodeFromString<List<BruttalComicBookDto>>(response.body!!.string())
|
||||||
|
|
||||||
val titleUrl = response.request.header("Referer")!!.substringAfter("/bruttal")
|
val comicBookUrl = response.request.header("Referer")!!
|
||||||
val title = json.first { it.obj["url"].string == titleUrl }.obj
|
.substringAfter("/bruttal")
|
||||||
|
val currentComicBook = comicBooks.first { it.url == comicBookUrl }
|
||||||
|
|
||||||
return title["seasons"].array
|
return currentComicBook.seasons
|
||||||
.flatMap { it.obj["chapters"].array }
|
.flatMap { it.chapters }
|
||||||
.map { jsonEl -> chapterFromObject(jsonEl.obj) }
|
.map(::chapterFromObject)
|
||||||
.reversed()
|
.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun chapterFromObject(obj: JsonObject): SChapter = SChapter.create().apply {
|
private fun chapterFromObject(chapter: BruttalChapterDto): SChapter = SChapter.create().apply {
|
||||||
name = obj["title"].string
|
name = chapter.title
|
||||||
chapter_number = obj["share_title"].string.removePrefix("Capítulo ").toFloatOrNull() ?: -1f
|
chapter_number = chapter.shareTitle
|
||||||
url = "/bruttal" + obj["url"].string
|
.removePrefix("Capítulo ")
|
||||||
|
.toFloatOrNull() ?: -1f
|
||||||
|
url = "/bruttal" + chapter.url
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
@ -145,22 +144,28 @@ class Bruttal : HttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val json = response.asJson().array
|
val comicBooks = json.decodeFromString<List<BruttalComicBookDto>>(response.body!!.string())
|
||||||
|
|
||||||
val chapterUrl = response.request.header("Referer")!!
|
val chapterUrl = response.request.header("Referer")!!
|
||||||
val titleSlug = chapterUrl.substringAfter("bruttal/").substringBefore("/")
|
val comicBookSlug = chapterUrl
|
||||||
val season = chapterUrl.substringAfter("temporada-").substringBefore("/").toInt()
|
.substringAfter("bruttal/")
|
||||||
val chapter = chapterUrl.substringAfter("capitulo-")
|
.substringBefore("/")
|
||||||
|
val seasonNumber = chapterUrl
|
||||||
|
.substringAfter("temporada-")
|
||||||
|
.substringBefore("/")
|
||||||
|
val chapterNumber = chapterUrl.substringAfter("capitulo-")
|
||||||
|
|
||||||
val titleObj = json.first { it.obj["url"].string == "/$titleSlug" }.obj
|
val currentComicBook = comicBooks.first { it.url == "/$comicBookSlug" }
|
||||||
val seasonObj = titleObj["seasons"].array[season - 1].obj
|
val currentSeason = currentComicBook.seasons.first {
|
||||||
val chapterObj = seasonObj["chapters"].array.first {
|
it.alias.substringAfter("-") == seasonNumber
|
||||||
it.obj["alias"].string.substringAfter("-") == chapter
|
}
|
||||||
|
val currentChapter = currentSeason.chapters.first {
|
||||||
|
it.alias.substringAfter("-") == chapterNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
return chapterObj["images"].array
|
return currentChapter.images
|
||||||
.mapIndexed { i, jsonEl ->
|
.mapIndexed { i, bruttalImage ->
|
||||||
val imageUrl = "$baseUrl/bruttal/" + jsonEl.obj["image"].string.removePrefix("./")
|
val imageUrl = "$baseUrl/bruttal/" + bruttalImage.image.removePrefix("./")
|
||||||
Page(i, chapterUrl, imageUrl)
|
Page(i, chapterUrl, imageUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,10 +189,8 @@ class Bruttal : HttpSource() {
|
|||||||
|
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used")
|
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used")
|
||||||
|
|
||||||
private fun Response.asJson(): JsonElement = JsonParser.parseString(body!!.string())
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
|
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.pt.bruttal
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BruttalHomeDto(
|
||||||
|
val list: List<BruttalComicBookDto> = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BruttalComicBookDto(
|
||||||
|
val author: String,
|
||||||
|
val illustrator: String,
|
||||||
|
@SerialName("image_mobile") val imageMobile: String,
|
||||||
|
val keywords: String,
|
||||||
|
val seasons: List<BruttalSeasonDto> = emptyList(),
|
||||||
|
@SerialName("soon_text") val soonText: String = "",
|
||||||
|
val synopsis: String,
|
||||||
|
val title: String,
|
||||||
|
val url: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BruttalSeasonDto(
|
||||||
|
val alias: String,
|
||||||
|
val chapters: List<BruttalChapterDto> = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BruttalChapterDto(
|
||||||
|
val alias: String,
|
||||||
|
val images: List<BruttalImageDto> = emptyList(),
|
||||||
|
@SerialName("share_title") val shareTitle: String,
|
||||||
|
val title: String,
|
||||||
|
val url: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BruttalImageDto(
|
||||||
|
val image: String
|
||||||
|
)
|
@ -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 = 'HipercooL'
|
extName = 'HipercooL'
|
||||||
pkgNameSuffix = 'pt.hipercool'
|
pkgNameSuffix = 'pt.hipercool'
|
||||||
extClass = '.Hipercool'
|
extClass = '.Hipercool'
|
||||||
extVersionCode = 6
|
extVersionCode = 7
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.extension.pt.hipercool
|
package eu.kanade.tachiyomi.extension.pt.hipercool
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.get
|
|
||||||
import com.github.salomonbrys.kotson.int
|
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonElement
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.annotations.Nsfw
|
import eu.kanade.tachiyomi.annotations.Nsfw
|
||||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
@ -21,7 +11,13 @@ 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.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -29,10 +25,10 @@ import okhttp3.Request
|
|||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
@Nsfw
|
@Nsfw
|
||||||
class Hipercool : HttpSource() {
|
class Hipercool : HttpSource() {
|
||||||
@ -49,7 +45,8 @@ class Hipercool : HttpSource() {
|
|||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
.addInterceptor(RateLimitInterceptor(1, 1, TimeUnit.SECONDS))
|
.addInterceptor(SpecificHostRateLimitInterceptor(baseUrl.toHttpUrl(), 1))
|
||||||
|
.addInterceptor(SpecificHostRateLimitInterceptor(STATIC_URL.toHttpUrl(), 2))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||||
@ -57,31 +54,27 @@ class Hipercool : HttpSource() {
|
|||||||
.add("Referer", baseUrl)
|
.add("Referer", baseUrl)
|
||||||
.add("X-Requested-With", "XMLHttpRequest")
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
|
|
||||||
private fun genericMangaListParse(response: Response): MangasPage {
|
private val json: Json by injectLazy()
|
||||||
val result = response.asJson().array
|
|
||||||
|
|
||||||
if (result.size() == 0)
|
private fun genericMangaListParse(response: Response): MangasPage {
|
||||||
|
val chapters = json.decodeFromString<List<HipercoolChapterDto>>(response.body!!.string())
|
||||||
|
|
||||||
|
if (chapters.isEmpty())
|
||||||
return MangasPage(emptyList(), false)
|
return MangasPage(emptyList(), false)
|
||||||
|
|
||||||
val mangaList = result
|
val mangaList = chapters
|
||||||
.map { genericMangaFromObject(it.obj) }
|
.map(::genericMangaFromObject)
|
||||||
.distinctBy { it.title }
|
.distinctBy { it.title }
|
||||||
|
|
||||||
val hasNextPage = result.size() == DEFAULT_COUNT
|
val hasNextPage = chapters.size == DEFAULT_COUNT
|
||||||
|
|
||||||
return MangasPage(mangaList, hasNextPage)
|
return MangasPage(mangaList, hasNextPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun genericMangaFromObject(obj: JsonObject): SManga {
|
private fun genericMangaFromObject(chapter: HipercoolChapterDto): SManga = SManga.create().apply {
|
||||||
val book = obj["_book"].obj
|
title = chapter.book!!.title
|
||||||
val bookSlug = book["slug"].string
|
thumbnail_url = chapter.book.slug.toThumbnailUrl(chapter.book.revision)
|
||||||
val bookRevision = book["revision"]?.int ?: 1
|
url = "/books/" + chapter.book.slug
|
||||||
|
|
||||||
return SManga.create().apply {
|
|
||||||
title = book["title"].string
|
|
||||||
thumbnail_url = bookSlug.toThumbnailUrl(bookRevision)
|
|
||||||
url = "/books/$bookSlug"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The source does not have popular mangas, so use latest instead.
|
// The source does not have popular mangas, so use latest instead.
|
||||||
@ -100,12 +93,12 @@ class Hipercool : HttpSource() {
|
|||||||
val mediaType = "application/json; charset=utf-8".toMediaTypeOrNull()
|
val mediaType = "application/json; charset=utf-8".toMediaTypeOrNull()
|
||||||
|
|
||||||
// Create json body.
|
// Create json body.
|
||||||
val json = jsonObject(
|
val json = buildJsonObject {
|
||||||
"start" to (page - 1) * DEFAULT_COUNT,
|
put("start", (page - 1) * DEFAULT_COUNT)
|
||||||
"count" to DEFAULT_COUNT,
|
put("content", DEFAULT_COUNT)
|
||||||
"text" to query,
|
put("text", query)
|
||||||
"type" to "text"
|
put("type", "text")
|
||||||
)
|
}
|
||||||
|
|
||||||
val body = json.toString().toRequestBody(mediaType)
|
val body = json.toString().toRequestBody(mediaType)
|
||||||
|
|
||||||
@ -130,27 +123,27 @@ class Hipercool : HttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val result = response.asJson().obj
|
val book = json.decodeFromString<HipercoolBookDto>(response.body!!.string())
|
||||||
|
|
||||||
val artists = result["tags"].array
|
val artists = book.tags
|
||||||
.filter { it["label"].string == "Artista" }
|
.filter { it.label == "Artista" }
|
||||||
.flatMap { it["values"].array }
|
.flatMap { it.values }
|
||||||
.joinToString("; ") { it["label"].string }
|
.joinToString("; ") { it.label }
|
||||||
|
|
||||||
val authors = result["tags"].array
|
val authors = book.tags
|
||||||
.filter { it["label"].string == "Autor" }
|
.filter { it.label == "Autor" }
|
||||||
.flatMap { it["values"].array }
|
.flatMap { it.values }
|
||||||
.joinToString("; ") { it["label"].string }
|
.joinToString("; ") { it.label }
|
||||||
|
|
||||||
val tags = result["tags"].array
|
val tags = book.tags
|
||||||
.filter { it["label"].string == "Tags" }
|
.filter { it.label == "Tags" }
|
||||||
.flatMap { it["values"].array }
|
.flatMap { it.values }
|
||||||
.joinToString(", ") { it["label"].string }
|
.joinToString { it.label }
|
||||||
|
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = result["title"].string
|
title = book.title
|
||||||
thumbnail_url = result["slug"].string.toThumbnailUrl(result["revision"].int)
|
thumbnail_url = book.slug.toThumbnailUrl(book.revision)
|
||||||
description = result["synopsis"]?.string ?: ""
|
description = book.synopsis.orEmpty()
|
||||||
artist = artists
|
artist = artists
|
||||||
author = authors
|
author = authors
|
||||||
genre = tags
|
genre = tags
|
||||||
@ -161,31 +154,31 @@ class Hipercool : HttpSource() {
|
|||||||
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 result = response.asJson().obj
|
val book = json.decodeFromString<HipercoolBookDto>(response.body!!.string())
|
||||||
|
|
||||||
if (!result["chapters"]!!.isJsonArray)
|
if (book.chapters is JsonPrimitive)
|
||||||
return emptyList()
|
return emptyList()
|
||||||
|
|
||||||
return result["chapters"].array
|
return json.decodeFromString<List<HipercoolChapterDto>>(book.chapters.toString())
|
||||||
.map { chapterListItemParse(result, it.obj) }
|
.map { chapterListItemParse(book, it) }
|
||||||
.reversed()
|
.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun chapterListItemParse(book: JsonObject, obj: JsonObject): SChapter = SChapter.create().apply {
|
private fun chapterListItemParse(book: HipercoolBookDto, chapter: HipercoolChapterDto): SChapter =
|
||||||
name = obj["title"].string
|
SChapter.create().apply {
|
||||||
chapter_number = obj["title"].string.toFloatOrNull() ?: -1f
|
name = "Cap. " + chapter.title
|
||||||
// The property is written wrong.
|
chapter_number = chapter.title.toFloatOrNull() ?: -1f
|
||||||
date_upload = DATE_FORMATTER.tryParseTime(obj["publishied_at"].string)
|
date_upload = chapter.publishedAt.toDate()
|
||||||
|
|
||||||
val fullUrl = "$baseUrl/books".toHttpUrlOrNull()!!.newBuilder()
|
val fullUrl = "$baseUrl/books".toHttpUrlOrNull()!!.newBuilder()
|
||||||
.addPathSegment(book["slug"].string)
|
.addPathSegment(book.slug)
|
||||||
.addPathSegment(obj["slug"].string)
|
.addPathSegment(chapter.slug)
|
||||||
.addQueryParameter("images", obj["images"].int.toString())
|
.addQueryParameter("images", chapter.images.toString())
|
||||||
.addQueryParameter("revision", book["revision"].int.toString())
|
.addQueryParameter("revision", book.revision.toString())
|
||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
setUrlWithoutDomain(fullUrl)
|
setUrlWithoutDomain(fullUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||||
val chapterUrl = (baseUrl + chapter.url).toHttpUrlOrNull()!!
|
val chapterUrl = (baseUrl + chapter.url).toHttpUrlOrNull()!!
|
||||||
@ -228,9 +221,9 @@ class Hipercool : HttpSource() {
|
|||||||
return GET(page.imageUrl!!, newHeaders)
|
return GET(page.imageUrl!!, newHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SimpleDateFormat.tryParseTime(date: String): Long {
|
private fun String.toDate(): Long {
|
||||||
return try {
|
return try {
|
||||||
parse(date.substringBefore("T"))?.time ?: 0L
|
DATE_FORMATTER.parse(substringBefore("T"))?.time ?: 0L
|
||||||
} catch (e: ParseException) {
|
} catch (e: ParseException) {
|
||||||
0L
|
0L
|
||||||
}
|
}
|
||||||
@ -243,13 +236,11 @@ class Hipercool : HttpSource() {
|
|||||||
.addQueryParameter("revision", revision.toString())
|
.addQueryParameter("revision", revision.toString())
|
||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
private fun Response.asJson(): JsonElement = JsonParser.parseString(body!!.string())
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val STATIC_URL = "https://static.hiper.cool"
|
private const val STATIC_URL = "https://static.hiper.cool"
|
||||||
|
|
||||||
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
|
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
|
||||||
|
|
||||||
private const val DEFAULT_COUNT = 40
|
private const val DEFAULT_COUNT = 40
|
||||||
|
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.pt.hipercool
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HipercoolBookDto(
|
||||||
|
val chapters: JsonElement,
|
||||||
|
val revision: Int = 1,
|
||||||
|
val slug: String,
|
||||||
|
val synopsis: String? = null,
|
||||||
|
val tags: List<HipercoolTagDto> = emptyList(),
|
||||||
|
val title: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HipercoolTagDto(
|
||||||
|
val label: String,
|
||||||
|
val values: List<HipercoolTagDto> = emptyList()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class HipercoolChapterDto(
|
||||||
|
@SerialName("_book") val book: HipercoolBookDto? = null,
|
||||||
|
val images: Int = 0,
|
||||||
|
@SerialName("publishied_at") val publishedAt: String,
|
||||||
|
val slug: String,
|
||||||
|
val title: String
|
||||||
|
)
|
@ -6,13 +6,12 @@ ext {
|
|||||||
extName = 'Dmzj'
|
extName = 'Dmzj'
|
||||||
pkgNameSuffix = 'zh.dmzj'
|
pkgNameSuffix = 'zh.dmzj'
|
||||||
extClass = '.Dmzj'
|
extClass = '.Dmzj'
|
||||||
extVersionCode = 17
|
extVersionCode = 18
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':lib-ratelimit')
|
implementation project(':lib-ratelimit')
|
||||||
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.2.0'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user