MCCMS: add filters, fix popular and latest manga, update URL (#12171)
This commit is contained in:
parent
cff72ef4ce
commit
e0b4fcbce8
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in New Issue