From 7de9719d0a78464affd6decb53534d8ae3895750 Mon Sep 17 00:00:00 2001 From: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Date: Fri, 24 Jun 2022 17:15:54 +0800 Subject: [PATCH] Gufengmh: prefer PC chapter list page and SinMH cleanups (#12290) --- .../overrides/sinmh/gufengmh/src/Gufengmh.kt | 42 ++++++++++++++++++- multisrc/overrides/sinmh/imitui/src/Imitui.kt | 17 ++++---- .../sinmh/wuqimanga/src/WuqiManga.kt | 17 ++++---- .../kanade/tachiyomi/multisrc/sinmh/SinMH.kt | 12 ++++-- .../multisrc/sinmh/SinMHGenerator.kt | 2 +- 5 files changed, 67 insertions(+), 23 deletions(-) diff --git a/multisrc/overrides/sinmh/gufengmh/src/Gufengmh.kt b/multisrc/overrides/sinmh/gufengmh/src/Gufengmh.kt index 4eaf4fb24..1955119cf 100644 --- a/multisrc/overrides/sinmh/gufengmh/src/Gufengmh.kt +++ b/multisrc/overrides/sinmh/gufengmh/src/Gufengmh.kt @@ -1,10 +1,48 @@ package eu.kanade.tachiyomi.extension.zh.gufengmh import eu.kanade.tachiyomi.multisrc.sinmh.SinMH +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import org.jsoup.nodes.Document +import rx.Observable +import rx.Single class Gufengmh : SinMH("古风漫画网", "https://www.gufengmh9.com") { - override val dateSelector = ".pic_zi:nth-of-type(4) > dd" + override fun mangaDetailsParse(document: Document): SManga = + super.mangaDetailsParse(document).apply { + if (status == SManga.COMPLETED) return@apply + val firstChapter = document.selectFirst(".chapter-body li > a") ?: return@apply + if (firstChapter.attr("href").startsWith("javascript")) + status = SManga.LICENSED + } - override fun chapterListSelector() = ".list li > a" + override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = + Single.create<List<SChapter>> { subscriber -> + val pcResponse = client.newCall(GET(baseUrl + manga.url, headers)).execute() + val pcResult = chapterListParse(pcResponse, ".chapter-body li > a", "span.sj") + if (pcResult.none { it.url.isEmpty() }) return@create subscriber.onSuccess(pcResult) + // Example: https://www.gufengmh9.com/manhua/niaoling/ + val mobileResponse = client.newCall(GET(mobileUrl + manga.url, headers)).execute() + val mobileResult = chapterListParse(mobileResponse, ".list li > a", ".pic_zi:nth-of-type(4) > dd") + val pcAscending = pcResult.asReversed() + val mobileAscending = mobileResult.asReversed() + for ((pcChapter, mobileChapter) in pcAscending zip mobileAscending) { + if (pcChapter.name != mobileChapter.name) return@create subscriber.onSuccess(mobileResult) + pcChapter.url = mobileChapter.url + } + pcAscending.forEachIndexed { i, chapter -> + if (chapter.url.isNotEmpty()) return@forEachIndexed + if (i == 0) return@create subscriber.onSuccess(mobileResult) + val prevUrl = pcAscending[i - 1].url + val response = client.newCall(GET(baseUrl + prevUrl, headers)).execute() + chapter.url = buildString { + append(prevUrl, 0, prevUrl.lastIndexOf('/') + 1) + append(ProgressiveParser(response.body!!.string()).substringBetween("""nextChapterData = {"id":""", ",")) + append(".html") + } + } + subscriber.onSuccess(pcResult) + }.toObservable() } diff --git a/multisrc/overrides/sinmh/imitui/src/Imitui.kt b/multisrc/overrides/sinmh/imitui/src/Imitui.kt index 4833bbf31..9e7302051 100644 --- a/multisrc/overrides/sinmh/imitui/src/Imitui.kt +++ b/multisrc/overrides/sinmh/imitui/src/Imitui.kt @@ -2,22 +2,25 @@ package eu.kanade.tachiyomi.extension.zh.imitui import eu.kanade.tachiyomi.multisrc.sinmh.SinMH import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.util.asJsoup import org.jsoup.nodes.Document import rx.Observable +import rx.Single class Imitui : SinMH("爱米推漫画", "https://www.imitui.com") { + override fun chapterListSelector() = ".chapter-body li > a:not([href^=/comic/app/])" + override fun fetchPageList(chapter: SChapter): Observable<List<Page>> = - client.newCall(GET(baseUrl + chapter.url, headers)).asObservableSuccess().map { - val pcResult = pageListParse(it) - if (pcResult.isNotEmpty()) return@map pcResult - val response = client.newCall(GET(mobileUrl + chapter.url, headers)).execute() - mobilePageListParse(response.asJsoup()) - } + Single.create<List<Page>> { + val pcResponse = client.newCall(GET(baseUrl + chapter.url, headers)).execute() + val pcResult = pageListParse(pcResponse.asJsoup()) + if (pcResult.isNotEmpty()) return@create it.onSuccess(pcResult) + val mobileResponse = client.newCall(GET(mobileUrl + chapter.url, headers)).execute() + it.onSuccess(mobilePageListParse(mobileResponse.asJsoup())) + }.toObservable() private fun mobilePageListParse(document: Document): List<Page> { val pageCount = document.select("div.image-content > p").text().removePrefix("1/").toInt() diff --git a/multisrc/overrides/sinmh/wuqimanga/src/WuqiManga.kt b/multisrc/overrides/sinmh/wuqimanga/src/WuqiManga.kt index aa9a9c545..c1840a582 100644 --- a/multisrc/overrides/sinmh/wuqimanga/src/WuqiManga.kt +++ b/multisrc/overrides/sinmh/wuqimanga/src/WuqiManga.kt @@ -52,7 +52,7 @@ class WuqiManga : SinMH("57漫画", "http://www.wuqimh.net") { override val dateSelector = ".cont-list dt:contains(更新于) + dd" override val imageHost: String by lazy { - client.newCall(GET("$baseUrl/templates/wuqi/default/scripts/configs.js", headers)).execute().use { + client.newCall(GET("$baseUrl/templates/wuqi/default/scripts/configs.js", headers)).execute().let { Regex("""\['(.+?)']""").find(it.body!!.string())!!.groupValues[1].run { "http://$this" } } } @@ -73,15 +73,14 @@ class WuqiManga : SinMH("57漫画", "http://www.wuqimh.net") { return@replace if (key < size) dictionary[key] else this } }.removeSurrounding("'").split("','") - return unpacked.filterNot { it.endsWith("/ManHuaKu/222.jpg") }.mapIndexed { i, image -> - val imageUrl = if (image.startsWith("http")) image else imageHost + image - Page(i, imageUrl = imageUrl) - }.also { list -> - if (list.isEmpty()) return emptyList() - client.newCall(GET(list[0].imageUrl!!, headers)).execute().use { - if (!it.isSuccessful) throw Exception("该章节的图片加载出错:${it.code}") - } + val list = unpacked.filterNot { it.endsWith("/ManHuaKu/222.jpg") }.map { image -> + if (image.startsWith("http")) image else imageHost + image } + if (list.isEmpty()) return emptyList() + client.newCall(GET(list[0], headers)).execute().apply { close() }.also { + if (!it.isSuccessful) throw Exception("该章节的图片加载出错:${it.code}") + } + return list.mapIndexed { i, imageUrl -> Page(i, imageUrl = imageUrl) } } override fun parseCategories(document: Document) { diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMH.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMH.kt index 48aa05893..18838601f 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMH.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMH.kt @@ -151,8 +151,12 @@ abstract class SinMH( protected open fun List<SChapter>.sortedDescending() = this.asReversed() override fun chapterListParse(response: Response): List<SChapter> { + return chapterListParse(response, chapterListSelector(), dateSelector) + } + + protected fun chapterListParse(response: Response, listSelector: String, dateSelector: String): List<SChapter> { val document = response.asJsoup() - return document.select(chapterListSelector()).map { chapterFromElement(it) }.sortedDescending().apply { + return document.select(listSelector).map { chapterFromElement(it) }.sortedDescending().apply { if (isNewDateLogic && this.isNotEmpty()) { val date = document.selectFirst(dateSelector).textNodes().last().text() this[0].date_upload = DATE_FORMAT.parse(date)?.time ?: 0L @@ -160,9 +164,9 @@ abstract class SinMH( } } - override fun chapterListSelector() = ".chapter-body li > a:not([href^=/comic/app/])" + override fun chapterListSelector() = ".chapter-body li > a" override fun chapterFromElement(element: Element) = SChapter.create().apply { - setUrlWithoutDomain(element.attr("href")) + runCatching { setUrlWithoutDomain(element.attr("href")) }.onFailure { url = "" } val children = element.children() name = if (children.isEmpty()) element.text() else children[0].text() } @@ -172,7 +176,7 @@ abstract class SinMH( override fun pageListRequest(chapter: SChapter) = GET(mobileUrl + chapter.url, headers) protected open val imageHost: String by lazy { - client.newCall(GET("$baseUrl/js/config.js", headers)).execute().use { + client.newCall(GET("$baseUrl/js/config.js", headers)).execute().let { Regex("""resHost:.+?"domain":\["(.+?)"""").find(it.body!!.string())!! .groupValues[1].substringAfter(':').run { "https:$this" } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMHGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMHGenerator.kt index ea0bface2..fad6dfc4a 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMHGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/sinmh/SinMHGenerator.kt @@ -10,7 +10,7 @@ class SinMHGenerator : ThemeSourceGenerator { override val sources = listOf( SingleLang( name = "Gufeng Manhua", baseUrl = "https://www.gufengmh9.com", lang = "zh", - className = "Gufengmh", sourceName = "古风漫画网", overrideVersionCode = 5 + className = "Gufengmh", sourceName = "古风漫画网", overrideVersionCode = 6 ), SingleLang( name = "Imitui Manhua", baseUrl = "https://www.imitui.com", lang = "zh",