Fix nullable strings usage

master
Koitharu 1 year ago
parent 5df1445e29
commit 6abcdd8d4b
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -182,7 +182,7 @@ internal class ComickFunParser(context: MangaLoaderContext) :
var alt = ""
comic.getJSONArray("md_titles").mapJSON { alt += it.getString("title") + " - " }
return manga.copy(
altTitle = alt.ifEmpty { comic.getStringOrNull("title") },
altTitle = alt.ifEmpty { comic.getStringOrNull("title") }?.nullIfEmpty(),
contentRating = if (jo.getBooleanOrDefault("matureContent", false)
|| comic.getBooleanOrDefault("hentai", false)
) {
@ -199,7 +199,7 @@ internal class ComickFunParser(context: MangaLoaderContext) :
source = source,
)
},
author = jo.getJSONArray("artists").optJSONObject(0)?.getString("name"),
author = jo.getJSONArray("artists").optJSONObject(0)?.getStringOrNull("name"),
chapters = getChapters(comic.getString("hid")),
)
}

@ -197,7 +197,7 @@ internal class ExHentaiParser(
return manga.copy(
title = title?.getElementById("gn")?.text()?.cleanupTitle() ?: manga.title,
altTitle = title?.getElementById("gj")?.text()?.cleanupTitle() ?: manga.altTitle,
altTitle = (title?.getElementById("gj")?.text()?.cleanupTitle() ?: manga.altTitle)?.nullIfEmpty(),
publicUrl = doc.baseUri().ifEmpty { manga.publicUrl },
rating = root.getElementById("rating_label")?.text()
?.substringAfterLast(' ')

@ -182,7 +182,7 @@ internal abstract class MangaFireParser(
return manga.copy(
title = document.selectFirstOrThrow(".info > h1").ownText(),
altTitle = document.selectFirst(".info > h6")?.ownText(),
altTitle = document.selectFirst(".info > h6")?.ownTextOrNull(),
rating = document.selectFirst("div.rating-box")?.attr("data-score")
?.toFloatOrNull()?.div(10) ?: RATING_UNKNOWN,
coverUrl = document.selectFirstOrThrow("div.manga-detail div.poster img")
@ -212,7 +212,7 @@ internal abstract class MangaFireParser(
}
},
author = document.select("div.meta a[href*=/author/]")
.joinToString { it.ownText() },
.joinToString { it.ownText() }.nullIfEmpty(),
description = document.selectFirstOrThrow("#synopsis div.modal-content").html(),
chapters = getChapters(manga.url, document),
)

@ -179,9 +179,9 @@ internal class MangaPark(context: MangaLoaderContext) :
val nsfw = tags.any { t -> t.key == "hentai" || t.key == "adult" }
val dateFormat = SimpleDateFormat("dd/MM/yyyy", sourceLocale)
manga.copy(
altTitle = doc.selectFirst("div[q:key=tz_2]")?.text().orEmpty(),
author = doc.selectFirst("div[q:key=tz_4]")?.text().orEmpty(),
description = doc.selectFirst("react-island[q:key=0a_9]")?.html().orEmpty(),
altTitle = doc.selectFirst("div[q:key=tz_2]")?.textOrNull(),
author = doc.selectFirst("div[q:key=tz_4]")?.textOrNull(),
description = doc.selectFirst("react-island[q:key=0a_9]")?.html(),
state = when (doc.selectFirst("span[q:key=Yn_5]")?.text()?.lowercase()) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED

@ -172,10 +172,10 @@ internal class MangaReaderToParser(context: MangaLoaderContext) :
return manga.copy(
title = document.selectFirst("h2.manga-name")!!.ownText(),
altTitle = document.selectFirst("div.manga-name-or")?.ownText(),
altTitle = document.selectFirst("div.manga-name-or")?.ownTextOrNull(),
rating = document.selectFirst("div.anisc-info .item:contains(score:) > .name")
?.text()?.toFloatOrNull()?.div(10) ?: RATING_UNKNOWN,
coverUrl = document.selectFirst(".manga-poster > img")!!.attr("src"),
coverUrl = document.selectFirst(".manga-poster > img")?.attrAsAbsoluteUrlOrNull("src"),
tags = document.select("div.genres > a[href*=/genre/]").mapNotNullToSet {
val tag = it.ownText()
if (tag == "Hentai") {
@ -202,8 +202,8 @@ internal class MangaReaderToParser(context: MangaLoaderContext) :
}
},
author = document.select("div.anisc-info a[href*=/author/]")
.joinToString { it.ownText().replace(", ", " ") },
description = document.select("div.description").text(),
.joinToString { it.ownText().replace(", ", " ") }.nullIfEmpty(),
description = document.select("div.description").html(),
chapters = parseChapters(document),
source = source,
)

@ -269,7 +269,7 @@ internal class NineNineNineHentaiParser(context: MangaLoaderContext) :
altTitle = name,
coverUrl = cover.first,
largeCoverUrl = cover.second,
author = tags?.filter { it.type == "artist" }?.joinToString { it.name.toCamelCase() },
author = tags?.filter { it.type == "artist" }?.joinToString { it.name.toCamelCase() }?.nullIfEmpty(),
contentRating = ContentRating.ADULT,
tags = tags?.mapToSet {
MangaTag(

@ -88,8 +88,6 @@ internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(contex
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.selectFirstOrThrow(".card-body .col-lg-9")
return manga.copy(
altTitle = null,
state = null,
tags = root.select(".flex-wrap a").mapToSet { a ->
MangaTag(
key = a.attr("href").substringAfterLast('/'),
@ -97,8 +95,7 @@ internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(contex
source = source,
)
},
author = null,
description = root.selectFirstOrThrow(".card-text").text(),
description = root.selectFirstOrThrow(".card-text").html(),
chapters = doc.select(".card-body a.btn-fixed-width").mapChapters(reversed = true) { i, a ->
val url = a.attrAsRelativeUrl("href")
MangaChapter(

@ -148,7 +148,6 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
}
}
return manga.copy(
altTitle = null,
state = when (doc.selectFirstOrThrow(".full-list-info:contains(الحالة:) a").text()) {
"مستمرة" -> MangaState.ONGOING
"مكتمل" -> MangaState.FINISHED
@ -162,8 +161,7 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
source = source,
)
},
author = null,
description = doc.selectFirstOrThrow(".review-content").text(),
description = doc.selectFirstOrThrow(".review-content").html(),
chapters = run {
if (maxPageChapter == 1) {
parseChapters(doc)

@ -124,8 +124,7 @@ internal abstract class CupFoxParser(
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
return manga.copy(
altTitle = doc.selectFirst(selectMangaDetailsAltTitle)?.text()?.substringAfter(""),
state = null,
altTitle = doc.selectFirst(selectMangaDetailsAltTitle)?.text()?.substringAfter("")?.nullIfEmpty(),
tags = doc.select(selectMangaDetailsTags).mapToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
@ -133,9 +132,8 @@ internal abstract class CupFoxParser(
source = source,
)
},
author = doc.selectFirst(selectMangaDetailsAuthor)?.text()?.substringAfter(""),
description = doc.selectFirst(selectMangaDescription)
?.html(),
author = doc.selectFirst(selectMangaDetailsAuthor)?.text()?.substringAfter("")?.nullIfEmpty(),
description = doc.selectFirst(selectMangaDescription)?.html(),
chapters = doc.select(selectMangaChapters)
.mapChapters { i, li ->
val a = li.selectFirstOrThrow("a")

@ -1,6 +1,5 @@
package org.koitharu.kotatsu.parsers.site.en
import org.koitharu.kotatsu.parsers.ErrorMessages
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
@ -96,7 +95,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex
return doc.select("ul.lf-list li a").mapToSet { a ->
MangaTag(
key = a.attr("href").substringAfterLast('/'),
title = a.text(),
title = a.text().toTitleCase(sourceLocale),
source = source,
)
}
@ -105,7 +104,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
return manga.copy(
altTitle = doc.selectFirstOrThrow("div.anime-top h1.title").text(),
altTitle = doc.selectFirstOrThrow("div.anime-top h1.title").textOrNull(),
state = when (doc.selectFirstOrThrow("ul.anime-genres li.status a").text()) {
"Ongoing" -> MangaState.ONGOING
"Completed" -> MangaState.FINISHED
@ -114,14 +113,14 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex
tags = doc.select("ul.anime-genres li a").mapToSet { a ->
MangaTag(
key = a.attr("href").substringAfterLast('/'),
title = a.text(),
title = a.text().toTitleCase(sourceLocale),
source = source,
)
},
author = doc.selectFirst("table.full-table tr:contains(Author:) td:nth-child(2)")?.text(),
description = doc.selectFirstOrThrow("div.detail-desc-content p").text(),
author = doc.selectFirst("table.full-table tr:contains(Author:) td:nth-child(2)")?.textOrNull(),
description = doc.selectFirstOrThrow("div.detail-desc-content p").html(),
chapters = doc.select("ul.basic-list li").let { elements ->
elements.mapChapters() { i, li ->
elements.mapChapters { i, li ->
val a = li.selectFirstOrThrow("a.ch-name")
val url = a.attrAsRelativeUrl("href")
val name = a.text()

@ -144,7 +144,7 @@ internal class DynastyScans(context: MangaLoaderContext) :
private fun Element.parseTags() = select("a").mapToSet {
MangaTag(
key = it.attr("href").removeSuffix('/').substringAfterLast('/'),
title = it.text(),
title = it.text().toTitleCase(sourceLocale),
source = source,
)
}
@ -157,7 +157,6 @@ internal class DynastyScans(context: MangaLoaderContext) :
.find { it.ownText() == "This manga has been licensed" }
?.nextElementSibling()?.html()
return manga.copy(
altTitle = null,
state = when (root.select("h2.tag-title small").last()?.text()) {
"— Ongoing" -> MangaState.ONGOING
"— Completed", "— Completed and Licensed" -> MangaState.FINISHED
@ -165,10 +164,8 @@ internal class DynastyScans(context: MangaLoaderContext) :
"— On Hiatus" -> MangaState.PAUSED
else -> null
},
coverUrl = root.selectFirst("img.thumbnail")?.src()
.orEmpty(), // It is needed if the manga was found via the search.
coverUrl = root.selectFirst("img.thumbnail")?.src(),
tags = root.selectFirstOrThrow("div.tag-tags").parseTags(),
author = null,
description = licensedText,
chapters = chapters,
)

@ -109,7 +109,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val chaptersDeferred = async { loadChapters(manga.url) }
manga.copy(
altTitle = doc.selectFirstOrThrow(".alternative-title").text(),
altTitle = doc.selectFirstOrThrow(".alternative-title").textOrNull(),
state = when (doc.selectFirstOrThrow(".header-stats span:contains(Status) strong").text()) {
"Ongoing" -> MangaState.ONGOING
"Completed" -> MangaState.FINISHED
@ -122,7 +122,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
source = source,
)
},
author = doc.selectFirstOrThrow(".author").text(),
author = doc.selectFirstOrThrow(".author").textOrNull(),
description = doc.selectFirstOrThrow(".description").html(),
chapters = chaptersDeferred.await(),
)

@ -100,9 +100,9 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) :
val firstChapter = doc.selectFirst("tr[class*='volume-'] a")?.attr("href")
val chaptersDeferred = async { loadChapters(firstChapter) }
manga.copy(
description = doc.selectFirst("dd.text-justify.text-break")?.text().orEmpty(),
altTitle = doc.select("span[itemprop*=alternativeHeadline]").joinToString { ", " },
author = doc.select("a[href*=author]").text(),
description = doc.selectFirst("dd.text-justify.text-break")?.html(),
altTitle = doc.select("span[itemprop*=alternativeHeadline]").joinToString { ", " }.nullIfEmpty(),
author = doc.select("a[href*=author]").textOrNull(),
state = when (doc.selectFirst("span.badge.bg-success.text-uppercase")?.text()) {
"Ongoing" -> MangaState.ONGOING
"" -> MangaState.FINISHED

@ -147,6 +147,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
val author = cardInfoElement?.selectFirst(".info-name:contains(Author)")?.parent()
?.select("a")
?.joinToString(", ") { it.text() }
?.nullIfEmpty()
val availableTags = tagsMap.get()
val tags = cardInfoElement?.selectFirst(".info-name:contains(Genre)")?.parent()
?.select("a")
@ -163,7 +164,8 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
}
return manga.copy(
altTitle = cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownText()?.removePrefix(": "),
altTitle = cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull()
?.removePrefix(": "),
author = author,
description = docs.selectFirst(".series-summary .summary-content")?.html(),
tags = tags.orEmpty(),

@ -147,6 +147,7 @@ internal class Manhwa18Parser(context: MangaLoaderContext) :
val author = cardInfoElement?.selectFirst(".info-name:contains(Author)")?.parent()
?.select("a")
?.joinToString(", ") { it.text() }
?.nullIfEmpty()
val availableTags = tagsMap.get()
val tags = cardInfoElement?.selectFirst(".info-name:contains(Genre)")?.parent()
?.select("a")
@ -163,7 +164,8 @@ internal class Manhwa18Parser(context: MangaLoaderContext) :
}
return manga.copy(
altTitle = cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownText()?.removePrefix(": "),
altTitle = cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull()
?.removePrefix(": "),
author = author,
description = docs.selectFirst(".series-summary .summary-content")?.html(),
tags = tags.orEmpty(),

@ -63,15 +63,14 @@ internal class Po2Scans(context: MangaLoaderContext) : SinglePageMangaParser(con
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("dd MMM, yy", Locale.ENGLISH)
return manga.copy(
altTitle = null,
state = when (doc.select(".status span").last()?.text()) {
"Ongoing" -> MangaState.ONGOING
"Done" -> MangaState.FINISHED
else -> null
},
tags = emptySet(),
author = doc.select(".author span").last()?.text(),
description = doc.selectFirstOrThrow(".summary").text(),
author = doc.selectLast(".author span")?.textOrNull(),
description = doc.selectFirstOrThrow(".summary").html(),
chapters = doc.select(".chap-section .chap")
.mapChapters(reversed = true) { i, div ->
val a = div.selectFirstOrThrow("a")

@ -189,8 +189,8 @@ internal abstract class FmreaderParser(
else -> null
}
}
val alt = doc.body().selectFirst(selectAlt)?.text()?.replace("Other names", "")
val auth = doc.body().selectFirst(selectAut)?.text()
val alt = doc.body().selectFirst(selectAlt)?.text()?.replace("Other names", "")?.nullIfEmpty()
val auth = doc.body().selectFirst(selectAut)?.textOrNull()
manga.copy(
tags = doc.body().select(selectTag).mapToSet { a ->
MangaTag(

@ -125,10 +125,8 @@ internal abstract class FoolSlideParser(
}
manga.copy(
coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl,
description = desc.orEmpty(),
altTitle = null,
author = author.orEmpty(),
state = null,
description = desc?.nullIfEmpty(),
author = author?.nullIfEmpty(),
chapters = chapters,
)
}

@ -35,10 +35,8 @@ internal class Seinagi(context: MangaLoaderContext) :
}
manga.copy(
coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl,
description = desc,
altTitle = null,
author = author,
state = null,
description = desc?.nullIfEmpty(),
author = author?.nullIfEmpty(),
chapters = chapters,
)
}

@ -34,10 +34,8 @@ internal class Pzykosis666hFansub(context: MangaLoaderContext) :
}
manga.copy(
coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl,
description = desc.orEmpty(),
altTitle = null,
author = author.orEmpty(),
state = null,
description = desc?.nullIfEmpty(),
author = author?.nullIfEmpty(),
chapters = chapters,
)
}

@ -34,10 +34,8 @@ internal class SeinagiAdulto(context: MangaLoaderContext) :
}
manga.copy(
coverUrl = doc.selectFirst(".thumbnail img")?.src().orEmpty(),// for manga result on search
description = desc.orEmpty(),
altTitle = null,
author = author.orEmpty(),
state = null,
description = desc?.nullIfEmpty(),
author = author?.nullIfEmpty(),
chapters = chapters,
)
}

@ -148,7 +148,7 @@ internal class BentomangaParser(context: MangaLoaderContext) :
val root = webClient.httpGet(mangaUrl).parseHtml()
.requireElementById("container_manga_show")
return manga.copy(
altTitle = root.selectFirst(".component-manga-title_alt")?.text(),
altTitle = root.selectFirst(".component-manga-title_alt")?.textOrNull(),
description = root.selectFirst(".datas_synopsis")?.html().assertNotNull("description")
?: manga.description,
state = when (root.selectFirst(".datas_more-status-data")?.textOrNull().assertNotNull("status")) {

@ -171,7 +171,6 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.FRENCH)
return manga.copy(
altTitle = null,
tags = root.select("div.serieGenre span").mapToSet { span ->
MangaTag(
key = span.text(),
@ -179,8 +178,8 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
source = source,
)
},
coverUrl = root.selectFirst("div.serieImg img")?.attr("src").orEmpty(),
author = root.select("div.serieAdd p:contains(Auteur:) strong").text(),
coverUrl = root.selectFirst("div.serieImg img")?.attr("src"),
author = root.select("div.serieAdd p:contains(Auteur:) strong").textOrNull(),
description = root.selectFirst("div.serieDescription div")?.html(),
chapters = root.select("div.chapterList a")
.mapChapters(reversed = true) { i, a ->

@ -87,7 +87,7 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context,
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE)
return manga.copy(
altTitle = root.select("ul.pmovie__list li:contains(Nom Alternatif:)").text()
.replace("Nom Alternatif:", ""),
.replace("Nom Alternatif:", "").nullIfEmpty(),
state = when (root.select("ul.pmovie__list li:contains(Status:)").text()) {
"Status: OnGoing", "Status: En cours" -> MangaState.ONGOING
"Status: Fini" -> MangaState.FINISHED
@ -97,11 +97,13 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context,
.replace("Genre:", "").split(" / ").mapToSet { tag ->
MangaTag(
key = tag.lowercase(),
title = tag,
title = tag.toTitleCase(sourceLocale),
source = source,
)
},
author = root.select("ul.pmovie__list li:contains(Artist(s):)").text().replace("Artist(s):", ""),
author = root.select("ul.pmovie__list li:contains(Artist(s):)").text()
.replace("Artist(s):", "")
.nullIfEmpty(),
description = root.selectFirst("div.pmovie__text")?.html(),
chapters = root.select("ul li div.chapter")
.mapChapters(reversed = true) { i, div ->

@ -10,6 +10,7 @@ import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.getFloatOrDefault
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import java.text.SimpleDateFormat
import java.util.*
@ -161,15 +162,14 @@ internal class LugnicaScans(context: MangaLoaderContext) :
val slug = manga.url.substringAfterLast("/")
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE)
return manga.copy(
altTitle = null,
state = when (jsonManga.getString("status")) {
"0" -> MangaState.ONGOING
"1" -> MangaState.FINISHED
"3" -> MangaState.ABANDONED
else -> null
},
author = jsonManga.getString("author"),
description = jsonManga.getString("description"),
author = jsonManga.getStringOrNull("author"),
description = jsonManga.getStringOrNull("description"),
chapters = chapters.mapChapters { i, it ->
val id = it.substringAfter("\"chapter\":").substringBefore(",")
val url = "https://$domain/api/get/chapter/$slug/$id"

@ -99,8 +99,8 @@ internal class MangaKawaii(context: MangaLoaderContext) : PagedMangaParser(conte
val firstChapter = doc.selectFirst("tr[class*='volume-'] a")?.attr("href")
val chaptersDeferred = async { loadChapters(firstChapter) }
manga.copy(
description = doc.selectFirst("dd.text-justify.text-break")?.text().orEmpty(),
altTitle = doc.select("span[itemprop*=alternativeHeadline]").joinToString { ", " },
description = doc.selectFirst("dd.text-justify.text-break")?.html(),
altTitle = doc.select("span[itemprop*=alternativeHeadline]").joinToString { ", " }.nullIfEmpty(),
author = doc.select("a[href*=author]").text(),
state = when (doc.selectFirst("span.badge.bg-success.text-uppercase")?.text()) {
"En Cours" -> MangaState.ONGOING

@ -113,7 +113,7 @@ internal class ScansMangasMe(context: MangaLoaderContext) :
val doc = webClient.httpGet(fullUrl).parseHtml()
val chaptersDeferred = getChapters(doc)
val desc = doc.selectFirstOrThrow("div.desc").html().nullIfEmpty()
val alt = doc.body().select("div.infox span.alter").text().nullIfEmpty()
val alt = doc.body().select("div.infox span.alter").textOrNull()
val aut = doc.select("div.spe span")[2].text().replace("Auteur:", "").nullIfEmpty()
manga.copy(
tags = doc.select("div.spe span:contains(Genres) a").mapToSet { a ->

@ -124,7 +124,7 @@ internal class ScantradUnion(context: MangaLoaderContext) :
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE)
return manga.copy(
altTitle = root.select(".divider2:contains(Noms associés :)").firstOrNull()?.text(),
altTitle = root.select(".divider2:contains(Noms associés :)").firstOrNull()?.textOrNull(),
state = when (root.select(".label.label-primary")[2].text()) {
"En cours" -> MangaState.ONGOING
"Terminé", "Abondonné", "One Shot" -> MangaState.FINISHED
@ -137,7 +137,7 @@ internal class ScantradUnion(context: MangaLoaderContext) :
source = source,
)
},
author = root.select("div.project-details a[href*=auteur]").text(),
author = root.select("div.project-details a[href*=auteur]").textOrNull(),
description = root.selectFirst("p.sContent")?.html(),
chapters = root.select("div.chapter-list li")
.mapChapters(reversed = true) { i, li ->

@ -183,7 +183,7 @@ internal abstract class FuzzyDoodleParser(
}
manga.copy(
altTitle = doc.selectLast(selectAltTitle)?.text(),
altTitle = doc.selectLast(selectAltTitle)?.textOrNull(),
state = when (doc.selectFirst(selectState)?.text()?.lowercase().orEmpty()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
@ -191,8 +191,8 @@ internal abstract class FuzzyDoodleParser(
in paused -> MangaState.PAUSED
else -> null
},
author = doc.selectFirst(selectAuthor)?.text().orEmpty(),
description = doc.select(selectDescription).text(),
author = doc.selectFirst(selectAuthor)?.textOrNull(),
description = doc.select(selectDescription).html(),
tags = doc.select(selectTagManga).mapToSet {
val key = it.attr("href").substringAfterLast('=')
MangaTag(

@ -89,7 +89,7 @@ internal abstract class HeanCmsAlt(
val doc = webClient.httpGet(fullUrl).parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return manga.copy(
altTitle = doc.selectFirst(selectAlt)?.text().orEmpty(),
altTitle = doc.selectFirst(selectAlt)?.textOrNull(),
description = doc.selectFirst(selectDesc)?.html(),
chapters = doc.select(selectChapter)
.mapChapters(reversed = true) { i, a ->

@ -25,7 +25,7 @@ internal class Brakeout(context: MangaLoaderContext) :
val doc = webClient.httpGet(fullUrl).parseHtml()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)
return manga.copy(
altTitle = doc.selectFirst(selectAlt)?.text().orEmpty(),
altTitle = doc.selectFirst(selectAlt)?.textOrNull(),
description = doc.selectFirstOrThrow(selectDesc).html(),
chapters = doc.select(selectChapter)
.mapChapters(reversed = true) { i, div ->

@ -96,9 +96,9 @@ internal class HentaiCrot(context: MangaLoaderContext) :
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
return manga.copy(
description = doc.selectFirst("div.entry-content p")?.text().orEmpty(),
altTitle = doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.text().orEmpty(),
author = doc.selectFirst("div.entry-content ul li:contains(Artists :) em")?.text().orEmpty(),
description = doc.selectFirst("div.entry-content p")?.html(),
altTitle = doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.textOrNull(),
author = doc.selectFirst("div.entry-content ul li:contains(Artists :) em")?.textOrNull(),
state = null,
chapters = listOf(
MangaChapter(

@ -96,9 +96,9 @@ internal class PixHentai(context: MangaLoaderContext) :
val fullUrl = manga.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml()
return manga.copy(
description = doc.selectFirst("div.entry-content p")?.text().orEmpty(),
altTitle = doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.text().orEmpty(),
author = doc.selectFirst("div.entry-content ul li:contains(Artists :) em")?.text().orEmpty(),
description = doc.selectFirst("div.entry-content p")?.html(),
altTitle = doc.selectFirst("div.entry-content ul li:contains(Alternative Name(s) :) em")?.textOrNull(),
author = doc.selectFirst("div.entry-content ul li:contains(Artists :) em")?.textOrNull(),
state = null,
chapters = listOf(
MangaChapter(

@ -150,8 +150,7 @@ internal abstract class LikeMangaParser(
}
}
return manga.copy(
altTitle = doc.selectFirstOrThrow(".list-info li.othername h2").text(),
state = null,
altTitle = doc.selectFirst(".list-info li.othername h2")?.textOrNull(),
tags = doc.select("li.kind a").mapToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
@ -159,8 +158,8 @@ internal abstract class LikeMangaParser(
source = source,
)
},
author = doc.select("li.author p").last()?.text(),
description = doc.requireElementById("summary_shortened").text(),
author = doc.selectLast("li.author p")?.textOrNull(),
description = doc.requireElementById("summary_shortened").html(),
chapters = run {
if (maxPageChapter == 1) {
parseChapters(doc)

@ -28,11 +28,11 @@ internal class MangasNoSekai(context: MangaLoaderContext) :
source = source,
)
},
author = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Autor)) p a")?.text()
.orEmpty(),
author = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Autor)) p a")
?.textOrNull(),
description = body.selectFirst("#section-sinopsis p")?.text().orEmpty(),
altTitle = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Otros nombres)) p")?.text()
.orEmpty(),
altTitle = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Otros nombres)) p")
?.textOrNull(),
state = body.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Estado)) p")
?.let {
when (it.text()) {

@ -186,8 +186,8 @@ internal abstract class MadthemeParser(
source = source,
)
},
description = desc.orEmpty(),
altTitle = alt.orEmpty(),
description = desc?.nullIfEmpty(),
altTitle = alt.nullIfEmpty(),
state = state,
chapters = chaptersDeferred.await(),
contentRating = if (nsfw || manga.isNsfw) {

@ -154,8 +154,8 @@ internal abstract class Manga18Parser(
else -> null
}
}
val alt = body.selectFirst(selectAlt)?.text().takeIf { it != "Updating" || it.isNotEmpty() }
val author = body.selectFirst(selectAuthor)?.text().takeIf { it != "Updating" }
val alt = body.selectFirst(selectAlt)?.textOrNull().takeUnless { it == "Updating" }
val author = body.selectFirst(selectAuthor)?.textOrNull()?.takeUnless { it == "Updating" }
manga.copy(
tags = doc.body().select(selectTag).mapToSet { a ->
MangaTag(
@ -164,7 +164,7 @@ internal abstract class Manga18Parser(
source = source,
)
},
description = desc.orEmpty(),
description = desc?.nullIfEmpty(),
altTitle = alt,
author = author,
state = state,

@ -107,7 +107,7 @@ internal abstract class MangAdventureParser(
.addEncodedQueryParameter("date_format", "timestamp").get()
return manga.copy(
description = details.getStringOrNull("description"),
altTitle = details.getJSONArray("aliases").joinToString(),
altTitle = details.getJSONArray("aliases").joinToString().nullIfEmpty(),
author = buildString {
val authors = details.getJSONArray("authors")
val artists = details.getJSONArray("artists")

@ -155,13 +155,13 @@ internal abstract class MangaWorldParser(
tags = tags,
author = div.selectFirst(".author a")?.text(),
state =
when (div.selectFirst(".status a")?.text()?.lowercase()) {
"in corso" -> MangaState.ONGOING
"finito" -> MangaState.FINISHED
"droppato" -> MangaState.ABANDONED
"in pausa" -> MangaState.PAUSED
else -> null
},
when (div.selectFirst(".status a")?.text()?.lowercase()) {
"in corso" -> MangaState.ONGOING
"finito" -> MangaState.FINISHED
"droppato" -> MangaState.ABANDONED
"in pausa" -> MangaState.PAUSED
else -> null
},
source = source,
isNsfw = isNsfwSource,
)
@ -184,30 +184,31 @@ internal abstract class MangaWorldParser(
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
return manga.copy(
altTitle =
doc.selectFirst(".meta-data .font-weight-bold:contains(Titoli alternativi:)")
?.parent()
?.ownText()
?.substringAfter(": ")
?.trim(),
doc.selectFirst(".meta-data .font-weight-bold:contains(Titoli alternativi:)")
?.parent()
?.ownText()
?.substringAfter(": ")
?.trim()
?.nullIfEmpty(),
description = doc.getElementById("noidungm")?.text().orEmpty(),
chapters =
doc.select(".chapters-wrapper .chapter a").mapChapters(reversed = true) { i, a ->
val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain)
MangaChapter(
id = generateUid(url),
name = a.selectFirst("span.d-inline-block")?.text() ?: "Chapter : ${i + 1f}",
number = i + 1f,
volume = 0,
url = "$url?style=list",
scanlator = null,
uploadDate =
SimpleDateFormat("dd MMMM yyyy", Locale.ITALIAN).tryParse(
a.selectFirst(".chap-date")?.text(),
),
branch = null,
source = source,
)
},
doc.select(".chapters-wrapper .chapter a").mapChapters(reversed = true) { i, a ->
val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain)
MangaChapter(
id = generateUid(url),
name = a.selectFirst("span.d-inline-block")?.text() ?: "Chapter : ${i + 1f}",
number = i + 1f,
volume = 0,
url = "$url?style=list",
scanlator = null,
uploadDate =
SimpleDateFormat("dd MMMM yyyy", Locale.ITALIAN).tryParse(
a.selectFirst(".chap-date")?.text(),
),
branch = null,
source = source,
)
},
)
}

@ -193,14 +193,14 @@ internal abstract class MmrcmsParser(
else -> null
}
}
val alt = doc.body().selectFirst(selectAlt)?.nextElementSibling()?.text()
val auth = doc.body().selectFirst(selectAut)?.nextElementSibling()?.text()
val alt = doc.body().selectFirst(selectAlt)?.nextElementSibling()?.textOrNull()
val auth = doc.body().selectFirst(selectAut)?.nextElementSibling()?.textOrNull()
val tags = doc.body().selectFirst(selectTag)?.nextElementSibling()?.select("a") ?: emptySet()
manga.copy(
tags = tags.mapToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
title = a.text().toTitleCase(),
title = a.text().toTitleCase(sourceLocale),
source = source,
)
},

@ -57,14 +57,14 @@ internal class Onma(context: MangaLoaderContext) :
else -> null
}
}
val alt = doc.body().selectFirst(selectAlt)?.text()
val auth = doc.body().selectFirst(selectAut)?.text()
val alt = doc.body().selectFirst(selectAlt)?.textOrNull()
val auth = doc.body().selectFirst(selectAut)?.textOrNull()
val tags = doc.body().selectFirst(selectTag)?.select("a") ?: emptySet()
manga.copy(
tags = tags.mapToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
title = a.text().toTitleCase(),
title = a.text().toTitleCase(sourceLocale),
source = source,
)
},

@ -184,7 +184,6 @@ internal abstract class NepnepParser(
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:SS", sourceLocale)
return manga.copy(
altTitle = null,
state = when (doc.selectFirstOrThrow(".list-group-item:contains(Status:) a").text()) {
"Ongoing (Scan)", "Ongoing (Publish)",
-> MangaState.ONGOING
@ -204,12 +203,12 @@ internal abstract class NepnepParser(
tags = doc.select(".list-group-item:contains(Genre(s):) a").mapToSet { a ->
MangaTag(
key = a.attr("href").substringAfterLast('='),
title = a.text(),
title = a.text().toTitleCase(sourceLocale),
source = source,
)
},
author = doc.select(".list-group-item:contains(Author(s):) a").text(),
description = doc.selectFirstOrThrow(".top-5.Content").text(),
author = doc.select(".list-group-item:contains(Author(s):) a").textOrNull(),
description = doc.selectFirstOrThrow(".top-5.Content").textOrNull(),
chapters = chapter.mapJSONIndexed { i, j ->
val indexChapter = j.getString("Chapter")!!

@ -159,8 +159,8 @@ internal abstract class OtakuSanctuaryParser(
}
}
val alt = doc.body().selectFirst(selectAlt)?.text()?.replace("Other names", "")
val auth = doc.body().selectFirst(selectAut)?.text()
val alt = doc.body().selectFirst(selectAlt)?.textOrNull()?.replace("Other names", "")?.nullIfEmpty()
val auth = doc.body().selectFirst(selectAut)?.textOrNull()
val dateFormat = SimpleDateFormat(datePattern, sourceLocale)

@ -122,8 +122,6 @@ internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context,
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
return manga.copy(
altTitle = null,
state = null,
tags = doc.select("div.serie-infos li:contains(Categorias:) a").mapToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),
@ -132,7 +130,7 @@ internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context,
)
},
author = doc.select("div.serie-infos li:contains(Autor:)").text().replace("Autor:", "").nullIfEmpty(),
description = doc.select(".serie-texto p").text(),
description = doc.select(".serie-texto p").html(),
contentRating = if (doc.select("div.serie-infos li:contains(Categorias:)").text().contains("Hentai")) {
ContentRating.ADULT
} else {

@ -7,6 +7,7 @@ import org.koitharu.kotatsu.parsers.SinglePageMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import java.text.DateFormat
import java.text.SimpleDateFormat
@ -105,9 +106,9 @@ internal class YugenMangas(context: MangaLoaderContext) :
return manga.copy(
description = detailManga.getString("synopsis"),
coverUrl = detailManga.getString("cover"),
altTitle = detailManga.getString("alternative_names"),
author = detailManga.getString("author"),
state = detailManga.getString("status")?.let {
altTitle = detailManga.getStringOrNull("alternative_names"),
author = detailManga.getStringOrNull("author"),
state = detailManga.getStringOrNull("status")?.let {
when (it) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED

@ -145,7 +145,7 @@ internal abstract class LibSocialParser(
}
manga.copy(
title = json.getStringOrNull("rus_name") ?: manga.title,
altTitle = json.getString("name"),
altTitle = json.getStringOrNull("name"),
tags = tagsSetOf(tags, genres),
author = json.getJSONArray("authors").optJSONObject(0)?.getStringOrNull("name"),
description = json.getString("summary").nl2br(),

@ -146,9 +146,9 @@ internal abstract class ScanParser(
?: RATING_UNKNOWN,
tags = tags,
author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div, .card-series-about .mb-3:contains(Autore) a")
?.text(),
altTitle = doc.selectFirst(".card div.col-12.mb-4 h2, .card-series-about .h6")?.text().orEmpty(),
description = doc.selectFirst(".card div.col-12.mb-4 p, .card-series-desc .mb-4 p")?.html().orEmpty(),
?.textOrNull(),
altTitle = 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(),
chapters = doc.select(".chapters-list .col-chapter, .card-list-chapter .col-chapter")
.mapChapters(reversed = true) { i, div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")

@ -25,9 +25,9 @@ internal class MangaFr(context: MangaLoaderContext) :
?: RATING_UNKNOWN,
tags = emptySet(),
author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div, .card-series-about .mb-3:contains(Autore) a")
?.text(),
altTitle = doc.selectFirst(".card div.col-12.mb-4 h2, .card-series-about .h6")?.text().orEmpty(),
description = doc.selectFirst(".card div.col-12.mb-4 p, .card-series-desc .mb-4 p")?.html().orEmpty(),
?.textOrNull(),
altTitle = 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(),
chapters = doc.select(".chapters-list .col-chapter, .card-list-chapter .col-chapter")
.mapChapters(reversed = true) { i, div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")

@ -27,9 +27,9 @@ internal class ScanIta(context: MangaLoaderContext) :
rating = doc.selectFirst(".card-series-detail .rate-value span")?.ownText()?.toFloatOrNull()?.div(5f)
?: RATING_UNKNOWN,
tags = tags,
author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div")?.text(),
altTitle = doc.selectFirst(".card div.col-12.mb-4 h2")?.text().orEmpty(),
description = doc.selectFirst(".card div.col-12.mb-4 p")?.html().orEmpty(),
author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div")?.textOrNull(),
altTitle = doc.selectFirst(".card div.col-12.mb-4 h2")?.textOrNull(),
description = doc.selectFirst(".card div.col-12.mb-4 p")?.html(),
chapters = chaptersDeferred.await(),
)
}

@ -64,15 +64,14 @@ internal class SadScans(context: MangaLoaderContext) : SinglePageMangaParser(con
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("dd MMM, yy", Locale.ENGLISH)
return manga.copy(
altTitle = null,
state = when (doc.select(".status span").last()?.text()) {
"Devam ediyor" -> MangaState.ONGOING
"Tamamlandı" -> MangaState.FINISHED
else -> null
},
tags = emptySet(),
author = doc.select(".author span").last()?.text(),
description = doc.selectFirstOrThrow(".summary").text(),
author = doc.selectLast(".author span")?.textOrNull(),
description = doc.selectFirstOrThrow(".summary").html(),
chapters = doc.select(".chap-section .chap")
.mapChapters(reversed = true) { i, div ->
val a = div.selectFirstOrThrow("a")

@ -112,8 +112,9 @@ internal class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context
val stateDoc = stateDocDeferred.await()
manga.copy(
altTitle = infoEl.selectFirst("span.info:contains(Tên Khác:)")?.parent()?.select("span:not(.info) > a")
?.joinToString { it.text() },
author = infoEl.select("p:contains(Tác giả:) a").text(),
?.joinToString { it.text() }
?.nullIfEmpty(),
author = infoEl.select("p:contains(Tác giả:) a").textOrNull(),
description = infoEl.select("p:contains(Nội dung:) + p").html(),
tags = tags,
state = stateDoc.select("p:contains(Tình Trạng:) a").firstOrNull()?.text()?.let {

@ -87,8 +87,8 @@ internal class SayHentai(context: MangaLoaderContext) : PagedMangaParser(context
override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
return manga.copy(
altTitle = doc.selectFirst("h2.other-name")?.text(),
author = doc.selectFirst("div.summary-heading:contains(Tác giả) + div.summary-content")?.text(),
altTitle = doc.selectFirst("h2.other-name")?.textOrNull(),
author = doc.selectFirst("div.summary-heading:contains(Tác giả) + div.summary-content")?.textOrNull(),
tags = doc.select("div.genres-content a[rel=tag]").mapToSet { a ->
MangaTag(
key = a.attr("href").substringAfterLast('/'),

@ -4,8 +4,8 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.*
@ -149,7 +149,7 @@ internal class TruyenGG(context: MangaLoaderContext) : PagedMangaParser(context,
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH)
return manga.copy(
altTitle = doc.selectFirst("h2.other-name")?.text(),
altTitle = doc.selectFirst("h2.other-name")?.textOrNull(),
author = doc.select("p:contains(Tác Giả) + p").joinToString { it.text() }.nullIfEmpty(),
tags = doc.select("a.clblue").mapToSet {
MangaTag(

@ -159,7 +159,7 @@ internal class TruyenQQ(context: MangaLoaderContext) : PagedMangaParser(context,
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH)
return manga.copy(
altTitle = doc.selectFirst("h2.other-name")?.text(),
altTitle = doc.selectFirst("h2.other-name")?.textOrNull(),
tags = doc.select("ul.list01 li").mapToSet {
val key = it.attr("href").substringAfterLast("-").substringBeforeLast(".")
MangaTag(

@ -119,10 +119,6 @@ internal abstract class VmpParser(
source = source,
)
},
description = null,
altTitle = null,
author = null,
state = null,
chapters = listOf(
MangaChapter(
id = manga.id,

@ -216,9 +216,9 @@ internal abstract class WpComicsParser(
val tagsElement = doc.select("li.kind p.col-xs-8 a")
val mangaTags = tagsElement.mapNotNullToSet { tagMap[it.text()] }
manga.copy(
description = doc.selectFirst(selectDesc)?.html().orEmpty(),
altTitle = doc.selectFirst("h2.other-name")?.text().orEmpty(),
author = doc.body().select(selectAut).text(),
description = doc.selectFirst(selectDesc)?.html(),
altTitle = doc.selectFirst("h2.other-name")?.textOrNull(),
author = doc.body().select(selectAut).textOrNull(),
state = doc.selectFirst(selectState)?.let {
when (it.text()) {
in ongoing -> MangaState.ONGOING

@ -128,7 +128,7 @@ internal class XoxoComics(context: MangaLoaderContext) :
else -> null
}
}
val aut = doc.body().select(selectAut).text()
val aut = doc.body().select(selectAut).textOrNull()
manga.copy(
tags = doc.body().select(selectTag).mapToSet { a ->
MangaTag(
@ -138,7 +138,6 @@ internal class XoxoComics(context: MangaLoaderContext) :
)
},
description = desc,
altTitle = null,
author = aut,
state = state,
chapters = chaptersDeferred.await(),

@ -1,29 +1,23 @@
package org.koitharu.kotatsu.parsers.site.wpcomics.vi
import androidx.collection.ArrayMap
import androidx.collection.ArraySet
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN
import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
@MangaSourceParser("NETTRUYEN", "NetTruyen", "vi")
internal class NetTruyen(context: MangaLoaderContext) :
WpComicsParser(context, MangaParserSource.NETTRUYEN, "nettruyenrr.com", 44) {
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("nettruyenrr.com", "nettruyenww.com", "nettruyenx.com")
override val configKeyDomain: ConfigKey.Domain =
ConfigKey.Domain("nettruyenrr.com", "nettruyenww.com", "nettruyenx.com")
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain)
@ -33,9 +27,9 @@ internal class NetTruyen(context: MangaLoaderContext) :
val tagsElement = doc.select("li.kind p.col-xs-8 a")
val mangaTags = tagsElement.mapNotNullToSet { tagMap[it.text()] }
manga.copy(
description = doc.selectFirst(selectDesc)?.html().orEmpty(),
altTitle = doc.selectFirst("h2.other-name")?.text().orEmpty(),
author = doc.body().select(selectAut).text(),
description = doc.selectFirst(selectDesc)?.html(),
altTitle = doc.selectFirst("h2.other-name")?.textOrNull(),
author = doc.body().select(selectAut).textOrNull(),
state = doc.selectFirst(selectState)?.let {
when (it.text()) {
in ongoing -> MangaState.ONGOING

@ -129,6 +129,8 @@ public fun Element.selectLastOrThrow(cssQuery: String): Element = parseNotNull(s
public fun Element.textOrNull(): String? = text().nullIfEmpty()
public fun Elements.textOrNull(): String? = text().nullIfEmpty()
public fun Element.ownTextOrNull(): String? = ownText().nullIfEmpty()
public fun Element.selectFirstParent(query: String): Element? {

Loading…
Cancel
Save