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:
AwkwardPeak7 2024-02-18 16:03:55 +05:00 committed by Draff
parent 42d15fed81
commit 8e7bba9d87
4 changed files with 56 additions and 161 deletions

View File

@ -1,11 +1,9 @@
ext {
extName = 'Rizz Comic'
extClass = '.RizzComic'
extVersionCode = 3
themePkg = 'mangathemesia'
baseUrl = 'https://rizzcomic.com'
overrideVersionCode = 0
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:randomua"))
}

View File

@ -1,64 +1,38 @@
package eu.kanade.tachiyomi.extension.en.rizzcomic
import android.app.Application
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.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
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.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
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 eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.FormBody
import okhttp3.Request
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.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 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)
.build()
}
override fun headersBuilder() = super.headersBuilder()
.set("Referer", "$baseUrl/")
override val client = super.client.newBuilder()
.rateLimit(1, 3)
.build()
private val apiHeaders by lazy {
headersBuilder()
@ -73,12 +47,12 @@ class RizzComic : HttpSource(), ConfigurableSource {
private fun updateCache() {
if ((urlPrefix.isNullOrEmpty() || genreCache.isEmpty()) && attempts < 3) {
runCatching {
val document = client.newCall(GET("$baseUrl/series", headers))
val document = client.newCall(GET("$baseUrl$mangaUrlDirectory", headers))
.execute().use { it.asJsoup() }
urlPrefix = document.selectFirst(".listupd a")
?.attr("href")
?.substringAfter("/series/")
?.substringAfter("$mangaUrlDirectory/")
?.substringBefore("-")
genreCache = document.selectFirst(".filter .genrez")
@ -150,6 +124,31 @@ class RizzComic : HttpSource(), ConfigurableSource {
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 {
updateCache()
@ -180,7 +179,7 @@ class RizzComic : HttpSource(), ConfigurableSource {
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsRequest(manga))
.asObservableSuccess()
.map { mangaDetailsParse(it, manga) }
.map { mangaDetailsParse(it).apply { description = manga.description } }
}
override fun mangaDetailsRequest(manga: SManga): Request {
@ -198,54 +197,14 @@ class RizzComic : HttpSource(), ConfigurableSource {
return "$baseUrl/series/$urlPart$slug"
}
private fun mangaDetailsParse(response: Response, manga: SManga) = manga.apply {
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 chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
override fun chapterListParse(response: Response): List<SChapter> {
val result = response.parseAs<List<Chapter>>()
val slug = response.request.url.fragment!!
return result.map {
SChapter.create().apply {
url = "$slug-chapter-${it.name}"
name = "Chapter ${it.name}"
date_upload = runCatching {
dateFormat.parse(it.time!!)!!.time
}.getOrDefault(0L)
return super.chapterListParse(response).map { chapter ->
chapter.apply {
url = url.removeSuffix("/")
.substringAfter("/")
.substringAfter("-")
}
}
}
@ -254,50 +213,23 @@ class RizzComic : HttpSource(), ConfigurableSource {
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 {
val newHeaders = headersBuilder()
.set("Accept", "image/avif,image/webp,image/png,image/jpeg,*/*")
.set("Referer", "$baseUrl/")
.build()
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 =
use { it.body.string() }.let(json::decodeFromString)
companion object {
private fun String.capitalize() = replaceFirstChar {
if (it.isLowerCase()) {
it.titlecase(Locale.ROOT)
} else {
it.toString()
}
}
private val dateFormat by lazy {
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH)
private fun String.capitalize() = replaceFirstChar {
if (it.isLowerCase()) {
it.titlecase(Locale.ROOT)
} else {
it.toString()
}
}
}

View File

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