Add MH source (closes #10963). (#11169)

This commit is contained in:
Alessandro Jean 2022-03-18 23:22:25 -03:00 committed by GitHub
parent b44c722988
commit a65be70e4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 161 additions and 0 deletions

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension" />

View File

@ -0,0 +1,18 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Muito Hentai'
pkgNameSuffix = 'pt.muitohentai'
extClass = '.MuitoHentai'
extVersionCode = 1
isNsfw = true
}
dependencies {
implementation project(':lib-ratelimit')
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,140 @@
package eu.kanade.tachiyomi.extension.pt.muitohentai
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
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 kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.injectLazy
import java.util.Locale
import java.util.concurrent.TimeUnit
class MuitoHentai : ParsedHttpSource() {
override val name = "Muito Hentai"
override val baseUrl = "https://www.muitohentai.com"
override val lang = "pt-BR"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build()
private val json: Json by injectLazy()
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Referer", "$baseUrl/")
// The source does not have a popular list page, so we use the list instead.
override fun popularMangaRequest(page: Int): Request {
val newHeaders = headersBuilder()
.set("Referer", if (page == 1) baseUrl else "$baseUrl/mangas/${page - 1}")
.build()
val pageStr = if (page != 1) page.toString() else ""
return GET("$baseUrl/mangas/$pageStr", newHeaders)
}
override fun popularMangaSelector(): String = "#archive-content article.tvshows"
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.selectFirst("div.data h3 a")!!.text()
thumbnail_url = element.selectFirst("div.poster img")!!.attr("abs:src")
setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
}
override fun popularMangaNextPageSelector() = "#paginacao a:last-child:contains(»)"
override fun latestUpdatesRequest(page: Int) = popularMangaRequest(page)
override fun latestUpdatesSelector(): String = "ul.lancamento-cap2 > li"
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
title = element.selectFirst("h2")!!.text()
thumbnail_url = element.selectFirst("div.capaMangaHentai img")!!.attr("abs:src")
setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href"))
}
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val searchUrl = "$baseUrl/buscar-manga/".toHttpUrl().newBuilder()
.addQueryParameter("q", query)
.toString()
return GET(searchUrl, headers)
}
override fun searchMangaSelector() = popularMangaSelector()
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun searchMangaNextPageSelector(): String? = null
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
author = document.selectFirst("div:has(strong:contains(Autor))")?.ownText()
genre = document.select("a.genero_btn").joinToString { it.text().capitalize(LOCALE) }
description = document.selectFirst("div.backgroundpost:contains(Sinopse)")?.ownText()
thumbnail_url = document.selectFirst("#capaAnime img")?.attr("src")
}
override fun chapterListParse(response: Response): List<SChapter> {
return super.chapterListParse(response).reversed()
}
override fun chapterListSelector(): String = "div.backgroundpost:contains(Capítulos de) h3 > a"
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
name = element.ownText().trim()
setUrlWithoutDomain(element.attr("abs:href"))
}
override fun pageListRequest(chapter: SChapter): Request {
val newHeader = headersBuilder()
.set("Referer", "$baseUrl${chapter.url}".substringBeforeLast("/"))
.build()
return GET(baseUrl + chapter.url, newHeader)
}
override fun pageListParse(document: Document): List<Page> {
return document.selectFirst("script:containsData(numeroImgAtual)")
?.data()
?.substringAfter("var arr = ")
?.substringBefore(";")
?.let { json.parseToJsonElement(it).jsonArray }
?.mapIndexed { i, el ->
Page(i, document.location(), el.jsonPrimitive.content)
}
.orEmpty()
}
override fun imageUrlParse(document: Document) = ""
override fun imageRequest(page: Page): Request {
val newHeaders = headersBuilder()
.set("Referer", page.url)
.build()
return GET(page.imageUrl!!, newHeaders)
}
companion object {
private val LOCALE = Locale("pt", "BR")
}
}