Small fixes

Koitharu 1 year ago
parent dd7568659f
commit f26fecb714
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -201,7 +201,7 @@ internal class ComickFunParser(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = getChapters(comic.getString("hid")), chapters = getChapters(comic.getString("hid")),
) )
} }

@ -184,7 +184,7 @@ internal class ExHentaiParser(
rawTitle.contains("(ongoing)", ignoreCase = true) -> MangaState.ONGOING rawTitle.contains("(ongoing)", ignoreCase = true) -> MangaState.ONGOING
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
source = source, source = source,
) )
} }

@ -558,7 +558,7 @@ internal class HitomiLaParser(context: MangaLoaderContext) : LegacyMangaParser(c
"https://${getDomain("${subDomain}a")}/webp/$commonId$imageId/$hash.webp" "https://${getDomain("${subDomain}a")}/webp/$commonId$imageId/$hash.webp"
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
publicUrl = json.getString("galleryurl").toAbsoluteUrl(domain), publicUrl = json.getString("galleryurl").toAbsoluteUrl(domain),
tags = tags =
buildSet buildSet

@ -171,7 +171,7 @@ internal class ImHentai(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(
id = manga.id, id = manga.id,

@ -134,7 +134,7 @@ internal abstract class LineWebtoonsParser(
coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain),
largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain), largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain),
tags = setOf(parseTag(jo.getJSONObject("genreInfo"))), tags = setOf(parseTag(jo.getJSONObject("genreInfo"))),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = jo.getString("synopsis"), description = jo.getString("synopsis"),
// I don't think the API provides this info // I don't think the API provides this info
state = null, state = null,
@ -165,7 +165,7 @@ internal abstract class LineWebtoonsParser(
coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain),
largeCoverUrl = null, largeCoverUrl = null,
tags = emptySet(), tags = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = null, description = null,
state = null, state = null,
source = source, source = source,
@ -211,7 +211,7 @@ internal abstract class LineWebtoonsParser(
coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain),
largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain), largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain),
tags = setOfNotNull(genres[jo.getString("representGenre")]), tags = setOfNotNull(genres[jo.getString("representGenre")]),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = jo.getString("synopsis"), description = jo.getString("synopsis"),
// I don't think the API provides this info // I don't think the API provides this info
state = null, state = null,

@ -213,7 +213,7 @@ internal abstract class MangaFireParser(
else -> null else -> null
} }
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = document.selectFirstOrThrow("#synopsis div.modal-content").html(), description = document.selectFirstOrThrow("#synopsis div.modal-content").html(),
chapters = getChapters(manga.url, document), chapters = getChapters(manga.url, document),
) )

@ -196,7 +196,7 @@ internal class MangaPark(context: MangaLoaderContext) :
val author = doc.selectFirst("div[q:key=tz_4]")?.textOrNull() val author = doc.selectFirst("div[q:key=tz_4]")?.textOrNull()
manga.copy( manga.copy(
altTitles = setOfNotNull(doc.selectFirst("div[q:key=tz_2]")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst("div[q:key=tz_2]")?.textOrNull()),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirst("react-island[q:key=0a_9]")?.html(), description = doc.selectFirst("react-island[q:key=0a_9]")?.html(),
state = when (doc.selectFirst("span[q:key=Yn_5]")?.text()?.lowercase()) { state = when (doc.selectFirst("span[q:key=Yn_5]")?.text()?.lowercase()) {
"ongoing" -> MangaState.ONGOING "ongoing" -> MangaState.ONGOING

@ -203,7 +203,7 @@ internal class MangaReaderToParser(context: MangaLoaderContext) :
else -> null else -> null
} }
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = document.select("div.description").html(), description = document.select("div.description").html(),
chapters = parseChapters(document), chapters = parseChapters(document),
source = source, source = source,

@ -140,7 +140,7 @@ internal abstract class NineMangaParser(
title = root.selectFirst("h1[itemprop=name]")?.textOrNull()?.removeSuffix("Manga")?.trimEnd() title = root.selectFirst("h1[itemprop=name]")?.textOrNull()?.removeSuffix("Manga")?.trimEnd()
?: manga.title, ?: manga.title,
tags = tags.orEmpty(), tags = tags.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = parseStatus(infoRoot.select("li a.red").text()), state = parseStatus(infoRoot.select("li a.red").text()),
description = infoRoot.getElementsByAttributeValue("itemprop", "description").first()?.html() description = infoRoot.getElementsByAttributeValue("itemprop", "description").first()?.html()
?.substringAfter("</b>"), ?.substringAfter("</b>"),

@ -270,7 +270,7 @@ internal class NineNineNineHentaiParser(context: MangaLoaderContext) :
altTitles = setOf(name), altTitles = setOf(name),
coverUrl = cover.first, coverUrl = cover.first,
largeCoverUrl = cover.second, largeCoverUrl = cover.second,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
contentRating = ContentRating.ADULT, contentRating = ContentRating.ADULT,
tags = tags?.mapToSet { tags = tags?.mapToSet {
MangaTag( MangaTag(

@ -137,7 +137,7 @@ internal abstract class WebtoonsParser(
coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain),
largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain), largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain),
tags = setOf(parseTag(jo.getJSONObject("genreInfo"))), tags = setOf(parseTag(jo.getJSONObject("genreInfo"))),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = jo.getString("synopsis"), description = jo.getString("synopsis"),
// I don't think the API provides this info, // I don't think the API provides this info,
state = null, state = null,
@ -170,7 +170,7 @@ internal abstract class WebtoonsParser(
title = jo.getString("title"), title = jo.getString("title"),
coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain),
altTitles = emptySet(), altTitles = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
contentRating = if (isNsfwSource) ContentRating.ADULT else null, contentRating = if (isNsfwSource) ContentRating.ADULT else null,
rating = jo.getFloatOrDefault("starScoreAverage", -10f) / 10f, rating = jo.getFloatOrDefault("starScoreAverage", -10f) / 10f,
tags = setOfNotNull(allGenreCache.get()[jo.getString("representGenre")]), tags = setOfNotNull(allGenreCache.get()[jo.getString("representGenre")]),
@ -213,7 +213,7 @@ internal abstract class WebtoonsParser(
coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain),
largeCoverUrl = null, largeCoverUrl = null,
tags = emptySet(), tags = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = null, description = null,
state = null, state = null,
source = source, source = source,

@ -134,7 +134,7 @@ internal abstract class CupFoxParser(
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirst(selectMangaDescription)?.html(), description = doc.selectFirst(selectMangaDescription)?.html(),
chapters = doc.select(selectMangaChapters) chapters = doc.select(selectMangaChapters)
.mapChapters { i, li -> .mapChapters { i, li ->

@ -114,7 +114,7 @@ internal class BeeToon(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = doc.select(".items-chapters a").mapChapters(reversed = true) { i, a -> chapters = doc.select(".items-chapters a").mapChapters(reversed = true) { i, a ->
val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain) val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain)
MangaChapter( MangaChapter(

@ -119,7 +119,7 @@ internal class ComicExtra(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirstOrThrow("div.detail-desc-content p").html(), description = doc.selectFirstOrThrow("div.detail-desc-content p").html(),
chapters = doc.select("ul.basic-list li").let { elements -> chapters = doc.select("ul.basic-list li").let { elements ->
elements.mapChapters { i, li -> elements.mapChapters { i, li ->

@ -154,7 +154,7 @@ internal class FlameComics(context: MangaLoaderContext) :
"Ongoing" -> MangaState.ONGOING "Ongoing" -> MangaState.ONGOING
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
largeCoverUrl = if (cover != null) { largeCoverUrl = if (cover != null) {
imageUrl(seriesId, cover, 640) imageUrl(seriesId, cover, 640)
} else { } else {

@ -90,7 +90,7 @@ internal class MangaGeko(context: MangaLoaderContext) :
coverUrl = div.selectFirstOrThrow("img").src(), coverUrl = div.selectFirstOrThrow("img").src(),
tags = emptySet(), tags = emptySet(),
state = null, state = null,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
source = source, source = source,
) )
} }
@ -125,7 +125,7 @@ internal class MangaGeko(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirstOrThrow(".description").html(), description = doc.selectFirstOrThrow(".description").html(),
chapters = chaptersDeferred.await(), chapters = chaptersDeferred.await(),
) )

@ -105,7 +105,7 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) :
altTitles = doc.select("span[itemprop*=alternativeHeadline]").mapNotNullToSet { altTitles = doc.select("span[itemprop*=alternativeHeadline]").mapNotNullToSet {
it.textOrNull() it.textOrNull()
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (doc.selectFirst("span.badge.bg-success.text-uppercase")?.text()) { state = when (doc.selectFirst("span.badge.bg-success.text-uppercase")?.text()) {
"Ongoing" -> MangaState.ONGOING "Ongoing" -> MangaState.ONGOING
"" -> MangaState.FINISHED "" -> MangaState.FINISHED

@ -121,7 +121,7 @@ internal class MangaTownParser(context: MangaLoaderContext) :
altTitles = emptySet(), altTitles = emptySet(),
rating = li.selectFirst("p.score")?.selectFirst("b") rating = li.selectFirst("p.score")?.selectFirst("b")
?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, ?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (status) { state = when (status) {
"ongoing" -> MangaState.ONGOING "ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED "completed" -> MangaState.FINISHED

@ -168,7 +168,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull() cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull()
?.removePrefix(": "), ?.removePrefix(": "),
), ),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = docs.selectFirst(".series-summary .summary-content")?.html(), description = docs.selectFirst(".series-summary .summary-content")?.html(),
tags = tags.orEmpty(), tags = tags.orEmpty(),
state = state, state = state,

@ -168,7 +168,7 @@ internal class Manhwa18Parser(context: MangaLoaderContext) :
cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull() cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull()
?.removePrefix(": "), ?.removePrefix(": "),
), ),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = docs.selectFirst(".series-summary .summary-content")?.html(), description = docs.selectFirst(".series-summary .summary-content")?.html(),
tags = tags.orEmpty(), tags = tags.orEmpty(),
state = state, state = state,

@ -97,7 +97,7 @@ internal class MyComicList(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (doc.selectFirst("td:contains(Status:) + td a")?.text()?.lowercase()) { state = when (doc.selectFirst("td:contains(Status:) + td a")?.text()?.lowercase()) {
"ongoing" -> MangaState.ONGOING "ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED "completed" -> MangaState.FINISHED

@ -71,7 +71,7 @@ internal class Po2Scans(context: MangaLoaderContext) :
else -> null else -> null
}, },
tags = emptySet(), tags = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirstOrThrow(".summary").html(), description = doc.selectFirstOrThrow(".summary").html(),
chapters = doc.select(".chap-section .chap") chapters = doc.select(".chap-section .chap")
.mapChapters(reversed = true) { i, div -> .mapChapters(reversed = true) { i, div ->

@ -145,7 +145,7 @@ internal class Pururin(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(
id = manga.id, id = manga.id,

@ -211,7 +211,7 @@ internal class WeebCentral(context: MangaLoaderContext) : LegacyMangaParser(cont
"Hiatus" -> PAUSED "Hiatus" -> PAUSED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
largeCoverUrl = null, largeCoverUrl = null,
chapters = null, chapters = null,
source = source, source = source,

@ -187,7 +187,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : LegacyPagedMan
}, },
largeCoverUrl = contents.selectFirst(".book-thumbnail")?.attrAsAbsoluteUrlOrNull("src"), largeCoverUrl = contents.selectFirst(".book-thumbnail")?.attrAsAbsoluteUrlOrNull("src"),
state = parseStatus(contents.select("span.book-status").text().orEmpty()), state = parseStatus(contents.select("span.book-status").text().orEmpty()),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = if (doc.select("div.chapters").isEmpty()) { chapters = if (doc.select("div.chapters").isEmpty()) {
doc.select(oneShotChapterListSelector).mapChapters(reversed = true) { _, item -> doc.select(oneShotChapterListSelector).mapChapters(reversed = true) { _, item ->
oneShotChapterFromElement(item) oneShotChapterFromElement(item)

@ -126,7 +126,7 @@ internal abstract class FoolSlideParser(
manga.copy( manga.copy(
coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl, coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl,
description = desc?.nullIfEmpty(), description = desc?.nullIfEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = chapters, chapters = chapters,
) )
} }

@ -160,7 +160,7 @@ internal class BentomangaParser(context: MangaLoaderContext) :
"En pause" -> MangaState.PAUSED "En pause" -> MangaState.PAUSED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = run { chapters = run {
val input = root.selectFirst("input[name=\"limit\"]") ?: return@run parseChapters(root) val input = root.selectFirst("input[name=\"limit\"]") ?: return@run parseChapters(root)
val max = input.attr("max").toInt() val max = input.attr("max").toInt()

@ -180,7 +180,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
) )
}, },
coverUrl = root.selectFirst("div.serieImg img")?.attrAsAbsoluteUrlOrNull("src"), coverUrl = root.selectFirst("div.serieImg img")?.attrAsAbsoluteUrlOrNull("src"),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = root.selectFirst("div.serieDescription div")?.html(), description = root.selectFirst("div.serieDescription div")?.html(),
chapters = root.select("div.chapterList a") chapters = root.select("div.chapterList a")
.mapChapters(reversed = true) { i, a -> .mapChapters(reversed = true) { i, a ->

@ -106,7 +106,7 @@ internal class LireScan(context: MangaLoaderContext) : LegacyPagedMangaParser(co
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = root.selectFirst("div.pmovie__text")?.html(), description = root.selectFirst("div.pmovie__text")?.html(),
chapters = root.select("ul li div.chapter") chapters = root.select("ul li div.chapter")
.mapChapters(reversed = true) { i, div -> .mapChapters(reversed = true) { i, div ->

@ -169,7 +169,7 @@ internal class LugnicaScans(context: MangaLoaderContext) :
"3" -> MangaState.ABANDONED "3" -> MangaState.ABANDONED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = jsonManga.getStringOrNull("description"), description = jsonManga.getStringOrNull("description"),
chapters = chapters.mapChapters { i, it -> chapters = chapters.mapChapters { i, it ->
val id = it.substringAfter("\"chapter\":").substringBefore(",") val id = it.substringAfter("\"chapter\":").substringBefore(",")

@ -138,7 +138,7 @@ internal class ScantradUnion(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = root.selectFirst("p.sContent")?.html(), description = root.selectFirst("p.sContent")?.html(),
chapters = root.select("div.chapter-list li") chapters = root.select("div.chapter-list li")
.mapChapters(reversed = true) { i, li -> .mapChapters(reversed = true) { i, li ->

@ -192,7 +192,7 @@ internal abstract class FuzzyDoodleParser(
in paused -> MangaState.PAUSED in paused -> MangaState.PAUSED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.select(selectDescription).html(), description = doc.select(selectDescription).html(),
tags = doc.select(selectTagManga).mapToSet { tags = doc.select(selectTagManga).mapToSet {
val key = it.attr("href").substringAfterLast('=') val key = it.attr("href").substringAfterLast('=')

@ -169,7 +169,7 @@ internal abstract class GalleryAdultsParser(
return manga.copy( return manga.copy(
tags = tag.orEmpty(), tags = tag.orEmpty(),
title = doc.selectFirst(selectTitle)?.textOrNull()?.cleanupTitle() ?: manga.title, title = doc.selectFirst(selectTitle)?.textOrNull()?.cleanupTitle() ?: manga.title,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(
id = manga.id, id = manga.id,

@ -129,7 +129,7 @@ internal class HentaiEra(context: MangaLoaderContext) :
val author = doc.selectFirst(selectAuthor)?.text() val author = doc.selectFirst(selectAuthor)?.text()
return manga.copy( return manga.copy(
tags = tag.orEmpty(), tags = tag.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(
id = manga.id, id = manga.id,

@ -116,7 +116,7 @@ internal abstract class GattsuParser(
description = doc.selectFirst("div.post-texto")?.html(), description = doc.selectFirst("div.post-texto")?.html(),
tags = doc.selectFirst(".post-itens li:contains(Tags), .paginaPostInfo li:contains(Categorias)") tags = doc.selectFirst(".post-itens li:contains(Tags), .paginaPostInfo li:contains(Categorias)")
?.parseTags().orEmpty(), ?.parseTags().orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(
id = manga.id, id = manga.id,

@ -75,7 +75,7 @@ internal abstract class GuyaParser(
tags = emptySet(), tags = emptySet(),
description = j.getString("description"), description = j.getString("description"),
state = null, state = null,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
contentRating = if (isNsfwSource) ContentRating.ADULT else null, contentRating = if (isNsfwSource) ContentRating.ADULT else null,
source = source, source = source,
) )

@ -143,7 +143,7 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
} }
val author = metadataEl?.selectFirst("tr:contains(Author)")?.selectLast("td")?.text() val author = metadataEl?.selectFirst("tr:contains(Author)")?.selectLast("td")?.text()
return manga.copy( return manga.copy(
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = docs.selectFirst(".wrapper > .metadata > .pb-2")?.selectFirst("p")?.html(), description = docs.selectFirst(".wrapper > .metadata > .pb-2")?.selectFirst("p")?.html(),
state = state, state = state,
rating = metadataEl?.selectFirst(".rating-prc")?.ownText()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, rating = metadataEl?.selectFirst(".rating-prc")?.ownText()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN,

@ -101,7 +101,7 @@ internal class HentaiCrot(context: MangaLoaderContext) :
altTitles = setOfNotNull( altTitles = setOfNotNull(
doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.textOrNull(), doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.textOrNull(),
), ),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = null, state = null,
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(

@ -101,7 +101,7 @@ internal class PixHentai(context: MangaLoaderContext) :
altTitles = setOfNotNull( altTitles = setOfNotNull(
doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.textOrNull(), doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.textOrNull(),
), ),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = null, state = null,
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(

@ -113,7 +113,7 @@ internal abstract class IkenParser(
description = it.getString("postContent"), description = it.getString("postContent"),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
tags = emptySet(), tags = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (it.getString("seriesStatus")) { state = when (it.getString("seriesStatus")) {
"ONGOING" -> MangaState.ONGOING "ONGOING" -> MangaState.ONGOING
"COMPLETED" -> MangaState.FINISHED "COMPLETED" -> MangaState.FINISHED

@ -90,7 +90,7 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
title = item.selectFirst(".mg_body > .title > a")?.text() ?: return@mapNotNull null, title = item.selectFirst(".mg_body > .title > a")?.text() ?: return@mapNotNull null,
coverUrl = item.selectFirst(".comic_icon > div > a > img")?.attrAsAbsoluteUrl("src"), coverUrl = item.selectFirst(".comic_icon > div > a > img")?.attrAsAbsoluteUrl("src"),
altTitles = emptySet(), altTitles = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
url = href, url = href,
contentRating = null, contentRating = null,

@ -159,7 +159,7 @@ internal abstract class LikeMangaParser(
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.requireElementById("summary_shortened").html(), description = doc.requireElementById("summary_shortened").html(),
chapters = run { chapters = run {
if (maxPageChapter == 1) { if (maxPageChapter == 1) {

@ -161,7 +161,7 @@ internal abstract class LilianaParser(
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (doc.selectFirst("div.y6x11p i.fas.fa-rss + span.dt")?.text()?.lowercase().orEmpty()) { state = when (doc.selectFirst("div.y6x11p i.fas.fa-rss + span.dt")?.text()?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED in finished -> MangaState.FINISHED

@ -477,7 +477,7 @@ internal abstract class MadaraParser(
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when ( state = when (
summary?.selectFirst(".mg_status") summary?.selectFirst(".mg_status")
?.selectFirst(".summary-content") ?.selectFirst(".summary-content")

@ -34,7 +34,7 @@ internal class FireScans(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when ( state = when (
summary?.selectFirst(".mg_status") summary?.selectFirst(".mg_status")
?.selectFirst(".summary-content") ?.selectFirst(".summary-content")

@ -119,7 +119,7 @@ internal class Hentai4Free(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase().orEmpty()) { ?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -93,7 +93,7 @@ internal class IsekaiScan(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase()) { ?.lowercase()) {
"ongoing" -> MangaState.ONGOING "ongoing" -> MangaState.ONGOING

@ -116,7 +116,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase().orEmpty()) { ?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -91,7 +91,7 @@ internal class MangaDass(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase().orEmpty()) { ?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -84,7 +84,7 @@ internal class MangaDna(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase().orEmpty()) { ?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -98,7 +98,7 @@ internal class MangaPure(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase()) { ?.lowercase()) {
"ongoing" -> MangaState.ONGOING "ongoing" -> MangaState.ONGOING

@ -87,7 +87,7 @@ internal class Manhwaz(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase().orEmpty()) { ?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -35,7 +35,7 @@ internal class ShibaManga(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when ( state = when (
summary?.selectFirst(".mg_status") summary?.selectFirst(".mg_status")
?.selectFirst(".summary-content") ?.selectFirst(".summary-content")

@ -29,7 +29,7 @@ internal class MangasNoSekai(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = body.selectFirst("#section-sinopsis p")?.text().orEmpty(), description = body.selectFirst("#section-sinopsis p")?.text().orEmpty(),
altTitles = setOfNotNull( altTitles = setOfNotNull(
doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Otros nombres)) p") doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Otros nombres)) p")

@ -83,7 +83,7 @@ internal class ManhwaHub(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase().orEmpty()) { ?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -39,7 +39,7 @@ internal class MangaFenxi(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when ( state = when (
summary?.selectFirst(".mg_status") summary?.selectFirst(".mg_status")
?.selectFirst(".summary-content") ?.selectFirst(".summary-content")

@ -88,7 +88,7 @@ internal class Saytruyenhay(context: MangaLoaderContext) :
source = source, source = source,
) )
}.orEmpty(), }.orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase().orEmpty()) { ?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -275,7 +275,7 @@ internal abstract class MangaReaderParser(
return manga.copy( return manga.copy(
description = docs.selectFirst(detailsDescriptionSelector)?.text(), description = docs.selectFirst(detailsDescriptionSelector)?.text(),
state = mangaState, state = mangaState,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
contentRating = if (manga.isNsfw || nsfw) { contentRating = if (manga.isNsfw || nsfw) {
ContentRating.ADULT ContentRating.ADULT
} else { } else {

@ -110,7 +110,7 @@ internal class Normoyun(context: MangaLoaderContext) :
return manga.copy( return manga.copy(
description = docs.selectFirst("span.desc")?.html(), description = docs.selectFirst("span.desc")?.html(),
state = mangaState, state = mangaState,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
contentRating = if (manga.isNsfw || nsfw) { contentRating = if (manga.isNsfw || nsfw) {
ContentRating.ADULT ContentRating.ADULT
} else { } else {

@ -133,7 +133,7 @@ internal class RizzComic(context: MangaLoaderContext) :
"hiatus" -> MangaState.PAUSED "hiatus" -> MangaState.PAUSED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
source = source, source = source,
description = j.getString("long_description"), description = j.getString("long_description"),
) )

@ -123,7 +123,7 @@ internal class Komikcast(context: MangaLoaderContext) :
return manga.copy( return manga.copy(
description = docs.selectFirst("div.komik_info-description-sinopsis")?.text(), description = docs.selectFirst("div.komik_info-description-sinopsis")?.text(),
state = mangaState, state = mangaState,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
contentRating = if (manga.isNsfw || nsfw) { contentRating = if (manga.isNsfw || nsfw) {
ContentRating.ADULT ContentRating.ADULT
} else { } else {

@ -154,7 +154,7 @@ internal abstract class MangaWorldParser(
altTitles = emptySet(), altTitles = emptySet(),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
tags = tags, tags = tags,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = state =
when (div.selectFirst(".status a")?.text()?.lowercase()) { when (div.selectFirst(".status a")?.text()?.lowercase()) {
"in corso" -> MangaState.ONGOING "in corso" -> MangaState.ONGOING

@ -68,7 +68,7 @@ internal class Onma(context: MangaLoaderContext) :
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = desc, description = desc,
altTitles = setOfNotNull(alt), altTitles = setOfNotNull(alt),
state = state, state = state,

@ -208,7 +208,7 @@ internal abstract class NepnepParser(
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirstOrThrow(".top-5.Content").textOrNull(), description = doc.selectFirstOrThrow(".top-5.Content").textOrNull(),
chapters = chapter.mapJSONIndexed { i, j -> chapters = chapter.mapJSONIndexed { i, j ->

@ -175,7 +175,7 @@ internal abstract class OtakuSanctuaryParser(
}, },
description = desc, description = desc,
altTitles = setOfNotNull(alt), altTitles = setOfNotNull(alt),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = state, state = state,
chapters = doc.body().requireElementById("chapter").select("tr.chapter") chapters = doc.body().requireElementById("chapter").select("tr.chapter")
.mapChapters(reversed = true) { i, tr -> .mapChapters(reversed = true) { i, tr ->

@ -196,7 +196,7 @@ internal abstract class PizzaReaderParser(
rating = j.getString("rating").toFloatOrNull()?.div(10f) rating = j.getString("rating").toFloatOrNull()?.div(10f)
?: RATING_UNKNOWN, ?: RATING_UNKNOWN,
tags = emptySet(), tags = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (j.getString("status").lowercase()) { state = when (j.getString("status").lowercase()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED in finished -> MangaState.FINISHED

@ -130,7 +130,7 @@ internal class BrMangas(context: MangaLoaderContext) : LegacyPagedMangaParser(co
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.select(".serie-texto p").html(), description = doc.select(".serie-texto p").html(),
contentRating = if (doc.select("div.serie-infos li:contains(Categorias:)").text().contains("Hentai")) { contentRating = if (doc.select("div.serie-infos li:contains(Categorias:)").text().contains("Hentai")) {
ContentRating.ADULT ContentRating.ADULT

@ -91,7 +91,7 @@ internal class LuratoonScansParser(context: MangaLoaderContext) :
"finalizado" -> MangaState.FINISHED "finalizado" -> MangaState.FINISHED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
largeCoverUrl = doc.selectFirst("img.sumario__img")?.attrAsAbsoluteUrlOrNull("src"), largeCoverUrl = doc.selectFirst("img.sumario__img")?.attrAsAbsoluteUrlOrNull("src"),
description = summaryContainer.selectFirst(".sumario__sinopse__texto")?.html(), description = summaryContainer.selectFirst(".sumario__sinopse__texto")?.html(),
chapters = doc.selectFirstOrThrow("ul.capitulos__lista") chapters = doc.selectFirstOrThrow("ul.capitulos__lista")

@ -108,7 +108,7 @@ internal class YugenMangas(context: MangaLoaderContext) :
description = detailManga.getString("synopsis"), description = detailManga.getString("synopsis"),
coverUrl = detailManga.getString("cover"), coverUrl = detailManga.getString("cover"),
altTitles = setOfNotNull(detailManga.getStringOrNull("alternative_names")), altTitles = setOfNotNull(detailManga.getStringOrNull("alternative_names")),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = detailManga.getStringOrNull("status")?.let { state = detailManga.getStringOrNull("status")?.let {
when (it) { when (it) {
"ongoing" -> MangaState.ONGOING "ongoing" -> MangaState.ONGOING

@ -145,7 +145,7 @@ internal class AComics(context: MangaLoaderContext) :
return manga.copy( return manga.copy(
tags = tags, tags = tags,
description = doc.selectFirst("section.serial-about-text p")?.text(), description = doc.selectFirst("section.serial-about-text p")?.text(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
chapters = listOf( chapters = listOf(
MangaChapter( MangaChapter(
id = manga.id, id = manga.id,

@ -99,7 +99,7 @@ internal class NudeMoonParser(
url = href, url = href,
title = title.substringAfter(" / "), title = title.substringAfter(" / "),
altTitles = setOfNotNull(title.substringBefore(" / ", "").takeUnless { it.isBlank() }), altTitles = setOfNotNull(title.substringBefore(" / ", "").takeUnless { it.isBlank() }),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
coverUrl = row.selectFirst("img")?.absUrl("src").orEmpty(), coverUrl = row.selectFirst("img")?.absUrl("src").orEmpty(),
tags = row.selectFirst(".tag-links")?.select("a")?.mapToSet { tags = row.selectFirst(".tag-links")?.select("a")?.mapToSet {
MangaTag( MangaTag(

@ -62,7 +62,7 @@ internal class WaMangaParser(
"закончен" -> MangaState.FINISHED "закончен" -> MangaState.FINISHED
else -> MangaState.UPCOMING else -> MangaState.UPCOMING
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
source = source, source = source,
contentRating = if (doc.getIntOrDefault("adult", 0) == 0) { contentRating = if (doc.getIntOrDefault("adult", 0) == 0) {
ContentRating.SAFE ContentRating.SAFE

@ -424,7 +424,7 @@ internal abstract class GroupleParser(
rating = runCatching { rating = runCatching {
node.selectFirst(".compact-rate")?.attr("title")?.toFloatOrNull()?.div(5f) node.selectFirst(".compact-rate")?.attr("title")?.toFloatOrNull()?.div(5f)
}.getOrNull() ?: RATING_UNKNOWN, }.getOrNull() ?: RATING_UNKNOWN,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
contentRating = if (isNsfwSource) ContentRating.ADULT else null, contentRating = if (isNsfwSource) ContentRating.ADULT else null,
tags = runCatching { tags = runCatching {
tileInfo?.select("a.element-link")?.mapToSet { tileInfo?.select("a.element-link")?.mapToSet {

@ -60,7 +60,7 @@ internal abstract class ChanParser(
publicUrl = href.toAbsoluteUrl(a.host ?: domain), publicUrl = href.toAbsoluteUrl(a.host ?: domain),
altTitles = setOfNotNull(title.second), altTitles = setOfNotNull(title.second),
title = title.first, title = title.first,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
coverUrl = row.selectFirst("div.manga_images")?.selectFirst("img") coverUrl = row.selectFirst("div.manga_images")?.selectFirst("img")
?.absUrl("src").orEmpty(), ?.absUrl("src").orEmpty(),
tags = runCatching { tags = runCatching {
@ -176,7 +176,7 @@ internal abstract class ChanParser(
publicUrl = href.toAbsoluteUrl(a.host ?: domain), publicUrl = href.toAbsoluteUrl(a.host ?: domain),
altTitles = setOfNotNull(title.second), altTitles = setOfNotNull(title.second),
title = title.first, title = title.first,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
coverUrl = div.selectFirst("img")?.absUrl("src").orEmpty(), coverUrl = div.selectFirst("img")?.absUrl("src").orEmpty(),
tags = emptySet(), tags = emptySet(),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,

@ -148,7 +148,7 @@ internal abstract class LibSocialParser(
title = json.getStringOrNull("rus_name") ?: manga.title, title = json.getStringOrNull("rus_name") ?: manga.title,
altTitles = setOfNotNull(json.getStringOrNull("name")), altTitles = setOfNotNull(json.getStringOrNull("name")),
tags = tagsSetOf(tags, genres), tags = tagsSetOf(tags, genres),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = json.getString("summary").nl2br(), description = json.getString("summary").nl2br(),
chapters = chapters.await(), chapters = chapters.await(),
) )

@ -148,7 +148,7 @@ internal abstract class ScanParser(
?.ownText()?.toFloatOrNull()?.div(5f) ?.ownText()?.toFloatOrNull()?.div(5f)
?: RATING_UNKNOWN, ?: RATING_UNKNOWN,
tags = tags, tags = tags,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
altTitles = setOfNotNull(doc.selectFirst(".card div.col-12.mb-4 h2, .card-series-about .h6")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst(".card div.col-12.mb-4 h2, .card-series-about .h6")?.textOrNull()),
description = doc.selectFirst(".card div.col-12.mb-4 p, .card-series-desc .mb-4 p")?.html(), description = doc.selectFirst(".card div.col-12.mb-4 p, .card-series-desc .mb-4 p")?.html(),
chapters = doc.select(".chapters-list .col-chapter, .card-list-chapter .col-chapter") chapters = doc.select(".chapters-list .col-chapter, .card-list-chapter .col-chapter")

@ -27,7 +27,7 @@ internal class MangaFr(context: MangaLoaderContext) :
?.ownText()?.toFloatOrNull()?.div(5f) ?.ownText()?.toFloatOrNull()?.div(5f)
?: RATING_UNKNOWN, ?: RATING_UNKNOWN,
tags = emptySet(), tags = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
altTitles = setOfNotNull(doc.selectFirst(".card div.col-12.mb-4 h2, .card-series-about .h6")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst(".card div.col-12.mb-4 h2, .card-series-about .h6")?.textOrNull()),
description = doc.selectFirst(".card div.col-12.mb-4 p, .card-series-desc .mb-4 p")?.html(), description = doc.selectFirst(".card div.col-12.mb-4 p, .card-series-desc .mb-4 p")?.html(),
chapters = doc.select(".chapters-list .col-chapter, .card-list-chapter .col-chapter") chapters = doc.select(".chapters-list .col-chapter, .card-list-chapter .col-chapter")

@ -28,7 +28,7 @@ internal class ScanIta(context: MangaLoaderContext) :
rating = doc.selectFirst(".card-series-detail .rate-value span")?.ownText()?.toFloatOrNull()?.div(5f) rating = doc.selectFirst(".card-series-detail .rate-value span")?.ownText()?.toFloatOrNull()?.div(5f)
?: RATING_UNKNOWN, ?: RATING_UNKNOWN,
tags = tags, tags = tags,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
altTitles = setOfNotNull(doc.selectFirst(".card div.col-12.mb-4 h2")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst(".card div.col-12.mb-4 h2")?.textOrNull()),
description = doc.selectFirst(".card div.col-12.mb-4 p")?.html(), description = doc.selectFirst(".card div.col-12.mb-4 p")?.html(),
chapters = chaptersDeferred.await(), chapters = chaptersDeferred.await(),

@ -72,7 +72,7 @@ internal class SadScans(context: MangaLoaderContext) :
else -> null else -> null
}, },
tags = emptySet(), tags = emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirstOrThrow(".summary").html(), description = doc.selectFirstOrThrow(".summary").html(),
chapters = doc.select(".chap-section .chap") chapters = doc.select(".chap-section .chap")
.mapChapters(reversed = true) { i, div -> .mapChapters(reversed = true) { i, div ->

@ -122,7 +122,7 @@ internal class HentaiUkrParser(context: MangaLoaderContext) : LegacyMangaParser(
coverUrl = jo.getString("thumb").toAbsoluteUrl(domain), coverUrl = jo.getString("thumb").toAbsoluteUrl(domain),
tags = getTags(jo.optJSONArray("tags")), tags = getTags(jo.optJSONArray("tags")),
state = null, state = null,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
largeCoverUrl = null, largeCoverUrl = null,
description = null, description = null,
chapters = null, chapters = null,

@ -83,7 +83,7 @@ internal class BlogTruyenParser(context: MangaLoaderContext) :
description = mangaInfo.select("div.al-j.fs-12").text(), description = mangaInfo.select("div.al-j.fs-12").text(),
url = relativeUrl, url = relativeUrl,
publicUrl = relativeUrl.toAbsoluteUrl(domain), publicUrl = relativeUrl.toAbsoluteUrl(domain),
coverUrl = mangaInfo.selectFirst("div > img.img")?.src().orEmpty(), coverUrl = mangaInfo.selectFirst("div > img.img")?.src(),
contentRating = null, contentRating = null,
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
tags = emptySet(), tags = emptySet(),
@ -129,7 +129,7 @@ internal class BlogTruyenParser(context: MangaLoaderContext) :
return manga.copy( return manga.copy(
tags = tags, tags = tags,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirst(".detail .content")?.html(), description = doc.selectFirst(".detail .content")?.html(),
chapters = parseChapterList(doc), chapters = parseChapterList(doc),
largeCoverUrl = doc.selectLast("div.thumbnail > img")?.src(), largeCoverUrl = doc.selectLast("div.thumbnail > img")?.src(),

@ -116,10 +116,10 @@ internal class BlogTruyenVN(context: MangaLoaderContext) :
id = generateUid(relativeUrl), id = generateUid(relativeUrl),
title = a.text(), title = a.text(),
altTitles = emptySet(), altTitles = emptySet(),
description = mangaInfo.select("div.al-j.fs-12").text(), description = mangaInfo.select("div.al-j.fs-12").textOrNull(),
url = relativeUrl, url = relativeUrl,
publicUrl = relativeUrl.toAbsoluteUrl(domain), publicUrl = relativeUrl.toAbsoluteUrl(domain),
coverUrl = mangaInfo.selectFirst("div > img.img")?.src().orEmpty(), coverUrl = mangaInfo.selectFirst("div > img.img")?.src(),
contentRating = null, contentRating = null,
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
tags = emptySet(), tags = emptySet(),
@ -181,7 +181,7 @@ internal class BlogTruyenVN(context: MangaLoaderContext) :
return manga.copy( return manga.copy(
tags = tags ?: emptySet(), tags = tags ?: emptySet(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirst(".detail .content")?.html(), description = doc.selectFirst(".detail .content")?.html(),
chapters = parseChapterList(doc), chapters = parseChapterList(doc),
largeCoverUrl = doc.selectLast("div.thumbnail > img")?.src(), largeCoverUrl = doc.selectLast("div.thumbnail > img")?.src(),

@ -32,7 +32,7 @@ internal class BuonDuaParser(context: MangaLoaderContext) : LegacyMangaParser(co
val df = SimpleDateFormat("HH:mm dd-MM-yyyy") val df = SimpleDateFormat("HH:mm dd-MM-yyyy")
val time = content.selectFirst("div.article-info > small")?.text()?.trim() val time = content.selectFirst("div.article-info > small")?.text()?.trim()
val chapters = content.selectFirst("nav.pagination")?.select("a.pagination-link") val chapters = content.selectFirst("nav.pagination")?.select("a.pagination-link")
?.mapIndexed { index, element -> ?.mapChapters { index, element ->
val relUrl = element.attrAsRelativeUrl("href") val relUrl = element.attrAsRelativeUrl("href")
MangaChapter( MangaChapter(
id = generateUid(relUrl), id = generateUid(relUrl),

@ -22,8 +22,7 @@ private const val PAGE_SIZE = 20
internal class CMangaParser(context: MangaLoaderContext) : internal class CMangaParser(context: MangaLoaderContext) :
LegacyPagedMangaParser(context, MangaParserSource.CMANGA, PAGE_SIZE), MangaParserAuthProvider { LegacyPagedMangaParser(context, MangaParserSource.CMANGA, PAGE_SIZE), MangaParserAuthProvider {
override val configKeyDomain: ConfigKey.Domain override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("cmangax.com")
get() = ConfigKey.Domain("cmangax.com")
override val availableSortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of( get() = EnumSet.of(
@ -47,7 +46,7 @@ internal class CMangaParser(context: MangaLoaderContext) :
override suspend fun getFilterOptions(): MangaListFilterOptions { override suspend fun getFilterOptions(): MangaListFilterOptions {
return MangaListFilterOptions( return MangaListFilterOptions(
availableTags = tags.get().values.toSet(), availableTags = tags.get().values.toArraySet(),
availableStates = arraySetOf(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED), availableStates = arraySetOf(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED),
) )
} }
@ -80,14 +79,14 @@ internal class CMangaParser(context: MangaLoaderContext) :
chapters = webClient chapters = webClient
.httpGet("/api/chapter_list?album=$mangaId&page=1&limit=${Int.MAX_VALUE}&v=0v21".toAbsoluteUrl(domain)) .httpGet("/api/chapter_list?album=$mangaId&page=1&limit=${Int.MAX_VALUE}&v=0v21".toAbsoluteUrl(domain))
.parseJsonArray() .parseJsonArray()
.mapJSON { jo -> .mapChapters(reversed = true) { _, jo ->
val chapterId = jo.getLong("id_chapter") val chapterId = jo.getLong("id_chapter")
val info = jo.parseJson("info") val info = jo.parseJson("info")
val chapterNumber = info.getString("num") val chapterNumber = info.getFloatOrDefault("num", -1f) + 1f
MangaChapter( MangaChapter(
id = generateUid(chapterId), id = generateUid(chapterId),
name = if (info.isLocked()) "Chapter $chapterNumber - locked" else "Chapter $chapterNumber", name = if (info.isLocked()) "Chapter $chapterNumber - locked" else "Chapter $chapterNumber",
number = chapterNumber.toFloatOrNull()?.plus(1) ?: 0f, number = chapterNumber,
volume = 0, volume = 0,
url = "/album/$slug/chapter-$mangaId-$chapterId", url = "/album/$slug/chapter-$mangaId-$chapterId",
uploadDate = df.tryParse(info.getString("last_update")), uploadDate = df.tryParse(info.getString("last_update")),
@ -95,7 +94,7 @@ internal class CMangaParser(context: MangaLoaderContext) :
scanlator = null, scanlator = null,
source = source, source = source,
) )
}.reversed(), },
) )
} }

@ -24,7 +24,7 @@ import java.util.*
@MangaSourceParser("CUUTRUYEN", "Cứu Truyện", "vi") @MangaSourceParser("CUUTRUYEN", "Cứu Truyện", "vi")
internal class CuuTruyenParser(context: MangaLoaderContext) : internal class CuuTruyenParser(context: MangaLoaderContext) :
LegacyPagedMangaParser(context, MangaParserSource.CUUTRUYEN, 20), Interceptor { LegacyPagedMangaParser(context, MangaParserSource.CUUTRUYEN, 20) {
override val userAgentKey = ConfigKey.UserAgent(UserAgents.KOTATSU) override val userAgentKey = ConfigKey.UserAgent(UserAgents.KOTATSU)
@ -115,7 +115,7 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
altTitles = emptySet(), altTitles = emptySet(),
coverUrl = jo.getString("cover_mobile_url"), coverUrl = jo.getString("cover_mobile_url"),
largeCoverUrl = jo.getString("cover_url"), largeCoverUrl = jo.getString("cover_url"),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
tags = emptySet(), tags = emptySet(),
state = null, state = null,
description = null, description = null,
@ -153,19 +153,21 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
// Remove old manga status from "tags" // Remove old manga status from "tags"
val newTags = tags.filter { it.key != "da-hoan-thanh" && it.key != "dang-tien-hanh" }.toSet() val newTags = tags.filter { it.key != "da-hoan-thanh" && it.key != "dang-tien-hanh" }.toSet()
val author = json.optJSONObject("author")?.getStringOrNull("name")?.substringBefore(',')?.nullIfEmpty() val author = json.optJSONObject("author")?.getStringOrNull("name")?.substringBefore(',')?.nullIfEmpty()
val title = json.getStringOrNull("name") ?: manga.title
manga.copy( manga.copy(
title = json.getStringOrNull("name") ?: manga.title, title = title,
altTitles = json.optJSONArray("titles")?.mapJSONToSet { it.getString("name") }?.minus(title).orEmpty(),
contentRating = if (json.getBooleanOrDefault("is_nsfw", manga.isNsfw)) { contentRating = if (json.getBooleanOrDefault("is_nsfw", manga.isNsfw)) {
ContentRating.ADULT ContentRating.ADULT
} else { } else {
ContentRating.SAFE ContentRating.SAFE
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = json.getStringOrNull("full_description"), description = json.getStringOrNull("full_description"),
tags = newTags, tags = newTags,
state = state, state = state,
chapters = chapters.await().mapJSON { jo -> chapters = chapters.await().mapChapters(reversed = true) { _, jo ->
val chapterId = jo.getLong("id") val chapterId = jo.getLong("id")
val number = jo.getFloatOrDefault("number", 0f) val number = jo.getFloatOrDefault("number", 0f)
MangaChapter( MangaChapter(
@ -179,7 +181,7 @@ internal class CuuTruyenParser(context: MangaLoaderContext) :
branch = null, branch = null,
source = source, source = source,
) )
}.reversed(), },
) )
} }

@ -105,7 +105,7 @@ internal class DuaLeoTruyen(context: MangaLoaderContext) :
"Full" -> MangaState.FINISHED "Full" -> MangaState.FINISHED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirst(".story-detail-info")?.html(), description = doc.selectFirst(".story-detail-info")?.html(),
chapters = doc.select(".list-chapters .chapter-item").mapChapters(reversed = true) { i, div -> chapters = doc.select(".list-chapters .chapter-item").mapChapters(reversed = true) { i, div ->
val a = div.selectFirstOrThrow(".chap_name a") val a = div.selectFirstOrThrow(".chap_name a")

@ -94,7 +94,7 @@ internal class Hentai18VN(context: MangaLoaderContext) :
private fun parseMangaSearch(doc: Document): List<Manga> { private fun parseMangaSearch(doc: Document): List<Manga> {
return doc.select("a.item").map { a -> return doc.select("a.item").map { a ->
val href = a.attr("href") val href = a.attr("href")
val mangaInfo = a.selectFirst("img") val mangaInfo = a.selectFirstOrThrow("img")
Manga( Manga(
id = generateUid(href), id = generateUid(href),
url = href, url = href,
@ -105,7 +105,7 @@ internal class Hentai18VN(context: MangaLoaderContext) :
tags = emptySet(), tags = emptySet(),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
state = null, state = null,
coverUrl = mangaInfo.requireSrc(), coverUrl = mangaInfo.src(),
contentRating = ContentRating.ADULT, contentRating = ContentRating.ADULT,
source = source, source = source,
) )
@ -138,13 +138,13 @@ internal class Hentai18VN(context: MangaLoaderContext) :
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()
val tags = doc.select("div.hentai-info .line-content a.item-tag") val tags = doc.select("div.hentai-info .line-content a.item-tag")
.mapNotNull { a -> .mapToSet { a ->
MangaTag( MangaTag(
title = a.text(), title = a.text().toTitleCase(sourceLocale),
key = a.attr("href").substringAfterLast("/"), key = a.attr("href").substringAfterLast('/'),
source = source, source = source,
) )
}.toSet() }
val chapters = doc.select("ul#chapter-list li.citem").mapChapters(reversed = true) { i, li -> val chapters = doc.select("ul#chapter-list li.citem").mapChapters(reversed = true) { i, li ->
val a = li.selectFirst("a") ?: return@mapChapters null val a = li.selectFirst("a") ?: return@mapChapters null
@ -152,7 +152,7 @@ internal class Hentai18VN(context: MangaLoaderContext) :
id = generateUid(a.attr("href")), id = generateUid(a.attr("href")),
name = a.text(), name = a.text(),
number = i + 1f, number = i + 1f,
url = a.attr("href").removePrefix("https://$domain"), url = a.attrAsRelativeUrl("href"),
uploadDate = parseChapterDate(li.selectFirst(".time")?.text()), uploadDate = parseChapterDate(li.selectFirst(".time")?.text()),
source = source, source = source,
scanlator = null, scanlator = null,

@ -115,7 +115,7 @@ internal class HentaiVNParser(context: MangaLoaderContext) : LegacyMangaParser(c
altTitles = infoEl.selectFirst("span.info:contains(Tên Khác:)")?.parent()?.select("span:not(.info) > a") altTitles = infoEl.selectFirst("span.info:contains(Tên Khác:)")?.parent()?.select("span:not(.info) > a")
?.mapNotNullToSet { it.textOrNull() } ?.mapNotNullToSet { it.textOrNull() }
.orEmpty(), .orEmpty(),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = infoEl.select("p:contains(Nội dung:) + p").html(), description = infoEl.select("p:contains(Nội dung:) + p").html(),
tags = tags, tags = tags,
state = stateDoc.select("p:contains(Tình Trạng:) a").firstOrNull()?.text()?.let { state = stateDoc.select("p:contains(Tình Trạng:) a").firstOrNull()?.text()?.let {

@ -118,7 +118,7 @@ internal class HentaiVnBuzz(context: MangaLoaderContext) :
private fun parseSearchManga(doc: Document): List<Manga> { private fun parseSearchManga(doc: Document): List<Manga> {
return doc.select(".story-item-list.d-flex.align-items-center.position-relative.mb-1").map { div -> return doc.select(".story-item-list.d-flex.align-items-center.position-relative.mb-1").map { div ->
val href = div.selectFirstOrThrow("a.story-item-list__image").attrAsRelativeUrl("href") val href = div.selectFirstOrThrow("a.story-item-list__image").attrAsRelativeUrl("href")
val coverUrl = div.selectFirst("img")?.attr("data-src").orEmpty() val coverUrl = div.selectFirst("img")?.attr("data-src")
val title = div.selectFirst("img")?.attr("alt").orEmpty() val title = div.selectFirst("img")?.attr("alt").orEmpty()
Manga( Manga(
id = generateUid(href), id = generateUid(href),
@ -163,11 +163,11 @@ internal class HentaiVnBuzz(context: MangaLoaderContext) :
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val author = doc.select("p:contains(Tác giả:) a").text().nullIfEmpty() val author = doc.select("p:contains(Tác giả:) a").text().nullIfEmpty()
return manga.copy( return manga.copy(
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
tags = doc.select("div.mb-1 span a").mapToSet { element -> tags = doc.select("div.mb-1 span a").mapToSet { element ->
MangaTag( MangaTag(
key = element.attr("href").substringAfter("/the-loai/"), key = element.attr("href").substringAfter("/the-loai/"),
title = element.text().substringBefore(",").trim(), // force trim before , symbol and space title = element.text().substringBefore(',').trim(), // force trim before , symbol and space
source = source, source = source,
) )
}, },

@ -162,7 +162,7 @@ internal class KuroNeko(context: MangaLoaderContext) : LegacyPagedMangaParser(co
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = root.selectFirst("meta[name=description]")?.attrOrNull("content"), description = root.selectFirst("meta[name=description]")?.attrOrNull("content"),
chapters = root.select("div.justify-between ul.overflow-y-auto.overflow-x-hidden a") chapters = root.select("div.justify-between ul.overflow-y-auto.overflow-x-hidden a")
.mapChapters(reversed = true) { i, a -> .mapChapters(reversed = true) { i, a ->

@ -163,7 +163,7 @@ internal class LxManga(context: MangaLoaderContext) : LegacyPagedMangaParser(con
source = source, source = source,
) )
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = root.selectFirst("meta[name=description]")?.attrOrNull("content"), description = root.selectFirst("meta[name=description]")?.attrOrNull("content"),
chapters = root.select("div.justify-between ul.overflow-y-auto.overflow-x-hidden a") chapters = root.select("div.justify-between ul.overflow-y-auto.overflow-x-hidden a")
.mapChapters(reversed = true) { i, a -> .mapChapters(reversed = true) { i, a ->

@ -90,7 +90,7 @@ internal class SayHentai(context: MangaLoaderContext) :
val author = doc.selectFirst("div.summary-heading:contains(Tác giả) + div.summary-content")?.textOrNull() val author = doc.selectFirst("div.summary-heading:contains(Tác giả) + div.summary-content")?.textOrNull()
return manga.copy( return manga.copy(
altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
tags = doc.select("div.genres-content a[rel=tag]").mapToSet { a -> tags = doc.select("div.genres-content a[rel=tag]").mapToSet { a ->
MangaTag( MangaTag(
key = a.attr("href").substringAfterLast('/'), key = a.attr("href").substringAfterLast('/'),
@ -178,7 +178,7 @@ internal class SayHentai(context: MangaLoaderContext) :
.mapToSet { a -> .mapToSet { a ->
val title = a.ownText().toTitleCase(sourceLocale) val title = a.ownText().toTitleCase(sourceLocale)
MangaTag( MangaTag(
key = a.attr("href").substringAfterLast("/"), key = a.attr("href").substringAfterLast('/'),
title = title, title = title,
source = source, source = source,
) )

@ -127,7 +127,7 @@ internal class TruyenGG(context: MangaLoaderContext) : LegacyPagedMangaParser(co
publicUrl = href.toAbsoluteUrl(domain), publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN, rating = RATING_UNKNOWN,
contentRating = if (isNsfwSource) ContentRating.ADULT else null, contentRating = if (isNsfwSource) ContentRating.ADULT else null,
coverUrl = div.selectFirst(".image-cover img")?.attr("data-src").orEmpty(), coverUrl = div.selectFirst(".image-cover img")?.attrAsAbsoluteUrlOrNull("data-src"),
tags = emptySet(), tags = emptySet(),
state = null, state = null,
authors = emptySet(), authors = emptySet(),
@ -143,11 +143,11 @@ internal class TruyenGG(context: MangaLoaderContext) : LegacyPagedMangaParser(co
return manga.copy( return manga.copy(
altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
tags = doc.select("a.clblue").mapToSet { tags = doc.select("a.clblue").mapToSet {
MangaTag( MangaTag(
key = it.attr("href").substringAfterLast('-').substringBeforeLast('.'), key = it.attr("href").substringAfterLast('-').substringBeforeLast('.'),
title = it.text(), title = it.text().toTitleCase(sourceLocale),
source = source, source = source,
) )
}, },
@ -196,7 +196,7 @@ internal class TruyenGG(context: MangaLoaderContext) : LegacyPagedMangaParser(co
return doc.select(".advsearch-form div.genre-item").mapToSet { return doc.select(".advsearch-form div.genre-item").mapToSet {
MangaTag( MangaTag(
key = it.selectFirstOrThrow("span").attr("data-id"), key = it.selectFirstOrThrow("span").attr("data-id"),
title = it.text(), title = it.text().toTitleCase(sourceLocale),
source = source, source = source,
) )
} }

@ -94,6 +94,7 @@ internal class TruyenHentaiVN(context: MangaLoaderContext) :
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()
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.US)
return manga.copy( return manga.copy(
authors = setOfNotNull(doc.selectFirst("div.author i")?.textOrNull()), authors = setOfNotNull(doc.selectFirst("div.author i")?.textOrNull()),
tags = doc.select("div.genre.mb-3.mgen a").mapNotNullToSet { a -> tags = doc.select("div.genre.mb-3.mgen a").mapNotNullToSet { a ->
@ -121,13 +122,7 @@ internal class TruyenHentaiVN(context: MangaLoaderContext) :
val name = div.selectFirst("a .name")?.text() ?: "" val name = div.selectFirst("a .name")?.text() ?: ""
val dateStr = div.selectFirst("a span:last-child")?.text() val dateStr = div.selectFirst("a span:last-child")?.text()
val uploadDate = dateStr?.let { val uploadDate = dateFormat.tryParse(dateStr)
try {
SimpleDateFormat("dd-MM-yyyy", Locale.US).parse(it)?.time ?: 0L
} catch (e: Exception) {
0L
}
} ?: 0L
MangaChapter( MangaChapter(
id = generateUid(url), id = generateUid(url),
@ -147,15 +142,13 @@ internal class TruyenHentaiVN(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()
return doc.select("div.content-text img").mapNotNull { img -> return doc.select("div.content-text img").mapNotNull { img ->
val url = img.requireSrc().toAbsoluteUrl(domain) val url = img.src() ?: return@mapNotNull null
if (url.isNotEmpty()) {
MangaPage( MangaPage(
id = generateUid(url), id = generateUid(url),
url = url, url = url,
preview = null, preview = null,
source = source, source = source,
) )
} else null
} }
} }

@ -166,7 +166,7 @@ internal class TruyenQQ(context: MangaLoaderContext) : LegacyPagedMangaParser(co
"Hoàn Thành" -> MangaState.FINISHED "Hoàn Thành" -> MangaState.FINISHED
else -> null else -> null
}, },
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = doc.selectFirst(".story-detail-info")?.html(), description = doc.selectFirst(".story-detail-info")?.html(),
chapters = doc.select("div.list_chapter div.works-chapter-item").mapChapters(reversed = true) { i, div -> chapters = doc.select("div.list_chapter div.works-chapter-item").mapChapters(reversed = true) { i, div ->
val a = div.selectFirstOrThrow("a") val a = div.selectFirstOrThrow("a")

@ -147,7 +147,7 @@ internal class TruyenTranh3Q(context: MangaLoaderContext) :
return manga.copy( return manga.copy(
altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
tags = tags, tags = tags,
description = doc.selectFirst("div.story-detail-info")?.html(), description = doc.selectFirst("div.story-detail-info")?.html(),
state = when (doc.selectFirst(".status p.col-xs-9")?.text()) { state = when (doc.selectFirst(".status p.col-xs-9")?.text()) {

@ -134,7 +134,7 @@ internal class VcomycsParser(context: MangaLoaderContext) :
info.selectFirst(".comic-intro-text > strong:contains(Tên khác:)")?.nextElementSibling() info.selectFirst(".comic-intro-text > strong:contains(Tên khác:)")?.nextElementSibling()
?.textOrNull(), ?.textOrNull(),
), ),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = when (info.selectFirst(".comic-stt")?.text()) { state = when (info.selectFirst(".comic-stt")?.text()) {
"Đang tiến hành" -> MangaState.ONGOING "Đang tiến hành" -> MangaState.ONGOING
"Trọn bộ" -> MangaState.FINISHED "Trọn bộ" -> MangaState.FINISHED

@ -101,7 +101,6 @@ internal class YurinekoParser(context: MangaLoaderContext) :
val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US) val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)
return manga.copy( return manga.copy(
chapters = response.getJSONArray("chapters") chapters = response.getJSONArray("chapters")
.asTypedList<JSONObject>()
.mapChapters(true) { i, jo -> .mapChapters(true) { i, jo ->
val mangaId = jo.getInt("mangaID") val mangaId = jo.getInt("mangaID")
val chapterId = jo.getInt("id") val chapterId = jo.getInt("id")

@ -168,7 +168,7 @@ internal abstract class WpComicsParser(
largeCoverUrl = null, largeCoverUrl = null,
tags = mangaTags, tags = mangaTags,
state = mangaState, state = mangaState,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
description = tooltipElement?.selectFirst("div.box_text")?.text(), description = tooltipElement?.selectFirst("div.box_text")?.text(),
chapters = null, chapters = null,
source = source, source = source,
@ -220,7 +220,7 @@ internal abstract class WpComicsParser(
manga.copy( manga.copy(
description = doc.selectFirst(selectDesc)?.html(), description = doc.selectFirst(selectDesc)?.html(),
altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()), altTitles = setOfNotNull(doc.selectFirst("h2.other-name")?.textOrNull()),
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = doc.selectFirst(selectState)?.let { state = doc.selectFirst(selectState)?.let {
when (it.text()) { when (it.text()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING

@ -138,7 +138,7 @@ internal class XoxoComics(context: MangaLoaderContext) :
) )
}, },
description = desc, description = desc,
authors = author?.let { setOf(it) } ?: emptySet(), authors = setOfNotNull(author),
state = state, state = state,
chapters = chaptersDeferred.await(), chapters = chaptersDeferred.await(),
) )

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save