Fix nullable strings usage
This commit is contained in:
@@ -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? {
|
||||
|
||||
Reference in New Issue
Block a user