Tachiyomi-Extensions/multisrc/overrides/wpmangastream/komikcast/src/KomikCast.kt

195 lines
8.3 KiB
Kotlin
Raw Normal View History

package eu.kanade.tachiyomi.extension.id.komikcast
import eu.kanade.tachiyomi.multisrc.wpmangastream.WPMangaStream
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.injectLazy
import java.util.concurrent.TimeUnit
class KomikCast : WPMangaStream("Komik Cast", "https://komikcast.me", "id") {
// Formerly "Komik Cast (WP Manga Stream)"
override val id = 972717448578983812
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.rateLimit(3)
.build()
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
2021-12-27 11:04:16 +00:00
.add("Accept-language", "en-US,en;q=0.9,id;q=0.8")
.add("Referer", baseUrl)
2021-12-27 11:04:16 +00:00
.add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0")
override fun imageRequest(page: Page): Request {
val newHeaders = headersBuilder()
.set("Accept", "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8")
.set("Referer", baseUrl)
.build()
return GET(page.imageUrl!!, newHeaders)
}
override fun popularMangaSelector() = "div.list-update_item"
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/daftar-komik/page/$page/?orderby=popular", headers)
}
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/komik/page/$page/", headers)
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = if (query.isNotBlank()) {
val url = "$baseUrl/page/$page".toHttpUrlOrNull()!!.newBuilder()
val pattern = "\\s+".toRegex()
val q = query.replace(pattern, "+")
if (query.isNotEmpty()) {
url.addQueryParameter("s", q)
} else {
url.addQueryParameter("s", "")
}
url.toString()
} else {
var url = "$baseUrl/daftar-komik/page/$page".toHttpUrlOrNull()!!.newBuilder()
var orderBy: String
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is StatusFilter -> url.addQueryParameter("status", arrayOf("", "ongoing", "completed")[filter.state])
is GenreListFilter -> {
val genreInclude = mutableListOf<String>()
filter.state.forEach {
if (it.state == 1) {
genreInclude.add(it.id)
}
}
if (genreInclude.isNotEmpty()) {
genreInclude.forEach { genre ->
url.addQueryParameter("genre[]", genre)
}
}
}
is SortByFilter -> {
orderBy = filter.toUriPart()
url.addQueryParameter("orderby", orderBy)
}
is ProjectFilter -> {
if (filter.toUriPart() == "project-filter-on") {
url = "$baseUrl/project-list/page/$page".toHttpUrlOrNull()!!.newBuilder()
}
}
}
}
url.toString()
}
return GET(url, headers)
}
override fun popularMangaFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("a").first().let {
manga.setUrlWithoutDomain(it.attr("href"))
manga.title = it.select(".list-update_item-info h3.title").text()
manga.thumbnail_url = element.select("div.list-update_item-image img").imgAttr()
}
return manga
}
override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply {
document.select("div.komik_info").firstOrNull()?.let { infoElement ->
genre = infoElement.select(".komik_info-content-genre a").joinToString { it.text() }
status = parseStatus(infoElement.select("span:contains(Status:)").firstOrNull()?.ownText())
author = infoElement.select("span:contains(Author:)").firstOrNull()?.ownText()
artist = infoElement.select("span:contains(Author:)").firstOrNull()?.ownText()
description = infoElement.select("div.komik_info-description-sinopsis p").joinToString("\n") { it.text() }
thumbnail_url = infoElement.select("div.komik_info-content-thumbnail img").imgAttr()
// add series type(manga/manhwa/manhua/other) thinggy to genre
document.select(seriesTypeSelector).firstOrNull()?.ownText()?.let {
if (it.isEmpty().not() && genre!!.contains(it, true).not()) {
genre += if (genre!!.isEmpty()) it else ", $it"
}
}
// add alternative name to manga description
document.select(altNameSelector).firstOrNull()?.ownText()?.let {
if (it.isBlank().not() && it != "N/A" && it != "-") {
description = when {
description.isNullOrBlank() -> altName + it
else -> description + "\n\n$altName" + it
}
}
}
}
}
}
override val seriesTypeSelector = "span:contains(Type) a"
override val altNameSelector = ".komik_info-content-native"
override fun chapterListSelector() = "div.komik_info-chapters li"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select("a").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain(urlElement.attr("href"))
chapter.name = urlElement.text()
chapter.date_upload = element.select(".chapter-link-time").firstOrNull()?.text()?.let { parseChapterDate(it) } ?: 0
return chapter
}
override fun pageListParse(document: Document): List<Page> {
var doc = document
var cssQuery = "div#chapter_body .main-reading-area img.size-full"
val imageListRegex = Regex("chapterImages = (.*) \\|\\|")
val imageListMatchResult = imageListRegex.find(document.toString())
if (imageListMatchResult != null) {
val imageListJson = imageListMatchResult.destructured.toList()[0]
val imageList = json.parseToJsonElement(imageListJson).jsonObject
var imageServer = "cdn"
if (!imageList.containsKey(imageServer)) imageServer = imageList.keys.first()
val imageElement = imageList[imageServer]!!.jsonArray.joinToString("")
doc = Jsoup.parse(json.decodeFromString(imageElement))
cssQuery = "img.size-full"
}
return doc.select(cssQuery)
.mapIndexed { i, img -> Page(i, "", img.attr("abs:Src")) }
}
override fun getFilterList() = FilterList(
Filter.Header("NOTE: Ignored if using text search!"),
Filter.Separator(),
SortByFilter(),
Filter.Separator(),
StatusFilter(),
Filter.Separator(),
GenreListFilter(getGenreList()),
Filter.Header("NOTE: cant be used with other filter!"),
Filter.Header("$name Project List page"),
ProjectFilter()
)
private val json: Json by injectLazy()
}