239 lines
8.6 KiB
Kotlin
239 lines
8.6 KiB
Kotlin
|
package eu.kanade.tachiyomi.extension.id.komikgo
|
||
|
|
||
|
import eu.kanade.tachiyomi.multisrc.wpmangastream.WPMangaStream
|
||
|
import eu.kanade.tachiyomi.network.GET
|
||
|
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 okhttp3.Request
|
||
|
import org.jsoup.nodes.Document
|
||
|
import org.jsoup.nodes.Element
|
||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||
|
import okhttp3.HttpUrl
|
||
|
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||
|
import java.util.concurrent.TimeUnit
|
||
|
import okhttp3.OkHttpClient
|
||
|
|
||
|
class KomikGo : WPMangaStream("Komik GO", "https://komikgo.com", "id") {
|
||
|
// Formerly "Komik GO (WP Manga Stream)"
|
||
|
override val id = 1070674823324721554
|
||
|
|
||
|
private val rateLimitInterceptor = RateLimitInterceptor(4)
|
||
|
|
||
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||
|
.readTimeout(30, TimeUnit.SECONDS)
|
||
|
.addNetworkInterceptor(rateLimitInterceptor)
|
||
|
.build()
|
||
|
|
||
|
override fun popularMangaRequest(page: Int): Request {
|
||
|
return GET("$baseUrl/page/$page?s&post_type=wp-manga&m_orderby=views", headers)
|
||
|
}
|
||
|
|
||
|
override fun latestUpdatesRequest(page: Int): Request {
|
||
|
return GET("$baseUrl/page/$page?s&post_type=wp-manga&m_orderby=latest", headers)
|
||
|
}
|
||
|
|
||
|
override fun popularMangaSelector() = "div.c-tabs-item__content"
|
||
|
|
||
|
override fun popularMangaFromElement(element: Element): SManga {
|
||
|
val manga = SManga.create()
|
||
|
manga.thumbnail_url = element.select("div.tab-thumb > a > img").attr("data-src")
|
||
|
element.select("div.tab-thumb > a").first().let {
|
||
|
manga.setUrlWithoutDomain(it.attr("href"))
|
||
|
manga.title = it.attr("title")
|
||
|
}
|
||
|
return manga
|
||
|
}
|
||
|
|
||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||
|
val url = HttpUrl.parse("$baseUrl/page/$page")!!.newBuilder()
|
||
|
url.addQueryParameter("post_type", "wp-manga")
|
||
|
val pattern = "\\s+".toRegex()
|
||
|
val q = query.replace(pattern, "+")
|
||
|
if (query.isNotEmpty()) {
|
||
|
url.addQueryParameter("s", q)
|
||
|
} else {
|
||
|
url.addQueryParameter("s", "")
|
||
|
}
|
||
|
|
||
|
var orderBy: String
|
||
|
|
||
|
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
|
||
|
when (filter) {
|
||
|
// is Status -> url.addQueryParameter("manga_status", arrayOf("", "completed", "ongoing")[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 StatusList -> {
|
||
|
val statuses = mutableListOf<String>()
|
||
|
filter.state.forEach {
|
||
|
if (it.state == 1) {
|
||
|
statuses.add(it.id)
|
||
|
}
|
||
|
}
|
||
|
if (statuses.isNotEmpty()) {
|
||
|
statuses.forEach { status ->
|
||
|
url.addQueryParameter("status[]", status)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
is SortBy -> {
|
||
|
orderBy = filter.toUriPart()
|
||
|
url.addQueryParameter("m_orderby", orderBy)
|
||
|
}
|
||
|
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return GET(url.toString(), headers)
|
||
|
}
|
||
|
|
||
|
override fun popularMangaNextPageSelector() = "#navigation-ajax"
|
||
|
|
||
|
override fun mangaDetailsParse(document: Document): SManga {
|
||
|
val infoElement = document.select("div.site-content").first()
|
||
|
|
||
|
val manga = SManga.create()
|
||
|
manga.author = infoElement.select("div.author-content")?.text()
|
||
|
manga.artist = infoElement.select("div.artist-content")?.text()
|
||
|
|
||
|
val genres = mutableListOf<String>()
|
||
|
infoElement.select("div.genres-content a").forEach { element ->
|
||
|
val genre = element.text()
|
||
|
genres.add(genre)
|
||
|
}
|
||
|
manga.genre = genres.joinToString(", ")
|
||
|
manga.status = parseStatus(infoElement.select("div.post-status > div:nth-child(2) div").text())
|
||
|
|
||
|
manga.description = document.select("div.description-summary")?.text()
|
||
|
manga.thumbnail_url = document.select("div.summary_image > a > img").attr("data-src")
|
||
|
|
||
|
return manga
|
||
|
}
|
||
|
|
||
|
override fun chapterListSelector() = "li.wp-manga-chapter"
|
||
|
|
||
|
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 = parseChapterDate(element.select("span.chapter-release-date i").text())
|
||
|
return chapter
|
||
|
}
|
||
|
|
||
|
override fun pageListParse(document: Document): List<Page> {
|
||
|
return document.select("div.reading-content * img").mapIndexed { i, img ->
|
||
|
Page(i, "", img.imgAttr())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private class TextField(name: String, val key: String) : Filter.Text(name)
|
||
|
|
||
|
private class SortBy : UriPartFilter(
|
||
|
"Sort by",
|
||
|
arrayOf(
|
||
|
Pair("Relevance", ""),
|
||
|
Pair("Latest", "latest"),
|
||
|
Pair("A-Z", "alphabet"),
|
||
|
Pair("Rating", "rating"),
|
||
|
Pair("Trending", "trending"),
|
||
|
Pair("Most View", "views"),
|
||
|
Pair("New", "new-manga")
|
||
|
)
|
||
|
)
|
||
|
|
||
|
private class Status(name: String, val id: String = name) : Filter.TriState(name)
|
||
|
private class StatusList(statuses: List<Status>) : Filter.Group<Status>("Status", statuses)
|
||
|
|
||
|
override fun getFilterList() = FilterList(
|
||
|
TextField("Author", "author"),
|
||
|
TextField("Year", "release"),
|
||
|
SortBy(),
|
||
|
StatusList(getStatusList()),
|
||
|
GenreListFilter(getGenreList())
|
||
|
)
|
||
|
|
||
|
private fun getStatusList() = listOf(
|
||
|
Status("Completed", "end"),
|
||
|
Status("Ongoing", "on-going"),
|
||
|
Status("Canceled", "canceled"),
|
||
|
Status("Onhold", "on-hold")
|
||
|
)
|
||
|
|
||
|
override fun getGenreList(): List<Genre> = listOf(
|
||
|
Genre("Adventure", "Adventure"),
|
||
|
Genre("Action", "action"),
|
||
|
Genre("Adventure", "adventure"),
|
||
|
Genre("Cars", "cars"),
|
||
|
Genre("4-Koma", "4-koma"),
|
||
|
Genre("Comedy", "comedy"),
|
||
|
Genre("Completed", "completed"),
|
||
|
Genre("Cooking", "cooking"),
|
||
|
Genre("Dementia", "dementia"),
|
||
|
Genre("Demons", "demons"),
|
||
|
Genre("Doujinshi", "doujinshi"),
|
||
|
Genre("Drama", "drama"),
|
||
|
Genre("Ecchi", "ecchi"),
|
||
|
Genre("Fantasy", "fantasy"),
|
||
|
Genre("Game", "game"),
|
||
|
Genre("Gender Bender", "gender-bender"),
|
||
|
Genre("Harem", "harem"),
|
||
|
Genre("Historical", "historical"),
|
||
|
Genre("Horror", "horror"),
|
||
|
Genre("Isekai", "isekai"),
|
||
|
Genre("Josei", "josei"),
|
||
|
Genre("Kids", "kids"),
|
||
|
Genre("Magic", "magic"),
|
||
|
Genre("Manga", "manga"),
|
||
|
Genre("Manhua", "manhua"),
|
||
|
Genre("Manhwa", "manhwa"),
|
||
|
Genre("Martial Arts", "martial-arts"),
|
||
|
Genre("Mature", "mature"),
|
||
|
Genre("Mecha", "mecha"),
|
||
|
Genre("Military", "military"),
|
||
|
Genre("Music", "music"),
|
||
|
Genre("Mystery", "mystery"),
|
||
|
Genre("Old Comic", "old-comic"),
|
||
|
Genre("One Shot", "one-shot"),
|
||
|
Genre("Oneshot", "oneshot"),
|
||
|
Genre("Parodi", "parodi"),
|
||
|
Genre("Parody", "parody"),
|
||
|
Genre("Police", "police"),
|
||
|
Genre("Psychological", "psychological"),
|
||
|
Genre("Romance", "romance"),
|
||
|
Genre("Samurai", "samurai"),
|
||
|
Genre("School", "school"),
|
||
|
Genre("School Life", "school-life"),
|
||
|
Genre("Sci-Fi", "sci-fi"),
|
||
|
Genre("Seinen", "seinen"),
|
||
|
Genre("Shoujo", "shoujo"),
|
||
|
Genre("Shoujo Ai", "shoujo-ai"),
|
||
|
Genre("Shounen", "shounen"),
|
||
|
Genre("Shounen ai", "shounen-ai"),
|
||
|
Genre("Slice of Life", "slice-of-life"),
|
||
|
Genre("Sports", "sports"),
|
||
|
Genre("Super Power", "super-power"),
|
||
|
Genre("Supernatural", "supernatural"),
|
||
|
Genre("Thriller", "thriller"),
|
||
|
Genre("Tragedy", "tragedy"),
|
||
|
Genre("Vampire", "vampire"),
|
||
|
Genre("Webtoons", "webtoons"),
|
||
|
Genre("Yaoi", "yaoi"),
|
||
|
Genre("Yuri", "yuri")
|
||
|
)
|
||
|
}
|