feat(misskon): split chapters into individual pages (#8800)

* feat(misskon): split chapters into individual pages

- Migrate from single-chapter to per-page architecture
- Fix long loading time issues

* fix(misskon): Remove chapter_number configuration
- Drop deprecated chapter_number field setup
This commit is contained in:
marioplus 2025-05-15 23:24:32 +08:00 committed by Draff
parent 314c5e0ed3
commit c44aba3f1a
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
2 changed files with 19 additions and 28 deletions

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'MissKon' extName = 'MissKon'
extClass = '.MissKon' extClass = '.MissKon'
extVersionCode = 1 extVersionCode = 2
isNsfw = true isNsfw = true
} }

View File

@ -13,6 +13,7 @@ import keiyoushi.utils.firstInstance
import keiyoushi.utils.tryParse import keiyoushi.utils.tryParse
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -76,46 +77,36 @@ class MissKon() : SimpleParsedHttpSource() {
return SManga.create().apply { return SManga.create().apply {
title = postInnerEl.select(".post-title").text() title = postInnerEl.select(".post-title").text()
genre = postInnerEl.select(".post-tag > a").joinToString { it.text() } genre = postInnerEl.select(".post-tag > a").joinToString { it.text() }
status = SManga.COMPLETED
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
} }
} }
override fun chapterListSelector() = "html" override fun chapterFromElement(element: Element) = throw UnsupportedOperationException()
override fun chapterListParse(response: Response): List<SChapter> {
override fun chapterFromElement(element: Element): SChapter { val doc = response.asJsoup()
val dateStr = element.selectFirst(".entry img")?.absUrl("data-src") val dateUploadStr = doc.selectFirst(".entry img")?.absUrl("data-src")
?.let { url -> ?.let { url ->
FULL_DATE_REGEX.find(url)?.groupValues?.get(1) FULL_DATE_REGEX.find(url)?.groupValues?.get(1)
?: YEAR_MONTH_REGEX.find(url)?.groupValues?.get(1)?.let { "$it/01" } ?: YEAR_MONTH_REGEX.find(url)?.groupValues?.get(1)?.let { "$it/01" }
} }
val dateUpload = FULL_DATE_FORMAT.tryParse(dateUploadStr)
return SChapter.create().apply { val maxPage = doc.select("div.page-link:first-of-type a.post-page-numbers").last()?.text()?.toInt() ?: 1
chapter_number = 0F val basePageUrl = response.request.url.toString()
setUrlWithoutDomain(element.selectFirst("link[rel=canonical]")!!.absUrl("href")) return (maxPage downTo 1).map { page ->
name = "Gallery" SChapter.create().apply {
date_upload = FULL_DATE_FORMAT.tryParse(dateStr) setUrlWithoutDomain("$basePageUrl/$page")
name = "Page $page"
date_upload = dateUpload
}
} }
} }
// endregion // endregion
// region Pages // region Pages
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
val basePageUrl = document.selectFirst("link[rel=canonical]")!!.absUrl("href") return document.select("div.post-inner > div.entry > p > img")
.mapIndexed { i, imgEl -> Page(i, imageUrl = imgEl.absUrl("data-src")) }
val pages = mutableListOf<Page>()
document.select("div.post-inner div.page-link:nth-child(1) .post-page-numbers")
.forEachIndexed { index, pageEl ->
val doc = when (index) {
0 -> document
else -> {
val url = "$basePageUrl${pageEl.text()}/"
client.newCall(GET(url, headers)).execute().asJsoup()
}
}
doc.select("div.post-inner > div.entry > p > img")
.map { it.absUrl("data-src") }
.forEach { pages.add(Page(pages.size, imageUrl = it)) }
}
return pages
} }
// endregion // endregion