|
|
|
@ -11,6 +11,7 @@
|
|
|
|
import org.koitharu.kotatsu.parsers.model.*
|
|
|
|
import org.koitharu.kotatsu.parsers.model.*
|
|
|
|
import org.koitharu.kotatsu.parsers.util.*
|
|
|
|
import org.koitharu.kotatsu.parsers.util.*
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
|
|
|
|
import org.jsoup.Jsoup
|
|
|
|
import java.util.*
|
|
|
|
import java.util.*
|
|
|
|
|
|
|
|
|
|
|
|
internal abstract class LilianaParser(
|
|
|
|
internal abstract class LilianaParser(
|
|
|
|
@ -36,12 +37,8 @@
|
|
|
|
override val filterCapabilities: MangaListFilterCapabilities
|
|
|
|
override val filterCapabilities: MangaListFilterCapabilities
|
|
|
|
get() = MangaListFilterCapabilities(
|
|
|
|
get() = MangaListFilterCapabilities(
|
|
|
|
isMultipleTagsSupported = true,
|
|
|
|
isMultipleTagsSupported = true,
|
|
|
|
isTagsExclusionSupported = false,
|
|
|
|
|
|
|
|
isSearchSupported = true,
|
|
|
|
isSearchSupported = true,
|
|
|
|
isSearchWithFiltersSupported = true,
|
|
|
|
isSearchWithFiltersSupported = true
|
|
|
|
isYearSupported = false,
|
|
|
|
|
|
|
|
isYearRangeSupported = false,
|
|
|
|
|
|
|
|
isOriginalLocaleSupported = false
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
|
|
|
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
|
|
|
@ -89,7 +86,7 @@
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private fun parseSearchManga(element: Element): Manga {
|
|
|
|
private fun parseSearchManga(element: Element): Manga {
|
|
|
|
val href = element.selectFirst("a")?.attrAsRelativeUrl("href") ?: element.parseFailed("Manga link not found")
|
|
|
|
val href = element.selectFirstOrThrow("a").attrAsRelativeUrl("href")
|
|
|
|
return Manga(
|
|
|
|
return Manga(
|
|
|
|
id = generateUid(href),
|
|
|
|
id = generateUid(href),
|
|
|
|
url = href,
|
|
|
|
url = href,
|
|
|
|
@ -111,10 +108,10 @@
|
|
|
|
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").mapNotNullToSet { 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().trim(),
|
|
|
|
title = a.text().toTitleCase(sourceLocale),
|
|
|
|
source = source,
|
|
|
|
source = source,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
@ -127,7 +124,7 @@
|
|
|
|
else -> null
|
|
|
|
else -> null
|
|
|
|
},
|
|
|
|
},
|
|
|
|
chapters = doc.select("ul > li.chapter").mapChapters { i, element ->
|
|
|
|
chapters = doc.select("ul > li.chapter").mapChapters { i, element ->
|
|
|
|
val href = element.selectFirst("a")?.attrAsRelativeUrl("href") ?: element.parseFailed("Chapter link not found")
|
|
|
|
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(),
|
|
|
|
@ -149,7 +146,7 @@
|
|
|
|
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://")
|
|
|
|
@ -158,34 +155,32 @@
|
|
|
|
append(chapterId)
|
|
|
|
append(chapterId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
val ajaxResponse = webClient.httpGet(ajaxUrl)
|
|
|
|
val responseJson = webClient.httpGet(ajaxUrl).parseJson()
|
|
|
|
val responseJson = JSONObject(ajaxResponse.requireBody().string())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 = org.jsoup.Jsoup.parse(pageListHtml)
|
|
|
|
val pageListDoc = Jsoup.parse(pageListHtml)
|
|
|
|
|
|
|
|
|
|
|
|
return pageListDoc.select("div.separator[data-index]").map { page ->
|
|
|
|
return pageListDoc.select("div.separator[data-index]").mapIndexed { index, page ->
|
|
|
|
val index = page.attr("data-index").toInt()
|
|
|
|
val url = page.selectFirstOrThrow("a").attr("abs:href")
|
|
|
|
val url = page.selectFirst("a")?.attr("abs:href") ?: page.parseFailed("Image url not found")
|
|
|
|
|
|
|
|
MangaPage(
|
|
|
|
MangaPage(
|
|
|
|
id = generateUid(url),
|
|
|
|
id = generateUid(url),
|
|
|
|
url = url,
|
|
|
|
url = url,
|
|
|
|
preview = null,
|
|
|
|
preview = null,
|
|
|
|
source = source,
|
|
|
|
source = source,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}.sortedBy { it.id.toInt() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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").mapNotNullToSet { element ->
|
|
|
|
doc.select("div.advanced-genres > div > .advance-item").mapToSet { element ->
|
|
|
|
MangaTag(
|
|
|
|
MangaTag(
|
|
|
|
key = element.selectFirst("span")?.attr("data-genre") ?: return@mapNotNullToSet null,
|
|
|
|
key = element.selectFirstOrThrow("span[data-genre]").attr("data-genre"),
|
|
|
|
title = element.text().trim(),
|
|
|
|
title = element.text().toTitleCase(sourceLocale),
|
|
|
|
source = source,
|
|
|
|
source = source,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|