Gufengmh: prefer PC chapter list page and SinMH cleanups (#12290)

This commit is contained in:
stevenyomi 2022-06-24 17:15:54 +08:00 committed by GitHub
parent afb387df25
commit 7de9719d0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 23 deletions

View File

@ -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()
}

View File

@ -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()

View File

@ -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) {

View File

@ -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" }
}

View File

@ -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",