[MadaraParser] auto fix url manga on

fix query ( withoutAjax
[MangaPark] fix close #1152
close #1145
[AdultWebtoon] fix close #1139
[ComicExtra] change type close #1130
[liliana] fix and add ManhuaPlusorg, Raw1001, MangaSect, MangaKoma01, ManhuaGold
master
devi 2 years ago
parent 3e102e9d69
commit 72564f5449

@ -1 +1 @@
total: 1122 total: 1127

@ -82,6 +82,7 @@ public class Manga(
@InternalParsersApi @InternalParsersApi
public fun copy( public fun copy(
url: String = this.url,
title: String = this.title, title: String = this.title,
altTitle: String? = this.altTitle, altTitle: String? = this.altTitle,
publicUrl: String = this.publicUrl, publicUrl: String = this.publicUrl,

@ -236,18 +236,24 @@ internal class MangaPark(context: MangaLoaderContext) :
val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0 val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0
val cal = Calendar.getInstance() val cal = Calendar.getInstance()
return when { return when {
WordSet("second").anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis WordSet("second")
WordSet("minute", "minutes", "mins", "min").anyWordIn(date) -> cal.apply { .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
add(
Calendar.MINUTE, WordSet("minute", "minutes", "mins", "min")
-number, .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
)
}.timeInMillis WordSet("hour", "hours")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
WordSet("hour", "hours").anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days").anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months").anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }
@ -255,18 +261,23 @@ internal class MangaPark(context: MangaLoaderContext) :
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml()
val script = if (doc.selectFirst("script:containsData(comic-)") != null) { val id = chapter.url.removeSuffix('/').substringAfterLast('/').substringBefore('-')
doc.selectFirstOrThrow("script:containsData(comic-)").data() val s = doc.selectFirstOrThrow("script:containsData($id)").data()
.substringAfterLast("\"comic-")
val script = if (s.contains("\"comic-")) {
s.substringAfterLast("\"comic-")
} else { } else {
doc.selectFirstOrThrow("script:containsData(manga-)").data() s.substringAfterLast("\"manga-")
.substringAfterLast("\"manga-")
} }
return Regex("\"(https?:.+?)\"") return Regex("\"(https?:.+?)\"")
.findAll(script) .findAll(script)
.mapNotNullTo(ArrayList()) { .mapIndexedNotNullTo(ArrayList()) { i, it ->
val url = it.groupValues.getOrNull(1) ?: return@mapNotNullTo null val url = it.groupValues.getOrNull(1) ?: return@mapIndexedNotNullTo null
if (url.contains("/comic/") || url.contains("/manga/") || url.contains("/image/mpup/")) { if (url.contains(".jpg") || url.contains(".jpeg") || url.contains(".jfif") || url.contains(".pjpeg") ||
url.contains(".pjp") || url.contains(".png") || url.contains(".webp") || url.contains(".avif") ||
url.contains(".gif")
) {
MangaPage( MangaPage(
id = generateUid(url), id = generateUid(url),
url = url, url = url,
@ -274,7 +285,7 @@ internal class MangaPark(context: MangaLoaderContext) :
source = source, source = source,
) )
} else { } else {
return@mapNotNullTo null return@mapIndexedNotNullTo null
} }
} }
} }

@ -11,7 +11,7 @@ import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@MangaSourceParser("COMICEXTRA", "ComicExtra", "en") @MangaSourceParser("COMICEXTRA", "ComicExtra", "en", ContentType.COMICS)
internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(context, MangaParserSource.COMICEXTRA, 25) { internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(context, MangaParserSource.COMICEXTRA, 25) {
override val configKeyDomain = ConfigKey.Domain("comixextra.com") override val configKeyDomain = ConfigKey.Domain("comixextra.com")

@ -1,5 +1,6 @@
package org.koitharu.kotatsu.parsers.site.liliana package org.koitharu.kotatsu.parsers.site.liliana
import androidx.collection.scatterSetOf
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
@ -27,16 +28,26 @@ internal abstract class LilianaParser(
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.POPULARITY_MONTH,
SortOrder.POPULARITY_WEEK,
SortOrder.POPULARITY_TODAY,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.ALPHABETICAL_DESC,
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.RATING_ASC, SortOrder.NEWEST_ASC,
SortOrder.RATING,
)
override suspend fun getFilterOptions(): MangaListFilterOptions = MangaListFilterOptions(
availableTags = getAvailableTags(),
availableStates = setOf(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
) )
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isTagsExclusionSupported = true,
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
) )
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
@ -45,45 +56,51 @@ internal abstract class LilianaParser(
append(domain) append(domain)
when { when {
!filter.query.isNullOrEmpty() -> { !filter.query.isNullOrEmpty() -> {
append("/search") append("/search/")
append("?keyword=") append(page)
append("/?keyword=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
} }
else -> { else -> {
append("/filter") append("/filter/")
append(page)
append("/?sort=")
when (order) {
SortOrder.UPDATED -> append("latest-updated")
SortOrder.POPULARITY -> append("views")
SortOrder.POPULARITY_MONTH -> append("views_month")
SortOrder.POPULARITY_WEEK -> append("views_week")
SortOrder.POPULARITY_TODAY -> append("views_day")
SortOrder.ALPHABETICAL -> append("az")
SortOrder.ALPHABETICAL_DESC -> append("za")
SortOrder.NEWEST -> append("new")
SortOrder.NEWEST_ASC -> append("old")
SortOrder.RATING -> append("score")
else -> append("latest-updated")
}
append("&genres=")
filter.tags.joinTo(this, ",") { it.key }
append("&notGenres=")
filter.tagsExclude.joinTo(this, ",") { it.key }
if (filter.states.isNotEmpty()) {
append("&status=")
append(
when (filter.states.first()) {
MangaState.ONGOING -> "on-going"
MangaState.FINISHED -> "completed"
MangaState.PAUSED -> "on-hold"
MangaState.ABANDONED -> "canceled"
else -> "all"
},
)
}
} }
} }
append("/")
append(page)
append("/")
when (order) {
SortOrder.UPDATED -> append("?sort=latest-updated")
SortOrder.POPULARITY -> append("?sort=views")
SortOrder.ALPHABETICAL -> append("?sort=az")
SortOrder.NEWEST -> append("?sort=new")
SortOrder.RATING_ASC -> append("?sort=score")
else -> append("?sort=default")
}
filter.tags.forEach { tag ->
append("&genres=")
append(tag.key)
}
if (filter.states.isNotEmpty()) {
append("&status=")
append(
when (filter.states.first()) {
MangaState.ONGOING -> "on-going"
MangaState.FINISHED -> "completed"
MangaState.PAUSED -> "on-hold"
MangaState.ABANDONED -> "canceled"
else -> "all"
},
)
}
} }
val doc = webClient.httpGet(url).parseHtml() val doc = webClient.httpGet(url).parseHtml()
@ -104,10 +121,30 @@ internal abstract class LilianaParser(
author = null, author = null,
state = null, state = null,
source = source, source = source,
isNsfw = false, isNsfw = isNsfwSource,
) )
} }
@JvmField
protected val ongoing = scatterSetOf(
"on-going", "đang tiến hành", "進行中",
)
@JvmField
protected val finished = scatterSetOf(
"completed", "hoàn thành", "完了",
)
@JvmField
protected val abandoned = scatterSetOf(
"canceled", "đã huỷ bỏ", "キャンセル",
)
@JvmField
protected val paused = scatterSetOf(
"on-hold", "tạm dừng", "一時停止",
)
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(
@ -123,27 +160,28 @@ internal abstract class LilianaParser(
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().orEmpty()) {
"on-going", "đang tiến hành", "進行中" -> MangaState.ONGOING in ongoing -> MangaState.ONGOING
"completed", "hoàn thành", "完了" -> MangaState.FINISHED in finished -> MangaState.FINISHED
"on-hold", "tạm dừng", "一時停止" -> MangaState.PAUSED in paused -> MangaState.PAUSED
"canceled", "đã huỷ bỏ", "キャンセル" -> MangaState.ABANDONED in abandoned -> MangaState.ABANDONED
else -> null else -> null
}, },
chapters = doc.select("ul > li.chapter").mapChapters(reversed = true) { i, element -> chapters = doc.select("ul > li.chapter").mapChapters(reversed = true) { 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() ?: "Chapter : ${i + 1f}",
number = i + 1f, number = i + 1f,
volume = 0,
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,
) )
}, },
) )
} }
@ -170,13 +208,10 @@ internal abstract class LilianaParser(
throw Exception(responseJson.optString("msg")) throw Exception(responseJson.optString("msg"))
} }
val pageListHtml = responseJson.getString("html") val pageListDoc = responseJson.getString("html").let(Jsoup::parse)
val pageListDoc = Jsoup.parse(pageListHtml)
return pageListDoc.select("div.iv-card").mapIndexed { index, div ->
val img = div.selectFirst("img")
val url = img?.attr("data-src") ?: img?.attr("src") ?: throw Exception("Failed to get image url")
return pageListDoc.select("div").map {
val url = it.selectFirstOrThrow("img").attr("src")
MangaPage( MangaPage(
id = generateUid(url), id = generateUid(url),
url = url, url = url,
@ -196,9 +231,4 @@ internal abstract class LilianaParser(
) )
} }
} }
override suspend fun getFilterOptions(): MangaListFilterOptions = MangaListFilterOptions(
availableTags = getAvailableTags(),
availableStates = setOf(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
)
} }

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.liliana.en
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.liliana.LilianaParser
@MangaSourceParser("MANGASECT", "MangaSect", "en")
internal class MangaSect(context: MangaLoaderContext) :
LilianaParser(context, MangaParserSource.MANGASECT, "mangasect.net")

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.liliana.en
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.liliana.LilianaParser
@MangaSourceParser("MANHUAGOLD", "ManhuaGold", "en")
internal class ManhuaGold(context: MangaLoaderContext) :
LilianaParser(context, MangaParserSource.MANHUAGOLD, "manhuagold.top")

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.liliana.en
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.liliana.LilianaParser
@MangaSourceParser("MANHUAPLUSORG", "ManhuaPlus.org", "en")
internal class ManhuaPlusOrg(context: MangaLoaderContext) :
LilianaParser(context, MangaParserSource.MANHUAPLUSORG, "manhuaplus.org")

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.liliana.ja
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.liliana.LilianaParser
@MangaSourceParser("MANGAKOMA01", "MangaKoma01", "ja")
internal class MangaKoma01(context: MangaLoaderContext) :
LilianaParser(context, MangaParserSource.MANGAKOMA01, "mangakoma01.net")

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.site.liliana.ja
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.liliana.LilianaParser
@MangaSourceParser("RAW1001", "Raw1001", "ja")
internal class Raw1001(context: MangaLoaderContext) :
LilianaParser(context, MangaParserSource.RAW1001, "raw1001.net")

@ -9,4 +9,4 @@ import org.koitharu.kotatsu.parsers.Broken
@Broken @Broken
@MangaSourceParser("DOCTRUYEN5S", "DocTruyen5s", "vi") @MangaSourceParser("DOCTRUYEN5S", "DocTruyen5s", "vi")
internal class DocTruyen5s(context: MangaLoaderContext) : internal class DocTruyen5s(context: MangaLoaderContext) :
LilianaParser(context, MangaParserSource.DOCTRUYEN5S, "dongmoe.com") LilianaParser(context, MangaParserSource.DOCTRUYEN5S, "dongmoe.com")

@ -233,7 +233,9 @@ internal abstract class MadaraParser(
} }
append("/?s=") append("/?s=")
append(filter.query?.urlEncoded()) filter.query?.let {
append(filter.query.urlEncoded())
}
append("&post_type=wp-manga") append("&post_type=wp-manga")
@ -536,10 +538,10 @@ internal abstract class MadaraParser(
val fullUrl = manga.url.toAbsoluteUrl(domain) val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml() val doc = webClient.httpGet(fullUrl).parseHtml()
val href = doc.selectFirst("head meta[property='og:url']")?.attr("content")?.toRelativeUrl(domain) ?: manga.url
val testCheckAsync = doc.select(selectTestAsync) val testCheckAsync = doc.select(selectTestAsync)
val chaptersDeferred = if (testCheckAsync.isNullOrEmpty()) { val chaptersDeferred = if (testCheckAsync.isNullOrEmpty()) {
async { loadChapters(manga.url, doc) } async { loadChapters(href, doc) }
} else { } else {
async { getChapters(manga, doc) } async { getChapters(manga, doc) }
} }
@ -561,6 +563,8 @@ internal abstract class MadaraParser(
val alt = doc.body().select(selectAlt).firstOrNull()?.tableValue()?.text()?.trim() val alt = doc.body().select(selectAlt).firstOrNull()?.tableValue()?.text()?.trim()
manga.copy( manga.copy(
url = href,
publicUrl = href.toAbsoluteUrl(domain),
tags = doc.body().select(selectGenre).mapNotNullToSet { a -> tags = doc.body().select(selectGenre).mapNotNullToSet { a ->
MangaTag( MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'), key = a.attr("href").removeSuffix("/").substringAfterLast('/'),

@ -5,13 +5,17 @@ import okhttp3.Headers
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Base64
@MangaSourceParser("ADULT_WEBTOON", "AdultWebtoon", "en", ContentType.HENTAI) @MangaSourceParser("ADULT_WEBTOON", "AdultWebtoon", "en", ContentType.HENTAI)
internal class AdultWebtoon(context: MangaLoaderContext) : internal class AdultWebtoon(context: MangaLoaderContext) :
@ -150,6 +154,68 @@ internal class AdultWebtoon(context: MangaLoaderContext) :
} }
} }
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
val chapterProtector = doc.getElementById("chapter-protector-data")
if (chapterProtector == null) {
throw if (doc.selectFirst(selectRequiredLogin) != null) {
AuthRequiredException(source)
} else {
val root = doc.body().selectFirst(selectBodyPage) ?: throw ParseException(
"No image found, try to log in",
fullUrl,
)
return root.select(selectPage).map { div ->
val img = div.selectFirstOrThrow("img")
val url = img.src()?.toRelativeUrl(domain) ?: div.parseFailed("Image src not found")
MangaPage(
id = generateUid(url),
url = url.replace("http:", "https:"),
preview = null,
source = source,
)
}
}
} else {
val chapterProtectorHtml = chapterProtector.attr("src")
.takeIf { it.startsWith("data:text/javascript;base64,") }
?.substringAfter("data:text/javascript;base64,")
?.let {
Base64.getDecoder().decode(it).decodeToString()
}
?: chapterProtector.html()
val password = chapterProtectorHtml.substringAfter("wpmangaprotectornonce='").substringBefore("';")
val chapterData = JSONObject(
chapterProtectorHtml.substringAfter("chapter_data='").substringBefore("';").replace("\\/", "/"),
)
val unsaltedCiphertext = context.decodeBase64(chapterData.getString("ct"))
val salt = chapterData.getString("s").toString().decodeHex()
val ciphertext = "Salted__".toByteArray(Charsets.UTF_8) + salt + unsaltedCiphertext
val rawImgArray = CryptoAES(context).decrypt(context.encodeBase64(ciphertext), password)
val imgArrayString = rawImgArray.filterNot { c -> c == '[' || c == ']' || c == '\\' || c == '"' }
return imgArrayString.split(",").map { url ->
MangaPage(
id = generateUid(url),
url = url.replace("http:", "https:"),
preview = null,
source = source,
)
}
}
}
private fun String.decodeHex(): ByteArray {
check(length % 2 == 0) { "Must have an even length" }
return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
}
private suspend fun makeRequest(url: String, payload: RequestBody, headers: Headers): Document { private suspend fun makeRequest(url: String, payload: RequestBody, headers: Headers): Document {
var retryCount = 0 var retryCount = 0
val backoffDelay = 2000L // Initial delay (milliseconds) val backoffDelay = 2000L // Initial delay (milliseconds)

@ -245,18 +245,18 @@ internal abstract class MangaReaderParser(
"En cours de publication", "Đang tiến hành", "Em lançamento", "em lançamento", "Em Lançamento", "Онгоінг", "Publishing", "En cours de publication", "Đang tiến hành", "Em lançamento", "em lançamento", "Em Lançamento", "Онгоінг", "Publishing",
"Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating", "Lançando", "In Arrivo", "Emision", "Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating", "Lançando", "In Arrivo", "Emision",
"En emision", "مستمر", "Curso", "En marcha", "Publicandose", "Publicando", "连载中", "Devam ediyor", "Devam Etmekte", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "Publicando", "连载中", "Devam ediyor", "Devam Etmekte",
-> MangaState.ONGOING -> MangaState.ONGOING
"Completed", "Completo", "Complété", "Fini", "Achevé", "Terminé", "Terminé ⚫", "Tamamlandı", "Đã hoàn thành", "Hoàn Thành", "Completed", "Completo", "Complété", "Fini", "Achevé", "Terminé", "Terminé ⚫", "Tamamlandı", "Đã hoàn thành", "Hoàn Thành",
"مكتملة", "Завершено", "Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído", "مكتملة", "Завершено", "Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído",
"Concluido", "已完结", "Bitmiş", "Concluido", "已完结", "Bitmiş",
-> MangaState.FINISHED -> MangaState.FINISHED
"Canceled", "Cancelled", "Cancelado", "cancellato", "Cancelados", "Dropped", "Discontinued", "abandonné", "Abandonné", "Canceled", "Cancelled", "Cancelado", "cancellato", "Cancelados", "Dropped", "Discontinued", "abandonné", "Abandonné",
-> MangaState.ABANDONED -> MangaState.ABANDONED
"Hiatus", "On Hold", "Pausado", "En espera", "En pause", "En Pause", "En attente", "Hiatus", "On Hold", "Pausado", "En espera", "En pause", "En Pause", "En attente",
-> MangaState.PAUSED -> MangaState.PAUSED
else -> null else -> null
} }

@ -186,17 +186,17 @@ internal abstract class NepnepParser(
altTitle = null, altTitle = null,
state = when (doc.selectFirstOrThrow(".list-group-item:contains(Status:) a").text()) { state = when (doc.selectFirstOrThrow(".list-group-item:contains(Status:) a").text()) {
"Ongoing (Scan)", "Ongoing (Publish)", "Ongoing (Scan)", "Ongoing (Publish)",
-> MangaState.ONGOING -> MangaState.ONGOING
"Complete (Scan)", "Complete (Publish)", "Complete (Scan)", "Complete (Publish)",
-> MangaState.FINISHED -> MangaState.FINISHED
"Cancelled (Scan)", "Cancelled (Publish)", "Cancelled (Scan)", "Cancelled (Publish)",
"Discontinued (Scan)", "Discontinued (Publish)", "Discontinued (Scan)", "Discontinued (Publish)",
-> MangaState.ABANDONED -> MangaState.ABANDONED
"Hiatus (Scan)", "Hiatus (Publish)", "Hiatus (Scan)", "Hiatus (Publish)",
-> MangaState.PAUSED -> MangaState.PAUSED
else -> null else -> null
}, },

@ -216,7 +216,7 @@ internal abstract class ChanParser(
when (order) { when (order) {
SortOrder.RATING, SortOrder.RATING,
SortOrder.POPULARITY, SortOrder.POPULARITY,
-> "favdesc" -> "favdesc"
SortOrder.ALPHABETICAL -> "abcasc" SortOrder.ALPHABETICAL -> "abcasc"
else -> "" // SortOrder.NEWEST else -> "" // SortOrder.NEWEST

@ -95,7 +95,7 @@ internal abstract class LibSocialParser(
SortOrder.NEWEST -> "created_at" SortOrder.NEWEST -> "created_at"
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.ALPHABETICAL_DESC, SortOrder.ALPHABETICAL_DESC,
-> "rus_name" -> "rus_name"
else -> null else -> null
}, },
@ -108,7 +108,7 @@ internal abstract class LibSocialParser(
SortOrder.RATING, SortOrder.RATING,
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.ALPHABETICAL_DESC, SortOrder.ALPHABETICAL_DESC,
-> "desc" -> "desc"
SortOrder.ALPHABETICAL -> "asc" SortOrder.ALPHABETICAL -> "asc"
else -> null else -> null

@ -1,6 +1,5 @@
package org.koitharu.kotatsu.parsers.site.vi package org.koitharu.kotatsu.parsers.site.vi
import androidx.collection.ArrayMap
import org.json.JSONArray import org.json.JSONArray
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
@ -53,7 +52,8 @@ internal class BlogTruyenParser(context: MangaLoaderContext) :
filter.tags.isNotEmpty() -> { filter.tags.isNotEmpty() -> {
filter.tags.oneOrThrowIfMany()?.let { tag -> filter.tags.oneOrThrowIfMany()?.let { tag ->
val categoryAjax = "https://${domain}/ajax/Category/AjaxLoadMangaByCategory?id=${tag.key}&orderBy=5&p=$page" val categoryAjax =
"https://${domain}/ajax/Category/AjaxLoadMangaByCategory?id=${tag.key}&orderBy=5&p=$page"
val listContent = webClient.httpGet(categoryAjax).parseHtml().selectFirst("div.list") val listContent = webClient.httpGet(categoryAjax).parseHtml().selectFirst("div.list")
parseMangaList(listContent) ?: emptyList() parseMangaList(listContent) ?: emptyList()
} ?: emptyList() } ?: emptyList()
@ -248,6 +248,6 @@ internal class BlogTruyenParser(context: MangaLoaderContext) :
MangaTag("Soft Yuri", "36", source), MangaTag("Soft Yuri", "36", source),
MangaTag("Live action", "16", source), MangaTag("Live action", "16", source),
MangaTag("Tu chân - tu tiên", "66", source), MangaTag("Tu chân - tu tiên", "66", source),
MangaTag("Ngôn tình", "65", source) MangaTag("Ngôn tình", "65", source),
) )
} }

@ -17,7 +17,7 @@ import org.koitharu.kotatsu.parsers.Broken
@Broken @Broken
@MangaSourceParser("BLOGTRUYENVN", "BlogTruyenVN", "vi") @MangaSourceParser("BLOGTRUYENVN", "BlogTruyenVN", "vi")
internal class BlogTruyenVNParser(context: MangaLoaderContext) : internal class BlogTruyenVN(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.BLOGTRUYENVN, pageSize = 20) { PagedMangaParser(context, MangaParserSource.BLOGTRUYENVN, pageSize = 20) {
override val configKeyDomain: ConfigKey.Domain override val configKeyDomain: ConfigKey.Domain

Loading…
Cancel
Save