MCCMS: add filters, fix popular and latest manga, update URL (#12171)

This commit is contained in:
kasperskier 2022-06-12 22:17:49 +08:00 committed by GitHub
parent cff72ef4ce
commit e0b4fcbce8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 19 deletions

View File

@ -1,8 +1,13 @@
package eu.kanade.tachiyomi.extension.zh.haoman6_glens
import eu.kanade.tachiyomi.multisrc.mccms.MCCMS
import eu.kanade.tachiyomi.network.GET
import okhttp3.Response
class Haoman6_glens : MCCMS("好漫6 (g-lens)", "https://www.g-lens.com") {
override fun transformTitle(title: String) = title.removeSuffix("_").removeSuffix("-")
override val lazyLoadImageAttr = "pc-ec"
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/category/order/addtime", headers)
override fun latestUpdatesParse(response: Response) = searchMangaParse(response)
}

View File

@ -2,13 +2,12 @@ package eu.kanade.tachiyomi.extension.zh.haoman8
import eu.kanade.tachiyomi.multisrc.mccms.MCCMS
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.FilterList
class Haoman8 : MCCMS("好漫8", "https://caiji.haoman8.com") {
// Search: 此站点nginx配置有问题只能用以下格式搜索第一页
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
override fun textSearchRequest(page: Int, query: String) =
GET("$baseUrl/index.php/search?key=$query", headers)
override fun searchMangaNextPageSelector(): String? = null

View File

@ -1,12 +1,13 @@
package eu.kanade.tachiyomi.extension.zh.haomanwu
import eu.kanade.tachiyomi.multisrc.mccms.MCCMS
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SManga
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
class Haomanwu : MCCMS("好漫屋", "https://app2.haomanwu.com") {
class Haomanwu : MCCMS("好漫屋", "https://app2.haoman6.com") {
// Search
@ -24,4 +25,8 @@ class Haomanwu : MCCMS("好漫屋", "https://app2.haomanwu.com") {
}
return pages
}
// 分类页面缺失
override fun fetchCategories() = Unit
override fun getFilterList() = FilterList(emptyList())
}

View File

@ -1,14 +1,19 @@
package eu.kanade.tachiyomi.multisrc.mccms
import android.util.Log
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import kotlin.concurrent.thread
/**
* 漫城CMS http://mccms.cn/
@ -20,19 +25,15 @@ abstract class MCCMS(
) : ParsedHttpSource() {
override val supportsLatest: Boolean = true
protected open val nextPageSelector = "div#Pagination a.next"
protected open val comicItemSelector = "div.common-comic-item"
protected open val comicItemTitleSelector = "p.comic__title > a"
protected open fun transformTitle(title: String) = title
// Popular
override fun popularMangaRequest(page: Int) = GET("$baseUrl/category/order/hits/page/$page", headers)
override fun popularMangaNextPageSelector() = nextPageSelector
override fun popularMangaSelector() = comicItemSelector
override fun popularMangaRequest(page: Int) = GET("$baseUrl/custom/hot", headers)
override fun popularMangaNextPageSelector(): String? = null
override fun popularMangaSelector() = ".top-list__box-item"
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
val titleElement = element.select(comicItemTitleSelector)
val titleElement = element.select("p.comic__title > a")
title = transformTitle(titleElement.text().trim())
setUrlWithoutDomain(titleElement.attr("abs:href"))
thumbnail_url = element.select("img").attr("abs:data-original")
@ -40,20 +41,48 @@ abstract class MCCMS(
// Latest
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/category/order/addtime/page/$page", headers)
override fun latestUpdatesNextPageSelector() = nextPageSelector
override fun latestUpdatesSelector() = comicItemSelector
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/custom/update", headers)
override fun latestUpdatesNextPageSelector(): String? = null
override fun latestUpdatesSelector() = "div.common-comic-item"
override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element)
// Search
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
protected open fun textSearchRequest(page: Int, query: String) =
GET("$baseUrl/search/$query/$page", headers)
override fun searchMangaNextPageSelector(): String? = nextPageSelector
override fun searchMangaSelector() = comicItemSelector
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
if (query.isNotBlank()) {
textSearchRequest(page, query)
} else {
val categories = filters.filterIsInstance<UriPartFilter>()
.map { it.toUriPart() }.filter { it.isNotEmpty() }.joinToString("/")
GET("$baseUrl/category/$categories/page/$page", headers)
}
override fun searchMangaNextPageSelector(): String? = "" // empty string means default pagination
override fun searchMangaSelector() = latestUpdatesSelector()
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
override fun searchMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val isTextSearch = document.location().contains("search")
val mangas = if (isTextSearch) {
document.select(searchMangaSelector()).map { searchMangaFromElement(it) }
} else {
document.select(latestUpdatesSelector()).map { popularMangaFromElement(it) }
}
val hasNextPage = if (isTextSearch && searchMangaNextPageSelector() != "") {
searchMangaNextPageSelector()?.let { document.selectFirst(it) } != null
} else { // default pagination
val buttons = document.select("#Pagination a")
val count = buttons.size
// Next page != Last page
buttons[count - 1].attr("href") != buttons[count - 2].attr("href")
}
return MangasPage(mangas, hasNextPage)
}
// Details
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
@ -83,4 +112,56 @@ abstract class MCCMS(
.mapIndexed { i, el -> Page(i, "", el.attr("abs:$lazyLoadImageAttr")) }
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used.")
protected class UriPartFilter(name: String, values: Array<String>, private val uriParts: Array<String>) :
Filter.Select<String>(name, values) {
fun toUriPart(): String = uriParts[state]
}
protected data class Category(val name: String, val values: Array<String>, val uriParts: Array<String>) {
fun toUriPartFilter() = UriPartFilter(name, values, uriParts)
}
private val sortCategory = Category("排序", arrayOf("热门人气", "更新时间"), arrayOf("order/hits", "order/addtime"))
private lateinit var categories: List<Category>
private var isFetchingCategories = false
private fun tryFetchCategories() {
if (isFetchingCategories) return
isFetchingCategories = true
thread {
try {
fetchCategories()
} catch (e: Exception) {
Log.e("MCCMS/$name", "Failed to fetch categories ($e)")
} finally {
isFetchingCategories = false
}
}
}
protected open fun fetchCategories() {
val document = client.newCall(GET("$baseUrl/category/", headers)).execute().asJsoup()
categories = document.select("div.cate-col").map { element ->
val name = element.select("p.cate-title").text().removeSuffix("")
val tags = element.select("li.cate-item > a")
val values = tags.map { it.text() }.toTypedArray()
val uriParts = tags.map { it.attr("href").removePrefix("/category/") }.toTypedArray()
Category(name, values, uriParts)
}
}
override fun getFilterList(): FilterList {
val result = mutableListOf(
Filter.Header("如果使用文本搜索,将会忽略分类筛选"),
sortCategory.toUriPartFilter(),
)
if (::categories.isInitialized) {
categories.forEach { result.add(it.toUriPartFilter()) }
} else {
tryFetchCategories()
result.add(Filter.Header("其他分类正在获取,请返回上一页后重试"))
}
return FilterList(result)
}
}

View File

@ -6,14 +6,14 @@ import generator.ThemeSourceGenerator
class MCCMSGenerator : ThemeSourceGenerator {
override val themeClass = "MCCMS"
override val themePkg = "mccms"
override val baseVersionCode = 1
override val baseVersionCode = 2
override val sources = listOf(
SingleLang(
name = "Haoman6", baseUrl = "https://www.haoman6.com", lang = "zh",
className = "Haoman6", sourceName = "好漫6", overrideVersionCode = 2
),
SingleLang(
name = "Haomanwu", baseUrl = "https://app2.haomanwu.com", lang = "zh",
name = "Haomanwu", baseUrl = "https://app2.haoman6.com", lang = "zh",
className = "Haomanwu", sourceName = "好漫屋", overrideVersionCode = 3
),
SingleLang(