[Liliana] Fix chapters order

master
Koitharu 2 years ago
parent 1406165789
commit 0150ede4cb
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -1 +1 @@
total: 1121 total: 1122

@ -1,204 +1,204 @@
package org.koitharu.kotatsu.parsers.site.liliana package org.koitharu.kotatsu.parsers.site.liliana
import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.coroutineScope import org.jsoup.Jsoup
import org.json.JSONObject import org.jsoup.nodes.Element
import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.jsoup.nodes.Element import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.model.* import java.util.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat internal abstract class LilianaParser(
import org.jsoup.Jsoup context: MangaLoaderContext,
import java.util.* source: MangaParserSource,
domain: String,
internal abstract class LilianaParser( pageSize: Int = 24,
context: MangaLoaderContext, ) : PagedMangaParser(context, source, pageSize) {
source: MangaParserSource,
domain: String, override val configKeyDomain = ConfigKey.Domain(domain)
pageSize: Int = 24
) : PagedMangaParser(context, source, pageSize) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys)
override val configKeyDomain = ConfigKey.Domain(domain) keys.add(userAgentKey)
}
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) override val availableSortOrders: Set<SortOrder> = EnumSet.of(
keys.add(userAgentKey) SortOrder.UPDATED,
} SortOrder.POPULARITY,
SortOrder.ALPHABETICAL,
override val availableSortOrders: Set<SortOrder> = EnumSet.of( SortOrder.NEWEST,
SortOrder.UPDATED, SortOrder.RATING_ASC,
SortOrder.POPULARITY, )
SortOrder.ALPHABETICAL,
SortOrder.NEWEST, override val filterCapabilities: MangaListFilterCapabilities
SortOrder.RATING_ASC get() = MangaListFilterCapabilities(
) isMultipleTagsSupported = true,
isSearchSupported = true,
override val filterCapabilities: MangaListFilterCapabilities isSearchWithFiltersSupported = true,
get() = MangaListFilterCapabilities( )
isMultipleTagsSupported = true,
isSearchSupported = true, override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
isSearchWithFiltersSupported = true val url = buildString {
) append("https://")
append(domain)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { when {
val url = buildString { !filter.query.isNullOrEmpty() -> {
append("https://") append("/search")
append(domain) append("?keyword=")
when { append(filter.query.urlEncoded())
!filter.query.isNullOrEmpty() -> { }
append("/search")
append("?keyword=") else -> {
append(filter.query.urlEncoded()) append("/filter")
} }
else -> { }
append("/filter") append("/")
} append(page)
} append("/")
append("/")
append(page) when (order) {
append("/") SortOrder.UPDATED -> append("?sort=latest-updated")
SortOrder.POPULARITY -> append("?sort=views")
when (order) { SortOrder.ALPHABETICAL -> append("?sort=az")
SortOrder.UPDATED -> append("?sort=latest-updated") SortOrder.NEWEST -> append("?sort=new")
SortOrder.POPULARITY -> append("?sort=views") SortOrder.RATING_ASC -> append("?sort=score")
SortOrder.ALPHABETICAL -> append("?sort=az") else -> append("?sort=default")
SortOrder.NEWEST -> append("?sort=new") }
SortOrder.RATING_ASC -> append("?sort=score")
else -> append("?sort=default") filter.tags.forEach { tag ->
} append("&genres=")
append(tag.key)
filter.tags.forEach { tag -> }
append("&genres=")
append(tag.key) if (filter.states.isNotEmpty()) {
} append("&status=")
append(
if (filter.states.isNotEmpty()) { when (filter.states.first()) {
append("&status=") MangaState.ONGOING -> "on-going"
append(when (filter.states.first()) { MangaState.FINISHED -> "completed"
MangaState.ONGOING -> "on-going" MangaState.PAUSED -> "on-hold"
MangaState.FINISHED -> "completed" MangaState.ABANDONED -> "canceled"
MangaState.PAUSED -> "on-hold" else -> "all"
MangaState.ABANDONED -> "canceled" },
else -> "all" )
}) }
} }
}
val doc = webClient.httpGet(url).parseHtml()
val doc = webClient.httpGet(url).parseHtml() return doc.select("div#main div.grid > div").map { parseSearchManga(it) }
return doc.select("div#main div.grid > div").map { parseSearchManga(it) } }
}
private fun parseSearchManga(element: Element): Manga {
private fun parseSearchManga(element: Element): Manga { val href = element.selectFirstOrThrow("a").attrAsRelativeUrl("href")
val href = element.selectFirstOrThrow("a").attrAsRelativeUrl("href") return Manga(
return Manga( id = generateUid(href),
id = generateUid(href), url = href,
url = href, publicUrl = href.toAbsoluteUrl(domain),
publicUrl = href.toAbsoluteUrl(domain), coverUrl = element.selectFirst("img")?.src().orEmpty(),
coverUrl = element.selectFirst("img")?.src().orEmpty(), title = element.selectFirst(".text-center a")?.text().orEmpty(),
title = element.selectFirst(".text-center a")?.text().orEmpty(), altTitle = null,
altTitle = null, rating = RATING_UNKNOWN,
rating = RATING_UNKNOWN, tags = emptySet(),
tags = emptySet(), author = null,
author = null, state = null,
state = null, source = source,
source = source, isNsfw = false,
isNsfw = false, )
) }
}
override suspend fun getDetails(manga: Manga): Manga {
override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() return manga.copy(
return manga.copy( description = doc.selectFirst("div#syn-target")?.text(),
description = doc.selectFirst("div#syn-target")?.text(), largeCoverUrl = doc.selectFirst(".a1 > figure img")?.src(),
largeCoverUrl = doc.selectFirst(".a1 > figure img")?.src(), tags = doc.select(".a2 div > a[rel='tag'].label").mapToSet { a ->
tags = doc.select(".a2 div > a[rel='tag'].label").mapToSet { a -> MangaTag(
MangaTag( key = a.attr("href").substringAfterLast('/'),
key = a.attr("href").substringAfterLast('/'), title = a.text().toTitleCase(sourceLocale),
title = a.text().toTitleCase(sourceLocale), source = source,
source = source, )
) },
}, author = doc.selectFirst("div.y6x11p i.fas.fa-user + span.dt")?.text()?.takeUnless {
author = doc.selectFirst("div.y6x11p i.fas.fa-user + span.dt")?.text()?.takeUnless { it.equals("updating", true)
it.equals("updating", true) },
}, state = when (doc.selectFirst("div.y6x11p i.fas.fa-rss + span.dt")?.text()?.lowercase()) {
state = when (doc.selectFirst("div.y6x11p i.fas.fa-rss + span.dt")?.text()?.lowercase()) { "on-going", "đang tiến hành", "進行中" -> MangaState.ONGOING
"on-going", "đang tiến hành", "進行中" -> MangaState.ONGOING "completed", "hoàn thành", "完了" -> MangaState.FINISHED
"completed", "hoàn thành", "完了" -> MangaState.FINISHED "on-hold", "tạm dừng", "一時停止" -> MangaState.PAUSED
"on-hold", "tạm dừng", "一時停止" -> MangaState.PAUSED "canceled", "đã huỷ bỏ", "キャンセル" -> MangaState.ABANDONED
"canceled", "đã huỷ bỏ", "キャンセル" -> MangaState.ABANDONED else -> null
else -> null },
}, chapters = doc.select("ul > li.chapter").mapChapters(reversed = true) { i, element ->
chapters = doc.select("ul > li.chapter").mapChapters { i, element -> val href = element.selectFirstOrThrow("a").attrAsRelativeUrl("href")
val href = element.selectFirstOrThrow("a").attrAsRelativeUrl("href") MangaChapter(
MangaChapter( id = generateUid(href),
id = generateUid(href), name = element.selectFirst("a")?.text().orEmpty(),
name = element.selectFirst("a")?.text().orEmpty(), number = i + 1f,
number = doc.select("ul > li.chapter").size - i.toFloat(), url = href,
url = href, scanlator = null,
scanlator = null, uploadDate = element.selectFirst("time[datetime]")?.attr("datetime")?.toLongOrNull()?.times(1000)
uploadDate = element.selectFirst("time[datetime]")?.attr("datetime")?.toLongOrNull()?.times(1000) ?: 0L, ?: 0L,
branch = null, branch = null,
source = source, source = source,
volume = 0 volume = 0,
) )
} },
) )
} }
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain) val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml() val doc = webClient.httpGet(fullUrl).parseHtml()
val script = doc.selectFirst("script:containsData(const CHAPTER_ID)")?.data() val script = doc.selectFirst("script:containsData(const CHAPTER_ID)")?.data()
?: throw Exception("Failed to get chapter id") ?: throw Exception("Failed to get chapter id")
val chapterId = script.substringAfter("const CHAPTER_ID = ").substringBefore(';') val chapterId = script.substringAfter("const CHAPTER_ID = ").substringBefore(';')
val ajaxUrl = buildString { val ajaxUrl = buildString {
append("https://") append("https://")
append(domain) append(domain)
append("/ajax/image/list/chap/") append("/ajax/image/list/chap/")
append(chapterId) append(chapterId)
} }
val responseJson = webClient.httpGet(ajaxUrl).parseJson() val responseJson = webClient.httpGet(ajaxUrl).parseJson()
if (!responseJson.optBoolean("status", false)) { if (!responseJson.optBoolean("status", false)) {
throw Exception(responseJson.optString("msg")) throw Exception(responseJson.optString("msg"))
} }
val pageListHtml = responseJson.getString("html") val pageListHtml = responseJson.getString("html")
val pageListDoc = Jsoup.parse(pageListHtml) val pageListDoc = Jsoup.parse(pageListHtml)
return pageListDoc.select("div.iv-card").mapIndexed { index, div -> return pageListDoc.select("div.iv-card").mapIndexed { index, div ->
val img = div.selectFirst("img") val img = div.selectFirst("img")
val url = img?.attr("data-src") ?: img?.attr("src") ?: throw Exception("Failed to get image url") val url = img?.attr("data-src") ?: img?.attr("src") ?: throw Exception("Failed to get image url")
MangaPage( MangaPage(
id = generateUid(url), id = generateUid(url),
url = url, url = url,
preview = null, preview = null,
source = source, source = source,
) )
} }
} }
protected open suspend fun getAvailableTags(): Set<MangaTag> = coroutineScope { protected open suspend fun getAvailableTags(): Set<MangaTag> = coroutineScope {
val doc = webClient.httpGet("https://$domain/filter").parseHtml() val doc = webClient.httpGet("https://$domain/filter").parseHtml()
doc.select("div.advanced-genres > div > .advance-item").mapToSet { element -> doc.select("div.advanced-genres > div > .advance-item").mapToSet { element ->
MangaTag( MangaTag(
key = element.selectFirstOrThrow("span[data-genre]").attr("data-genre"), key = element.selectFirstOrThrow("span[data-genre]").attr("data-genre"),
title = element.text().toTitleCase(sourceLocale), title = element.text().toTitleCase(sourceLocale),
source = source, source = source,
) )
} }
} }
override suspend fun getFilterOptions(): MangaListFilterOptions = MangaListFilterOptions( override suspend fun getFilterOptions(): MangaListFilterOptions = MangaListFilterOptions(
availableTags = getAvailableTags(), availableTags = getAvailableTags(),
availableStates = setOf(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED) availableStates = setOf(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
) )
} }

Loading…
Cancel
Save