MangaInUa: fix chapter list and page list (#17540)

This commit is contained in:
stevenyomi 2023-08-17 02:55:34 +08:00 committed by GitHub
parent 61383e923a
commit 1a3b4d2231
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 67 additions and 31 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'MangaInUa' extName = 'MangaInUa'
pkgNameSuffix = 'uk.mangainua' pkgNameSuffix = 'uk.mangainua'
extClass = '.Mangainua' extClass = '.Mangainua'
extVersionCode = 3 extVersionCode = 4
isNsfw = true isNsfw = true
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -7,13 +7,17 @@ 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.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import org.jsoup.select.Evaluator
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
@ -27,7 +31,7 @@ class Mangainua : ParsedHttpSource() {
override val client: OkHttpClient = network.cloudflareClient override val client: OkHttpClient = network.cloudflareClient
override fun headersBuilder(): Headers.Builder = Headers.Builder() override fun headersBuilder(): Headers.Builder = super.headersBuilder()
.add("Referer", baseUrl) .add("Referer", baseUrl)
// Popular // Popular
@ -37,11 +41,11 @@ class Mangainua : ParsedHttpSource() {
override fun popularMangaSelector() = "div.owl-carousel div.card--big" override fun popularMangaSelector() = "div.owl-carousel div.card--big"
override fun popularMangaFromElement(element: Element): SManga { override fun popularMangaFromElement(element: Element): SManga {
return SManga.create().apply { return SManga.create().apply {
element.select("h3.card__title a").first()!!.let { element.selectFirst("h3.card__title a")!!.let {
setUrlWithoutDomain(it.attr("href")) setUrlWithoutDomain(it.attr("href"))
title = it.text() title = it.text()
} }
thumbnail_url = element.select("img").attr("abs:src") thumbnail_url = element.selectFirst("img")?.absUrl("src")
} }
} }
override fun popularMangaNextPageSelector() = "not used" override fun popularMangaNextPageSelector() = "not used"
@ -53,11 +57,11 @@ class Mangainua : ParsedHttpSource() {
override fun latestUpdatesSelector() = "main.main article.item" override fun latestUpdatesSelector() = "main.main article.item"
override fun latestUpdatesFromElement(element: Element): SManga { override fun latestUpdatesFromElement(element: Element): SManga {
return SManga.create().apply { return SManga.create().apply {
element.select("h3.card__title a").first()!!.let { element.selectFirst("h3.card__title a")!!.let {
setUrlWithoutDomain(it.attr("href")) setUrlWithoutDomain(it.attr("href"))
title = it.text() title = it.text()
} }
thumbnail_url = element.select("div.card--big img").attr("abs:data-src") thumbnail_url = element.selectFirst("div.card--big img")?.absUrl("data-src")
} }
} }
override fun latestUpdatesNextPageSelector() = "a:contains(Наступна)" override fun latestUpdatesNextPageSelector() = "a:contains(Наступна)"
@ -76,18 +80,18 @@ class Mangainua : ParsedHttpSource() {
headers = headers, headers = headers,
) )
} else { } else {
throw UnsupportedOperationException("Запит має містити щонайменше 3 символи / The query must contain at least 3 characters") throw Exception("Запит має містити щонайменше 3 символи / The query must contain at least 3 characters")
} }
} }
override fun searchMangaSelector() = latestUpdatesSelector() override fun searchMangaSelector() = latestUpdatesSelector()
override fun searchMangaFromElement(element: Element): SManga { override fun searchMangaFromElement(element: Element): SManga {
return SManga.create().apply { return SManga.create().apply {
element.select("h3.card__title a").first()!!.let { element.selectFirst("h3.card__title a")!!.let {
setUrlWithoutDomain(it.attr("href")) setUrlWithoutDomain(it.attr("href"))
title = it.text() title = it.text()
} }
thumbnail_url = element.select("div.card--big img").attr("abs:src") thumbnail_url = element.selectFirst("div.card--big img")?.absUrl("src")
} }
} }
override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector() override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector()
@ -95,35 +99,40 @@ class Mangainua : ParsedHttpSource() {
// Manga Details // Manga Details
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply { return SManga.create().apply {
title = document.select("span.UAname").text() title = document.selectFirst("span.UAname")!!.text()
description = document.select("div.item__full-description").text() description = document.selectFirst("div.item__full-description")!!.text()
thumbnail_url = document.select("div.item__full-sidebar--poster img").first()!!.attr("abs:src") thumbnail_url = document.selectFirst("div.item__full-sidebar--poster img")!!.absUrl("src")
status = when (document.select("div.item__full-sideba--header:has(div:containsOwn(Статус перекладу:))").first()?.select("span.item__full-sidebar--description")?.first()?.text()) { status = when (document.selectFirst("div.item__full-sideba--header:has(div:containsOwn(Статус перекладу:))")?.selectFirst("span.item__full-sidebar--description")?.text()) {
"Триває" -> SManga.ONGOING "Триває" -> SManga.ONGOING
"Покинуто" -> SManga.CANCELLED "Покинуто" -> SManga.CANCELLED
"Закінчений" -> SManga.COMPLETED "Закінчений" -> SManga.COMPLETED
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
val type = when (document.select("div.item__full-sideba--header:has(div:containsOwn(Тип:))").first()?.select("span.item__full-sidebar--description")?.first()!!.text()) { val type = when (document.selectFirst("div.item__full-sideba--header:has(div:containsOwn(Тип:))")?.selectFirst("span.item__full-sidebar--description")!!.text()) {
"ВЕБМАНХВА" -> "Manhwa" "ВЕБМАНХВА" -> "Manhwa"
"МАНХВА" -> "Manhwa" "МАНХВА" -> "Manhwa"
"МАНЬХВА" -> "Manhua" "МАНЬХВА" -> "Manhua"
"ВЕБМАНЬХВА" -> "Manhua" "ВЕБМАНЬХВА" -> "Manhua"
else -> "Manga" else -> "Manga"
} }
genre = document.select("div.item__full-sideba--header:has(div:containsOwn(Жанри:))").first()?.select("span.item__full-sidebar--description")?.first()!!.select("a").joinToString { it.text() } + ", " + type genre = document.selectFirst("div.item__full-sideba--header:has(div:containsOwn(Жанри:))")?.selectFirst("span.item__full-sidebar--description")!!.select("a").joinToString { it.text() } + ", " + type
} }
} }
// Chapters // Chapters
override fun chapterListSelector() = "div.ltcitems" override fun chapterListSelector() = throw UnsupportedOperationException()
private var previousChapterName: String? = null
private var previousChapterNumber: Float = 0.0f
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
return SChapter.create().apply { throw UnsupportedOperationException()
element.select("a").let { urlElement -> }
private fun parseChapterElements(elements: Elements): List<SChapter> {
var previousChapterName: String? = null
var previousChapterNumber: Float = 0.0f
val dateFormat = DATE_FORMATTER
return elements.map { element ->
SChapter.create().apply {
val urlElement = element.selectFirst("a")!!
setUrlWithoutDomain(urlElement.attr("href")) setUrlWithoutDomain(urlElement.attr("href"))
val chapterName = urlElement.text().substringAfter("НОВЕ").trim() val chapterName = urlElement.text().substringAfter("НОВЕ").trim()
val chapterNumber = urlElement.text().substringAfter("Розділ").substringBefore("-").trim() val chapterNumber = urlElement.text().substringAfter("Розділ").substringBefore("-").trim()
@ -137,31 +146,58 @@ class Mangainua : ParsedHttpSource() {
chapter_number = chapterNumber.toFloat() chapter_number = chapterNumber.toFloat()
previousChapterNumber = chapterNumber.toFloat() previousChapterNumber = chapterNumber.toFloat()
} }
date_upload = dateFormat.parse(element.child(0).ownText())?.time!!
} }
date_upload = parseDate(element.select("div.ltcright:containsOwn(.)").text())
} }
} }
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
return super.chapterListParse(response).reversed() val document = response.asJsoup()
val userHash = document.parseUserHash()
val metaElement = document.selectFirst(Evaluator.Id("linkstocomics"))!!
val body = FormBody.Builder()
.addEncoded("action", "show")
.addEncoded("news_id", metaElement.attr("data-news_id"))
.addEncoded("news_category", metaElement.attr("data-news_category"))
.addEncoded("this_link", metaElement.attr("data-this_link"))
.addEncoded("user_hash", userHash)
.build()
val request = POST("$baseUrl/engine/ajax/controller.php?mod=load_chapters", headers, body)
val chaptersHtml = client.newCall(request).execute().body.string()
val chaptersDocument = Jsoup.parseBodyFragment(chaptersHtml)
return parseChapterElements(chaptersDocument.body().children()).asReversed()
} }
// Pages // Pages
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
return document.select("ul.loadcomicsimages img").mapIndexed { i, element -> val userHash = document.parseUserHash()
Page(i, "", element.attr("abs:data-src")) val newsId = document.selectFirst(Evaluator.Id("comics"))!!.attr("data-news_id")
val url = "$baseUrl/engine/ajax/controller.php?mod=load_chapters_image&news_id=$newsId&action=show&user_hash=$userHash"
val pagesHtml = client.newCall(GET(url, headers)).execute().body.string()
val pagesDocument = Jsoup.parseBodyFragment(pagesHtml)
return pagesDocument.getElementsByTag("img").mapIndexed { index, img ->
Page(index, imageUrl = img.attr("data-src"))
} }
} }
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
private fun parseDate(dateStr: String): Long {
return runCatching { DATE_FORMATTER.parse(dateStr)?.time }
.getOrNull() ?: 0L
}
companion object { companion object {
private val DATE_FORMATTER by lazy { private val DATE_FORMATTER by lazy {
SimpleDateFormat("dd.MM.yyyy", Locale.ENGLISH) SimpleDateFormat("dd.MM.yyyy", Locale.ENGLISH)
} }
private fun Document.parseUserHash(): String {
val start = "site_login_hash = '"
for (element in body().children()) {
if (element.tagName() != "script") continue
val data = element.data()
val leftIndex = data.indexOf(start)
if (leftIndex == -1) continue
val startIndex = leftIndex + start.length
val endIndex = data.indexOf('\'', startIndex)
return data.substring(startIndex, endIndex)
}
throw Exception("Couldn't find user hash")
}
} }
} }