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