Add Gattsu theme to multisrc. (#8245)

This commit is contained in:
Alessandro Jean 2021-07-23 16:40:29 -03:00 committed by GitHub
parent cb0c52aaf6
commit d45892ced1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 246 additions and 0 deletions

View File

@ -0,0 +1,4 @@
dependencies {
implementation project(':lib-ratelimit')
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -0,0 +1,43 @@
package eu.kanade.tachiyomi.extension.pt.hentaikai
import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.gattsu.Gattsu
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Element
import java.util.concurrent.TimeUnit
@Nsfw
class HentaiKai : Gattsu(
"Hentai Kai",
"https://hentaikai.com",
"pt-BR"
) {
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build()
override fun latestUpdatesRequest(page: Int): Request {
val pagePath = if (page > 1) "page/$page" else ""
return GET("$baseUrl/mangas-e-hqs-recentes/$pagePath", headers)
}
override fun latestUpdatesSelector() =
"div.meio div#fotos div.listaFotoConteudo > a[href^=$baseUrl]:not([title*=Episódio]):first-of-type"
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
title = element.attr("title")
thumbnail_url =
element.select("span.listaFotoThumb img.wp-post-image").first()!!.attr("src")
setUrlWithoutDomain(element.attr("href"))
}
override fun latestUpdatesNextPageSelector() = "div.meio div#fotos ul.paginacao li.next > a"
override fun searchMangaSelector() = "div.meio div.lista div.listaFotoConteudo > a[href^=$baseUrl]:not([title*=Episódio]):first-of-type"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -0,0 +1,19 @@
package eu.kanade.tachiyomi.extension.pt.hentaiseason
import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.gattsu.Gattsu
import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit
@Nsfw
class HentaiSeason : Gattsu(
"Hentai Season",
"https://hentaiseason.com",
"pt-BR"
) {
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build()
}

View File

@ -0,0 +1,154 @@
package eu.kanade.tachiyomi.multisrc.gattsu
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 eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
abstract class Gattsu(
override val name: String,
override val baseUrl: String,
override val lang: String
) : ParsedHttpSource() {
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override fun headersBuilder() = Headers.Builder()
.add("Accept", ACCEPT)
.add("Accept-Language", ACCEPT_LANGUAGE)
.add("Referer", baseUrl)
// Website does not have a popular, so use latest instead.
override fun popularMangaRequest(page: Int): Request = latestUpdatesRequest(page)
override fun popularMangaSelector(): String = latestUpdatesSelector()
override fun popularMangaFromElement(element: Element): SManga = latestUpdatesFromElement(element)
override fun popularMangaNextPageSelector(): String? = latestUpdatesNextPageSelector()
override fun latestUpdatesRequest(page: Int): Request = GET(baseUrl, headers)
override fun latestUpdatesSelector() = "div.meio div.lista ul li a[href^=$baseUrl]"
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
title = element.select("span.thumb-titulo").first()!!.text()
thumbnail_url = element.select("span.thumb-imagem img.wp-post-image").first()!!.attr("src")
setUrlWithoutDomain(element.attr("href"))
}
override fun latestUpdatesNextPageSelector(): String? = null
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val searchUrl = "$baseUrl/page/$page/".toHttpUrlOrNull()!!.newBuilder()
.addQueryParameter("s", query)
.addQueryParameter("post_type", "post")
.toString()
return GET(searchUrl, headers)
}
override fun searchMangaSelector() = latestUpdatesSelector()
override fun searchMangaFromElement(element: Element): SManga = latestUpdatesFromElement(element)
override fun searchMangaNextPageSelector() = "ul.paginacao li.next > a"
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
val postBox = document.select("div.meio div.post-box").first()!!
title = postBox.select("h1.post-titulo").first()!!.text()
author = postBox.select("ul.post-itens li:contains(Artista) a").firstOrNull()?.text()
genre = postBox.select("ul.post-itens li:contains(Tags) a")
.joinToString(", ") { it.text() }
description = postBox.select("div.post-texto p")
.joinToString("\n\n") { it.text() }
.replace("Sinopse :", "")
.trim()
status = SManga.COMPLETED
thumbnail_url = postBox.select("div.post-capa > img.wp-post-image")
.attr("src")
.withoutSize()
}
override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup()
if (document.select(pageListSelector()).firstOrNull() == null) {
return emptyList()
}
return document.select(chapterListSelector())
.map { chapterFromElement(it) }
}
override fun chapterListSelector() = "div.meio div.post-box:first-of-type"
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
name = "Capítulo único"
scanlator = element.select("ul.post-itens li:contains(Tradutor) a").firstOrNull()?.text()
date_upload = element.ownerDocument().select("meta[property=article:published_time]").firstOrNull()
?.attr("content")
.orEmpty()
.toDate()
setUrlWithoutDomain(element.ownerDocument().location())
}
protected open fun pageListSelector(): String = "div.meio div.post-box ul.post-fotos li a img"
override fun pageListParse(document: Document): List<Page> {
return document.select(pageListSelector())
.mapIndexed { i, el ->
Page(i, document.location(), el.attr("src").withoutSize())
}
}
override fun imageUrlParse(document: Document) = ""
override fun imageRequest(page: Page): Request {
val imageHeaders = headersBuilder()
.add("Accept", ACCEPT_IMAGE)
.add("Referer", page.url)
.build()
return GET(page.imageUrl!!, imageHeaders)
}
private fun String.toDate(): Long {
return try {
DATE_FORMATTER.parse(this.substringBefore("T"))?.time ?: 0L
} catch (e: ParseException) {
0L
}
}
private fun String.withoutSize(): String = this.replace(THUMB_SIZE_REGEX, ".")
companion object {
private const val ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," +
"image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"
private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5"
private val THUMB_SIZE_REGEX = "-\\d+x\\d+\\.".toRegex()
private val DATE_FORMATTER by lazy {
SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
}
}
}

View File

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.multisrc.gattsu
import generator.ThemeSourceData.SingleLang
import generator.ThemeSourceGenerator
class GattsuGenerator : ThemeSourceGenerator {
override val themePkg = "gattsu"
override val themeClass = "Gattsu"
override val baseVersionCode: Int = 1
override val sources = listOf(
SingleLang("Hentai Kai", "https://hentaikai.com", "pt-BR", isNsfw = true),
SingleLang("Hentai Season", "https://hentaiseason.com", "pt-BR", isNsfw = true)
)
companion object {
@JvmStatic
fun main(args: Array<String>) {
GattsuGenerator().createAll()
}
}
}