[KdtScan] Update domain + Fixes (#2050)

Co-authored-by: Draken <131387159+dragonx943@users.noreply.github.com>
Co-authored-by: dragonx943 <premieregirl26@gmail.com>
Naga 9 months ago committed by GitHub
parent 8bc7480d84
commit b5512e7574
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,267 @@
package org.koitharu.kotatsu.parsers.site.en
import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.core.PagedMangaParser
import org.koitharu.kotatsu.parsers.model.ContentRating
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaListFilterOptions
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrl
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.mapChapters
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.oneOrThrowIfMany
import org.koitharu.kotatsu.parsers.util.parseFailed
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
import org.koitharu.kotatsu.parsers.util.src
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toTitleCase
import org.koitharu.kotatsu.parsers.util.urlEncoded
import java.text.SimpleDateFormat
import java.util.EnumSet
@MangaSourceParser("KDTSCANS", "KdtScans", "en")
internal class KdtScans(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.KDTSCANS, 20) {
override val configKeyDomain = ConfigKey.Domain("www.silentquill.net")
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.RELEVANCE,
SortOrder.UPDATED,
SortOrder.POPULARITY,
SortOrder.NEWEST,
SortOrder.ALPHABETICAL,
SortOrder.ALPHABETICAL_DESC,
)
override val filterCapabilities = MangaListFilterCapabilities(
isSearchSupported = true,
isMultipleTagsSupported = true,
isTagsExclusionSupported = true,
)
override suspend fun getFilterOptions(): MangaListFilterOptions {
return MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(
MangaState.ONGOING,
MangaState.FINISHED,
MangaState.PAUSED,
),
availableContentTypes = EnumSet.of(
ContentType.MANGA,
ContentType.MANHWA,
ContentType.MANHUA,
ContentType.COMICS,
ContentType.NOVEL,
),
)
}
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString {
append("https://$domain/manga/?page=${page}")
filter.query?.let {
append("&s=${it.urlEncoded()}")
}
val sortValue = when (order) {
SortOrder.UPDATED -> "update"
SortOrder.POPULARITY -> "popular"
SortOrder.NEWEST -> "latest"
SortOrder.ALPHABETICAL -> "title"
SortOrder.ALPHABETICAL_DESC -> "titlereverse"
else -> "" // Default/Relevance
}
if (sortValue.isNotEmpty()) {
append("&order=$sortValue")
}
filter.tags.forEach { tag ->
append("&genre[]=${tag.key}")
}
filter.tagsExclude.forEach { tag ->
append("&genre[]=-${tag.key}")
}
filter.states.oneOrThrowIfMany().let { state ->
val stateValue = when (state) {
MangaState.ONGOING -> "ongoing"
MangaState.FINISHED -> "completed"
MangaState.PAUSED -> "hiatus"
else -> ""
}
if (stateValue.isNotEmpty()) {
append("&status=$stateValue")
}
}
filter.types.oneOrThrowIfMany()?.let { type ->
val typeValue = when (type) {
ContentType.MANGA -> "manga"
ContentType.MANHWA -> "manhwa"
ContentType.MANHUA -> "manhua"
ContentType.COMICS -> "comic"
ContentType.NOVEL -> "novel"
else -> ""
}
if (typeValue.isNotEmpty()) {
append("&type=$typeValue")
}
}
}
val doc = webClient.httpGet(url).parseHtml()
return parseMangaList(doc)
}
private fun parseMangaList(doc: Document): List<Manga> {
val elements = doc.select("div.listupd div.bs")
if (elements.isEmpty()) {
return emptyList()
}
return elements.map { div ->
val a = div.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href")
val img = div.selectFirst("img")
val title = a.attr("title").ifEmpty {
div.selectFirst(".tt")?.text().orEmpty()
}
val rating = div.selectFirst(".numscore")?.text()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN
Manga(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = img?.src(),
title = title,
altTitles = emptySet(),
rating = rating,
tags = emptySet(),
authors = emptySet(),
state = parseStatus(div.selectFirst(".status")?.text().orEmpty()),
source = source,
contentRating = if (isNsfwSource) ContentRating.ADULT else null,
)
}
}
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val infoElement =
doc.selectFirst(".main-info, .postbody") ?: doc.parseFailed("Cannot find manga details element")
val statusText =
infoElement.selectFirst(".tsinfo .imptdt:contains(Status) i, .infotable tr:contains(Status) td:last-child")
?.text()
val chapters = doc.select("#chapterlist li").mapChapters(reversed = true) { i, li ->
val a = li.selectFirstOrThrow("a")
val href = a.attrAsRelativeUrl("href")
MangaChapter(
id = generateUid(href),
url = href,
title = a.selectFirst(".chapternum")?.text() ?: a.text(),
number = i + 1f,
uploadDate = parseChapterDate(li.selectFirst(".chapterdate")?.text()),
source = source,
volume = 0,
scanlator = null,
branch = null,
)
}
val genres = infoElement.select(".mgen a, .seriestugenre a").mapToSet { a ->
MangaTag(
key = a.attr("href").substringAfterLast("/").removeSuffix("/"),
title = a.text(),
source = source,
)
}
val typeTag = infoElement.selectFirst(".tsinfo .imptdt:contains(Type) a")?.text()?.let { typeText ->
MangaTag(
key = typeText.lowercase(),
title = typeText.trim(),
source = source,
)
}
val allTags = genres.toMutableSet()
typeTag?.let { allTags.add(it) }
return manga.copy(
title = infoElement.selectFirst("h1.entry-title")?.text() ?: manga.title,
authors = infoElement.select(".tsinfo .imptdt:contains(Author) i, .infotable tr:contains(Author) td:last-child")
.mapToSet { it.text() },
description = infoElement.select(".desc, .entry-content[itemprop=description]")
.joinToString("\n") { it.text() },
state = parseStatus(statusText.orEmpty()),
tags = allTags,
chapters = chapters,
)
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
return doc.select("#readerarea img").map { img ->
val url = img.attr("data-src").ifEmpty { img.src().orEmpty() }
MangaPage(
id = generateUid(url),
url = url,
preview = null,
source = source,
)
}
}
private fun parseStatus(status: String): MangaState? {
return when {
status.contains("ongoing", ignoreCase = true) -> MangaState.ONGOING
status.contains("completed", ignoreCase = true) -> MangaState.FINISHED
status.contains("hiatus", ignoreCase = true) -> MangaState.PAUSED
status.contains("dropped", ignoreCase = true) -> MangaState.ABANDONED
status.contains("canceled", ignoreCase = true) -> MangaState.ABANDONED
else -> null
}
}
private fun parseChapterDate(date: String?): Long {
return try {
SimpleDateFormat("MMMM dd, yyyy", sourceLocale).parse(date?.trim()).time
} catch (_: Exception) {
0L
}
}
private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/manga/").parseHtml()
return doc.select("ul.genrez li").mapNotNullToSet { li ->
val key = li.selectFirst("input").attr("value") ?: return@mapNotNullToSet null
val title = li.selectFirst("label").text().toTitleCase()
MangaTag(
key = key,
title = title,
source = source,
)
}
}
}

@ -1,13 +0,0 @@
package org.koitharu.kotatsu.parsers.site.madara.all
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.*
@MangaSourceParser("KDTSCANS", "KdtScans", "")
internal class KdtScans(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.KDTSCANS, "kdtscans.com", 10) {
override val sourceLocale: Locale = Locale("es")
}
Loading…
Cancel
Save