RC: fix chapters (#1359)
* fix rizz chapters Co-authored-by: Anshuman Sarkar <77231921+Ryujin1108@users.noreply.github.com> * remove unused dto * lint * lint x2 --------- Co-authored-by: Anshuman Sarkar <77231921+Ryujin1108@users.noreply.github.com>
This commit is contained in:
parent
42d15fed81
commit
8e7bba9d87
|
@ -1,11 +1,9 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Rizz Comic'
|
extName = 'Rizz Comic'
|
||||||
extClass = '.RizzComic'
|
extClass = '.RizzComic'
|
||||||
extVersionCode = 3
|
themePkg = 'mangathemesia'
|
||||||
|
baseUrl = 'https://rizzcomic.com'
|
||||||
|
overrideVersionCode = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation(project(":lib:randomua"))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,64 +1,38 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.rizzcomic
|
package eu.kanade.tachiyomi.extension.en.rizzcomic
|
||||||
|
|
||||||
import android.app.Application
|
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import eu.kanade.tachiyomi.lib.randomua.addRandomUAPreferenceToScreen
|
|
||||||
import eu.kanade.tachiyomi.lib.randomua.getPrefCustomUA
|
|
||||||
import eu.kanade.tachiyomi.lib.randomua.getPrefUAType
|
|
||||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
|
||||||
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
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
||||||
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
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
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.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
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.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class RizzComic : HttpSource(), ConfigurableSource {
|
class RizzComic : MangaThemesia(
|
||||||
|
"Rizz Comic",
|
||||||
|
"https://rizzcomic.com",
|
||||||
|
"en",
|
||||||
|
mangaUrlDirectory = "/series",
|
||||||
|
dateFormat = SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH),
|
||||||
|
) {
|
||||||
|
|
||||||
override val name = "Rizz Comic"
|
override val client = super.client.newBuilder()
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val baseUrl = "https://rizzcomic.com"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
|
||||||
|
|
||||||
private val preferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val client by lazy {
|
|
||||||
network.cloudflareClient.newBuilder()
|
|
||||||
.setRandomUserAgent(
|
|
||||||
preferences.getPrefUAType(),
|
|
||||||
preferences.getPrefCustomUA(),
|
|
||||||
)
|
|
||||||
.rateLimit(1, 3)
|
.rateLimit(1, 3)
|
||||||
.build()
|
.build()
|
||||||
}
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
|
||||||
.set("Referer", "$baseUrl/")
|
|
||||||
|
|
||||||
private val apiHeaders by lazy {
|
private val apiHeaders by lazy {
|
||||||
headersBuilder()
|
headersBuilder()
|
||||||
|
@ -73,12 +47,12 @@ class RizzComic : HttpSource(), ConfigurableSource {
|
||||||
private fun updateCache() {
|
private fun updateCache() {
|
||||||
if ((urlPrefix.isNullOrEmpty() || genreCache.isEmpty()) && attempts < 3) {
|
if ((urlPrefix.isNullOrEmpty() || genreCache.isEmpty()) && attempts < 3) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val document = client.newCall(GET("$baseUrl/series", headers))
|
val document = client.newCall(GET("$baseUrl$mangaUrlDirectory", headers))
|
||||||
.execute().use { it.asJsoup() }
|
.execute().use { it.asJsoup() }
|
||||||
|
|
||||||
urlPrefix = document.selectFirst(".listupd a")
|
urlPrefix = document.selectFirst(".listupd a")
|
||||||
?.attr("href")
|
?.attr("href")
|
||||||
?.substringAfter("/series/")
|
?.substringAfter("$mangaUrlDirectory/")
|
||||||
?.substringBefore("-")
|
?.substringBefore("-")
|
||||||
|
|
||||||
genreCache = document.selectFirst(".filter .genrez")
|
genreCache = document.selectFirst(".filter .genrez")
|
||||||
|
@ -150,6 +124,31 @@ class RizzComic : HttpSource(), ConfigurableSource {
|
||||||
return FilterList(filters)
|
return FilterList(filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class Comic(
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
@SerialName("image_url") val cover: String? = null,
|
||||||
|
@SerialName("long_description") val synopsis: String? = null,
|
||||||
|
val status: String? = null,
|
||||||
|
val type: String? = null,
|
||||||
|
val artist: String? = null,
|
||||||
|
val author: String? = null,
|
||||||
|
val serialization: String? = null,
|
||||||
|
@SerialName("genre_id") val genres: String? = null,
|
||||||
|
) {
|
||||||
|
val slug get() = title.trim().lowercase()
|
||||||
|
.replace(slugRegex, "-")
|
||||||
|
.replace("-s-", "s-")
|
||||||
|
.replace("-ll-", "ll-")
|
||||||
|
|
||||||
|
val genreIds get() = genres?.split(",")?.map(String::trim)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val slugRegex = Regex("""[^a-z0-9]+""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
override fun searchMangaParse(response: Response): MangasPage {
|
||||||
updateCache()
|
updateCache()
|
||||||
|
|
||||||
|
@ -180,7 +179,7 @@ class RizzComic : HttpSource(), ConfigurableSource {
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
return client.newCall(mangaDetailsRequest(manga))
|
return client.newCall(mangaDetailsRequest(manga))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { mangaDetailsParse(it, manga) }
|
.map { mangaDetailsParse(it).apply { description = manga.description } }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||||
|
@ -198,54 +197,14 @@ class RizzComic : HttpSource(), ConfigurableSource {
|
||||||
return "$baseUrl/series/$urlPart$slug"
|
return "$baseUrl/series/$urlPart$slug"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mangaDetailsParse(response: Response, manga: SManga) = manga.apply {
|
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
||||||
val document = response.use { it.asJsoup() }
|
|
||||||
|
|
||||||
title = document.selectFirst("h1.entry-title")?.text().orEmpty()
|
|
||||||
artist = document.selectFirst(".tsinfo .imptdt:contains(artist) i")?.ownText()
|
|
||||||
author = listOfNotNull(
|
|
||||||
document.selectFirst(".tsinfo .imptdt:contains(author) i")?.ownText(),
|
|
||||||
document.selectFirst(".tsinfo .imptdt:contains(serialization) i")?.ownText(),
|
|
||||||
).joinToString()
|
|
||||||
genre = buildList {
|
|
||||||
add(
|
|
||||||
document.selectFirst(".tsinfo .imptdt:contains(type) a")
|
|
||||||
?.ownText()
|
|
||||||
?.capitalize(),
|
|
||||||
)
|
|
||||||
document.select(".mgen a").eachText().onEach { add(it) }
|
|
||||||
}.filterNotNull().joinToString()
|
|
||||||
status = document.selectFirst(".tsinfo .imptdt:contains(status) i")?.text().parseStatus()
|
|
||||||
thumbnail_url = document.selectFirst(".infomanga > div[itemprop=image] img, .thumb img")?.absUrl("src")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun String?.parseStatus(): Int = when {
|
|
||||||
this == null -> SManga.UNKNOWN
|
|
||||||
listOf("ongoing", "publishing").any { contains(it, ignoreCase = true) } -> SManga.ONGOING
|
|
||||||
contains("hiatus", ignoreCase = true) -> SManga.ON_HIATUS
|
|
||||||
contains("completed", ignoreCase = true) -> SManga.COMPLETED
|
|
||||||
listOf("dropped", "cancelled").any { contains(it, ignoreCase = true) } -> SManga.CANCELLED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga): Request {
|
|
||||||
val id = manga.url.substringAfter("#")
|
|
||||||
val slug = manga.url.substringBefore("#")
|
|
||||||
|
|
||||||
return GET("$baseUrl/index/search_chapters/$id#$slug", apiHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val result = response.parseAs<List<Chapter>>()
|
return super.chapterListParse(response).map { chapter ->
|
||||||
val slug = response.request.url.fragment!!
|
chapter.apply {
|
||||||
|
url = url.removeSuffix("/")
|
||||||
return result.map {
|
.substringAfter("/")
|
||||||
SChapter.create().apply {
|
.substringAfter("-")
|
||||||
url = "$slug-chapter-${it.name}"
|
|
||||||
name = "Chapter ${it.name}"
|
|
||||||
date_upload = runCatching {
|
|
||||||
dateFormat.parse(it.time!!)!!.time
|
|
||||||
}.getOrDefault(0L)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,40 +213,18 @@ class RizzComic : HttpSource(), ConfigurableSource {
|
||||||
return GET("$baseUrl/chapter/${getUrlPrefix()}-${chapter.url}", headers)
|
return GET("$baseUrl/chapter/${getUrlPrefix()}-${chapter.url}", headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
|
||||||
val document = response.use { it.asJsoup() }
|
|
||||||
val chapterUrl = response.request.url.toString()
|
|
||||||
|
|
||||||
return document.select("div#readerarea img")
|
|
||||||
.mapIndexed { i, img ->
|
|
||||||
Page(i, chapterUrl, img.absUrl("src"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageRequest(page: Page): Request {
|
override fun imageRequest(page: Page): Request {
|
||||||
val newHeaders = headersBuilder()
|
val newHeaders = headersBuilder()
|
||||||
.set("Accept", "image/avif,image/webp,image/png,image/jpeg,*/*")
|
.set("Accept", "image/avif,image/webp,image/png,image/jpeg,*/*")
|
||||||
|
.set("Referer", "$baseUrl/")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return GET(page.imageUrl!!, newHeaders)
|
return GET(page.imageUrl!!, newHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
|
||||||
addRandomUAPreferenceToScreen(screen)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response): String {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(): T =
|
private inline fun <reified T> Response.parseAs(): T =
|
||||||
use { it.body.string() }.let(json::decodeFromString)
|
use { it.body.string() }.let(json::decodeFromString)
|
||||||
|
|
||||||
companion object {
|
|
||||||
private fun String.capitalize() = replaceFirstChar {
|
private fun String.capitalize() = replaceFirstChar {
|
||||||
if (it.isLowerCase()) {
|
if (it.isLowerCase()) {
|
||||||
it.titlecase(Locale.ROOT)
|
it.titlecase(Locale.ROOT)
|
||||||
|
@ -295,9 +232,4 @@ class RizzComic : HttpSource(), ConfigurableSource {
|
||||||
it.toString()
|
it.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val dateFormat by lazy {
|
|
||||||
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.rizzcomic
|
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Comic(
|
|
||||||
val id: Int,
|
|
||||||
val title: String,
|
|
||||||
@SerialName("image_url") val cover: String? = null,
|
|
||||||
@SerialName("long_description") val synopsis: String? = null,
|
|
||||||
val status: String? = null,
|
|
||||||
val type: String? = null,
|
|
||||||
val artist: String? = null,
|
|
||||||
val author: String? = null,
|
|
||||||
val serialization: String? = null,
|
|
||||||
@SerialName("genre_id") val genres: String? = null,
|
|
||||||
) {
|
|
||||||
val slug get() = title.trim().lowercase()
|
|
||||||
.replace(slugRegex, "-")
|
|
||||||
.replace("-s-", "s-")
|
|
||||||
.replace("-ll-", "ll-")
|
|
||||||
|
|
||||||
val genreIds get() = genres?.split(",")?.map(String::trim)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val slugRegex = Regex("""[^a-z0-9]+""")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Chapter(
|
|
||||||
@SerialName("chapter_time") val time: String? = null,
|
|
||||||
@SerialName("chapter_title") val name: String,
|
|
||||||
)
|
|
Loading…
Reference in New Issue