Fix MangaHost not working (#3801)

* Fix MangaHost not working due to website redesign.

* Change OkHttpClient to Cloudflare.
This commit is contained in:
Alessandro Jean 2020-07-15 19:03:36 -03:00 committed by GitHub
parent 97472230c3
commit 4c2505faa2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 65 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'MangaHost' extName = 'MangaHost'
pkgNameSuffix = 'pt.mangahost' pkgNameSuffix = 'pt.mangahost'
extClass = '.MangaHost' extClass = '.MangaHost'
extVersionCode = 9 extVersionCode = 10
libVersion = '1.2' libVersion = '1.2'
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -11,6 +11,7 @@ import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -30,15 +31,17 @@ class MangaHost : ParsedHttpSource() {
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override fun headersBuilder(): Headers.Builder = Headers.Builder() override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("User-Agent", USER_AGENT) .add("User-Agent", USER_AGENT)
.add("Referer", baseUrl) .add("Referer", baseUrl)
private fun genericMangaFromElement(element: Element, lazy: Boolean = true): SManga = private fun genericMangaFromElement(element: Element): SManga =
SManga.create().apply { SManga.create().apply {
title = element.attr("title").withoutLanguage() title = element.attr("title").withoutLanguage()
thumbnail_url = element.select("img.manga") thumbnail_url = element.select("img")
.attr(if (lazy) "data-path" else "src") .attr("data-path")
.toLargeUrl() .toLargeUrl()
setUrlWithoutDomain(element.attr("href").substringBeforeLast("-mh")) setUrlWithoutDomain(element.attr("href").substringBeforeLast("-mh"))
} }
@ -52,7 +55,7 @@ class MangaHost : ParsedHttpSource() {
return GET("$baseUrl/mangas/mais-visualizados$pageStr", newHeaders) return GET("$baseUrl/mangas/mais-visualizados$pageStr", newHeaders)
} }
override fun popularMangaSelector(): String = "div.thumbnail div a.pull-left" override fun popularMangaSelector(): String = "div#dados div.manga-block div.manga-block-left a"
override fun popularMangaFromElement(element: Element): SManga = genericMangaFromElement(element) override fun popularMangaFromElement(element: Element): SManga = genericMangaFromElement(element)
@ -67,9 +70,9 @@ class MangaHost : ParsedHttpSource() {
return GET("$baseUrl/lancamentos$pageStr", newHeaders) return GET("$baseUrl/lancamentos$pageStr", newHeaders)
} }
override fun latestUpdatesSelector() = "table.table-lancamentos > tbody > tr > td:eq(0) > a" override fun latestUpdatesSelector() = "div#dados div.line-lancamentos div.column-img a"
override fun latestUpdatesFromElement(element: Element): SManga = genericMangaFromElement(element, false) override fun latestUpdatesFromElement(element: Element): SManga = genericMangaFromElement(element)
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
@ -87,56 +90,32 @@ class MangaHost : ParsedHttpSource() {
override fun searchMangaNextPageSelector(): String? = null override fun searchMangaNextPageSelector(): String? = null
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("div#page > section > div > div.pull-left") val infoElement = document.select("div.box-content div.w-row div.w-col:eq(1) article")
return SManga.create().apply { return SManga.create().apply {
author = infoElement.select("li:contains(Autor:)").textWithoutLabel() author = infoElement.select("div.text li div:contains(Autor:)").textWithoutLabel()
artist = infoElement.select("li:contains(Desenho (Art):)").textWithoutLabel() artist = infoElement.select("div.text li div:contains(Arte:)").textWithoutLabel()
genre = infoElement.select("li:contains(Categoria(s):)").textWithoutLabel() genre = infoElement.select("h3.subtitle + div.tags a").joinToString { it.text() }
description = infoElement.select("article").first()?.text() description = infoElement.select("div.text div.paragraph").first()?.text()
?.substringBefore("Relacionados:") ?.substringBefore("Relacionados:")
status = parseStatus(infoElement.select("li:contains(Status:)").text().orEmpty()) status = infoElement.select("div.text li div:contains(Status:)").text().toStatus()
thumbnail_url = document.select("div#page > section > div > img.thumbnail") thumbnail_url = document.select("div.box-content div.w-row div.w-col:eq(0) div.widget img")
.attr("src") .attr("src")
} }
} }
private fun parseStatus(status: String) = when {
status.contains("Ativo") -> SManga.ONGOING
status.contains("Completo") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
override fun chapterListSelector(): String = override fun chapterListSelector(): String =
"ul.list_chapters li a, table.table-hover:not(.table-mangas) > tbody > tr" "article.article > section.clearfix div.chapters div.cap div.card.pop"
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
val isNewLayout = element.tagName() == "a" name = element.select("div.pop-title").text().withoutLanguage()
scanlator = element.select("div.pop-content small strong").text()
if (isNewLayout) { date_upload = element.select("small.clearfix").text()
val content = Jsoup.parse(element.attr("data-content")) .substringAfter("Adicionado em ")
val date = content.select("small.clearfix").text() .let { DATE_FORMAT.tryParseTime(it) }
.substringAfter("Adicionado em ") chapter_number = element.select("div.pop-title span.btn-caps").text()
.toFloatOrNull() ?: 1f
return SChapter.create().apply { setUrlWithoutDomain(element.select("div.tags a").attr("href"))
name = element.attr("data-original-title").withoutLanguage()
scanlator = content.select("small.clearfix strong").text()
date_upload = DATE_FORMAT_NEW.tryParseTime(date)
chapter_number = element.text().toFloatOrNull() ?: 1f
setUrlWithoutDomain(content.select("div.clearfix a").attr("href"))
}
}
val firstColumn = element.select("td:eq(0)")
val secondColumn = element.select("td:eq(1)")
val thirdColumn = element.select("td:eq(2)")
return SChapter.create().apply {
name = firstColumn.select("a").text().withoutLanguage()
scanlator = secondColumn.text()
date_upload = DATE_FORMAT_OLD.tryParseTime(thirdColumn.text())
setUrlWithoutDomain(firstColumn.select("a").attr("href"))
}
} }
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
@ -149,17 +128,17 @@ class MangaHost : ParsedHttpSource() {
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
val documentStr = document.toString() val imagesHtml = document.select("script:containsData(var images)").first()!!
val images = documentStr .data()
.substringAfter(SCRIPT_BEGIN) .substringAfter("var images = [")
.substringBefore(SCRIPT_END) .substringBefore("];")
.replace(SCRIPT_REGEX, "") .replace(SCRIPT_REGEX, "")
val newDocument = Jsoup.parse(images) return Jsoup.parse(imagesHtml)
val referer = document.select("link[rel='canonical']").first() .select("a img")
.mapIndexed { i, el ->
return newDocument.select("a img") Page(i, document.location(), el.attr("src"))
.mapIndexed { i, el -> Page(i, referer.attr("href"), el.attr("src")) } }
} }
override fun imageUrlParse(document: Document) = "" override fun imageUrlParse(document: Document) = ""
@ -172,9 +151,15 @@ class MangaHost : ParsedHttpSource() {
return GET(page.imageUrl!!, newHeaders) return GET(page.imageUrl!!, newHeaders)
} }
private fun String.toStatus() = when {
contains("Ativo") -> SManga.ONGOING
contains("Completo") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
private fun SimpleDateFormat.tryParseTime(date: String): Long { private fun SimpleDateFormat.tryParseTime(date: String): Long {
return try { return try {
parse(date).time parse(date)!!.time
} catch (e: ParseException) { } catch (e: ParseException) {
0L 0L
} }
@ -184,19 +169,16 @@ class MangaHost : ParsedHttpSource() {
private fun String.toLargeUrl(): String = replace(IMAGE_REGEX, "_large.") private fun String.toLargeUrl(): String = replace(IMAGE_REGEX, "_large.")
private fun Elements.textWithoutLabel(): String = text()!!.substringAfter(":") private fun Elements.textWithoutLabel(): String = text()!!.substringAfter(":").trim()
companion object { companion object {
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36" private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"
private val LANG_REGEX = "( )?\\((PT-)?BR\\)".toRegex() private val LANG_REGEX = "( )?\\((PT-)?BR\\)".toRegex()
private val IMAGE_REGEX = "_(small|medium)\\.".toRegex() private val IMAGE_REGEX = "_(small|medium|xmedium)\\.".toRegex()
private val DATE_FORMAT_OLD by lazy { SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH) } private val DATE_FORMAT by lazy { SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH) }
private val DATE_FORMAT_NEW by lazy { SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH) }
private const val SCRIPT_BEGIN = "var images = ["
private const val SCRIPT_END = "];"
private val SCRIPT_REGEX = "[\",]".toRegex() private val SCRIPT_REGEX = "[\",]".toRegex()
} }
} }