Update 'HD' selectors and add blocking message. (#6638)

This commit is contained in:
Alessandro Jean 2021-04-20 17:37:12 -03:00 committed by GitHub
parent 91ad434ffa
commit e297c5fde1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 114 additions and 76 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'HQ Dragon' extName = 'HQ Dragon'
pkgNameSuffix = 'pt.hqdragon' pkgNameSuffix = 'pt.hqdragon'
extClass = '.HQDragon' extClass = '.HQDragon'
extVersionCode = 3 extVersionCode = 4
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -9,13 +9,15 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class HQDragon : ParsedHttpSource() { class HQDragon : ParsedHttpSource() {
@ -29,9 +31,14 @@ class HQDragon : ParsedHttpSource() {
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 1, TimeUnit.SECONDS)) .addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build() .build()
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Accept", ACCEPT)
.add("Accept-Language", ACCEPT_LANGUAGE)
.add("Referer", "$baseUrl/")
// Popular // Popular
// Top 10 // Top 10
@ -39,130 +46,161 @@ class HQDragon : ParsedHttpSource() {
return GET(baseUrl, headers) return GET(baseUrl, headers)
} }
override fun popularMangaSelector() = "ol.list-unstyled.mb-0 li a" override fun popularMangaParse(response: Response): MangasPage {
val results = super.popularMangaParse(response)
override fun popularMangaFromElement(element: Element): SManga { if (results.mangas.isEmpty()) {
val manga = SManga.create() throw Exception(BLOCK_MESSAGE)
}
manga.setUrlWithoutDomain(element.attr("href")) return results
manga.title = element.text()
return manga
} }
override fun popularMangaNextPageSelector() = "Not needed" override fun popularMangaSelector() = "h4:contains(Top 10) + ol.mb-0 li a"
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.text()
setUrlWithoutDomain(element.attr("href"))
}
override fun popularMangaNextPageSelector(): String? = null
// Latest // Latest
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
return super.fetchLatestUpdates(page)
.map { results -> results.copy(hasNextPage = page < 5) }
}
override fun latestUpdatesRequest(page: Int): Request { override fun latestUpdatesRequest(page: Int): Request {
val body = FormBody.Builder() val formBody = FormBody.Builder()
.add("pagina", page.toString()) .add("pagina", page.toString())
.build() .build()
val headers = headersBuilder() val headers = headersBuilder()
.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .add("Content-Length", formBody.contentLength().toString())
.add("Content-Type", formBody.contentType().toString())
.add("Origin", baseUrl)
.add("X-Requested-With", "XMLHttpRequest")
.set("Accept", "*/*")
.build() .build()
return POST("$baseUrl/assets/php/index_paginar.php", headers, body) return POST("$baseUrl/assets/php/index_paginar.php", headers, formBody)
} }
override fun latestUpdatesSelector() = "body a:has(img)"
override fun latestUpdatesParse(response: Response): MangasPage { override fun latestUpdatesParse(response: Response): MangasPage {
val document = response.asJsoup() val results = super.latestUpdatesParse(response)
val mangas = mutableListOf<SManga>()
document.select(latestUpdatesSelector()) if (results.mangas.isEmpty()) {
.forEach { mangas.add(latestUpdatesFromElements(it, it.nextElementSibling())) } throw Exception(BLOCK_MESSAGE)
}
return MangasPage(mangas, document.select("a[href\$=5693-x-force-2018]").isEmpty()) return results
} }
private fun latestUpdatesFromElements(imageElement: Element, titleElement: Element): SManga { override fun latestUpdatesSelector() = "a:has(img)"
val manga = SManga.create()
manga.thumbnail_url = imageElement.select("img").attr("src") override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
manga.setUrlWithoutDomain(titleElement.attr("href")) val image = element.select("img").first()
manga.title = titleElement.ownText()
return manga title = image.attr("alt")
thumbnail_url = image.attr("abs:src")
setUrlWithoutDomain(element.attr("href"))
} }
override fun latestUpdatesFromElement(element: Element): SManga = throw UnsupportedOperationException("Not used") override fun latestUpdatesNextPageSelector(): String? = null
override fun latestUpdatesNextPageSelector() = "not using"
// Search // Search
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
return GET("$baseUrl/pesquisa?pesquisa=$query", headers) val url = HttpUrl.parse("$baseUrl/pesquisa")!!.newBuilder()
.addQueryParameter("titulo", query)
return GET(url.toString(), headers)
} }
override fun searchMangaSelector() = "div.col-6" override fun searchMangaParse(response: Response): MangasPage {
val results = super.searchMangaParse(response)
override fun searchMangaFromElement(element: Element): SManga { if (results.mangas.isEmpty()) {
val manga = SManga.create() throw Exception(BLOCK_MESSAGE)
element.select("a + a").let {
manga.setUrlWithoutDomain(it.attr("href"))
manga.title = it.text()
} }
manga.thumbnail_url = element.select("img").attr("abs:src")
return manga return results
} }
override fun searchMangaNextPageSelector() = "Not needed" override fun searchMangaSelector() = "div.col-sm-6.col-md-3:has(img.img-thumbnail)"
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
val link = element.select("a + a").first()
title = link.text()
thumbnail_url = element.select("img").first().attr("abs:src")
setUrlWithoutDomain(link.attr("href"))
}
override fun searchMangaNextPageSelector(): String? = null
// Manga summary page // Manga summary page
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
val infoElement = document.select("div.blog-post div.row").first() val infoElement = document.select("div.blog-post div.row").firstOrNull()
?: throw Exception(BLOCK_MESSAGE)
val manga = SManga.create() title = infoElement.select("h3").first().text()
manga.title = infoElement.select("h3").first().text() author = infoElement.select("p:contains(Editora:)").first().textWithoutLabel()
manga.author = infoElement.select("p:contains(editora)").first().ownText() status = infoElement.select("p:contains(Status:) span").first().text().toStatus()
val status = infoElement.select("p:contains(status) span").text() description = infoElement.select("p:contains(Sinopse:)").first().ownText()
manga.status = parseStatus(status) thumbnail_url = infoElement.select("div.col-md-4 .img-fluid").first().attr("src")
manga.description = infoElement.select("p:contains(sinopse)").first().ownText()
manga.thumbnail_url = infoElement.select("img").attr("abs:src")
return manga
}
private fun parseStatus(status: String?) = when {
status == null -> SManga.UNKNOWN
status.contains("Ativo") -> SManga.ONGOING
status.contains("Completo") -> SManga.COMPLETED
else -> SManga.UNKNOWN
} }
// Chapters // Chapters
override fun chapterListSelector() = "tr a" override fun chapterListSelector() = "table.table tr a"
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
val chapter = SChapter.create() name = element.text().replace("Ler ", "")
setUrlWithoutDomain(element.attr("href"))
chapter.setUrlWithoutDomain(element.attr("href"))
chapter.name = element.text()
return chapter
} }
// Pages // Pages
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>() return document.select("img.img-responsive.img-manga")
.filter { it.attr("src").contains("/leitor/") }
document.select("img.img-responsive").forEachIndexed { i, img -> .mapIndexed { i, element ->
pages.add(Page(i, "", img.attr("abs:src"))) Page(i, document.location(), element.absUrl("src"))
} }
return pages
} }
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") override fun imageUrlParse(document: Document) = ""
override fun getFilterList() = FilterList() override fun imageRequest(page: Page): Request {
val newHeaders = headersBuilder()
.set("Accept", ACCEPT_IMAGE)
.set("Referer", page.url)
.build()
return GET(page.imageUrl!!, newHeaders)
}
private fun Element.textWithoutLabel(): String = text()!!.substringAfter(":").trim()
private fun String.toStatus(): Int = when {
contains("Ativo") -> SManga.ONGOING
contains("Completo") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
companion object {
private const val 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"
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 const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
private const val BLOCK_MESSAGE = "O site está bloqueando o Tachiyomi. " +
"Migre para outra fonte caso o problema persistir."
}
} }