diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Manga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Manga.kt index ec834042..9863b7be 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Manga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Manga.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.model import androidx.collection.ArrayMap import org.koitharu.kotatsu.parsers.util.findById +import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.nullIfEmpty public data class Manga constructor( @@ -49,9 +50,9 @@ public data class Manga constructor( */ @JvmField public val state: MangaState?, /** - * Author of the manga, may be null + * Authors of the manga */ - @JvmField public val author: String?, + @JvmField public val authors: Set, /** * Large cover url (absolute), null if is no large cover * @see coverUrl @@ -70,41 +71,12 @@ public data class Manga constructor( */ @JvmField public val source: MangaSource, ) { - - @Deprecated("Prefer constructor with contentRating instead of isNsfw") - public constructor( - id: Long, - title: String, - altTitle: String?, - url: String, - publicUrl: String, - rating: Float, - isNsfw: Boolean, - coverUrl: String?, - tags: Set, - state: MangaState?, - author: String?, - largeCoverUrl: String? = null, - description: String? = null, - chapters: List? = null, - source: MangaSource, - ) : this( - id = id, - title = title, - altTitle = altTitle?.nullIfEmpty(), - url = url, - publicUrl = publicUrl, - rating = rating, - contentRating = if (isNsfw) ContentRating.ADULT else null, - coverUrl = coverUrl?.nullIfEmpty(), - tags = tags, - state = state, - author = author?.nullIfEmpty(), - largeCoverUrl = largeCoverUrl?.nullIfEmpty(), - description = description?.nullIfEmpty(), - chapters = chapters, - source = source, - ) + /** + * Author of the manga, may be null + */ + @Deprecated("Please use authors") + public val author: String? + get() = authors.firstOrNull() /** * Return if manga has a specified rating diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/BatoToParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/BatoToParser.kt index 555757f5..4b50a373 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/BatoToParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/BatoToParser.kt @@ -214,6 +214,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser( val attrs = details.selectFirst(".attr-main")?.select(".attr-item")?.associate { it.child(0).text() to it.child(1) }.orEmpty() + val author = attrs["Authors:"]?.textOrNull() return manga.copy( title = root.selectFirst("h3.item-title")?.text() ?: manga.title, contentRating = if (root.selectFirst("alert")?.getElementsContainingOwnText("NSFW").isNullOrEmpty()) { @@ -233,7 +234,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser( "Hiatus" -> MangaState.PAUSED else -> manga.state }, - author = attrs["Authors:"]?.textOrNull() ?: manga.author, + authors = author?.let { setOf(it) } ?: manga.authors, chapters = root.selectFirst(".episode-list") ?.selectFirst(".main") ?.children() @@ -337,13 +338,13 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser( url = href, publicUrl = a.absUrl("href"), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirst("img[src]")?.absUrl("src"), largeCoverUrl = null, description = null, tags = div.selectFirst(".item-genre")?.parseTags().orEmpty(), state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt index 71be24b2..2a454e06 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt @@ -168,7 +168,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : 4 -> MangaState.PAUSED else -> null }, - author = null, + authors = emptySet(), source = source, ) } @@ -182,6 +182,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : val alt = comic.getJSONArray("md_titles").asTypedList().joinToString("\n") { it.getStringOrNull("title").orEmpty() } + val author = jo.getJSONArray("artists").optJSONObject(0)?.getStringOrNull("name") return manga.copy( altTitle = alt.nullIfEmpty(), contentRating = if (jo.getBooleanOrDefault("matureContent", false) @@ -200,7 +201,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : source = source, ) }, - author = jo.getJSONArray("artists").optJSONObject(0)?.getStringOrNull("name"), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = getChapters(comic.getString("hid")), ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ExHentaiParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ExHentaiParser.kt index 4d007e6d..3f76ebc4 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ExHentaiParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ExHentaiParser.kt @@ -168,6 +168,8 @@ internal class ExHentaiParser( val href = a.attrAsRelativeUrl("href") val tagsDiv = gLink.nextElementSibling() ?: gLink.parseFailed("tags div not found") val rawTitle = gLink.text() + val author = tagsDiv.getElementsContainingOwnText("artist:").first() + ?.nextElementSibling()?.textOrNull() Manga( id = generateUid(href), title = rawTitle.cleanupTitle(), @@ -182,8 +184,7 @@ internal class ExHentaiParser( rawTitle.contains("(ongoing)", ignoreCase = true) -> MangaState.ONGOING else -> null }, - author = tagsDiv.getElementsContainingOwnText("artist:").first() - ?.nextElementSibling()?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/HitomiLaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/HitomiLaParser.kt index 6d5b4193..59781388 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/HitomiLaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/HitomiLaParser.kt @@ -524,9 +524,9 @@ internal class HitomiLaParser(context: MangaLoaderContext) : MangaParser(context doc.selectFirstOrThrow("h1 > a") .attrAsRelativeUrl("href") .toAbsoluteUrl(domain), - author = null, + authors = emptySet(), tags = emptySet(), - isNsfw = true, + contentRating = ContentRating.ADULT, rating = RATING_UNKNOWN, altTitle = null, state = null, @@ -542,6 +542,10 @@ internal class HitomiLaParser(context: MangaLoaderContext) : MangaParser(context .parseRaw() .substringAfter("var galleryinfo = ") .let(::JSONObject) + val author = + json.optJSONArray("artists") + ?.mapJSON { it.getString("artist").toCamelCase() } + ?.joinToString() return manga.copy( title = json.getString("title"), @@ -554,10 +558,7 @@ internal class HitomiLaParser(context: MangaLoaderContext) : MangaParser(context "https://${getDomain("${subDomain}a")}/webp/$commonId$imageId/$hash.webp" }, - author = - json.optJSONArray("artists") - ?.mapJSON { it.getString("artist").toCamelCase() } - ?.joinToString(), + authors = author?.let { setOf(it) } ?: emptySet(), publicUrl = json.getString("galleryurl").toAbsoluteUrl(domain), tags = buildSet { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt index 8622c996..4f7fc69d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ImHentai.kt @@ -125,10 +125,10 @@ internal class ImHentai(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -161,6 +161,7 @@ internal class ImHentai(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga = coroutineScope { val fullUrl = manga.url.toAbsoluteUrl(domain) val doc = webClient.httpGet(fullUrl).parseHtml() + val author = doc.selectFirst("li:contains(Artists) a.tag")?.ownTextOrNull() manga.copy( tags = doc.body().select("li:contains(Tags) a.tag").mapNotNullToSet { val href = it.attr("href").substringAfterLast("tag/").substringBeforeLast('/') @@ -170,7 +171,7 @@ internal class ImHentai(context: MangaLoaderContext) : source = source, ) }, - author = doc.selectFirst("li:contains(Artists) a.tag")?.ownTextOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = listOf( MangaChapter( id = manga.id, @@ -202,10 +203,10 @@ internal class ImHentai(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = false, + contentRating = null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt index 492dc44b..6448e8fa 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/LineWebtoonsParser.kt @@ -121,6 +121,8 @@ internal abstract class LineWebtoonsParser( makeRequest("/lineWebtoon/webtoon/challengeTitleInfo.json?v=2&titleNo=${titleNo}") .getJSONObject("titleInfo") .let { jo -> + val isNsfwSource = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource) + val author = jo.getStringOrNull("writingAuthorName") Manga( id = generateUid(titleNo), title = jo.getString("title"), @@ -128,11 +130,11 @@ internal abstract class LineWebtoonsParser( url = "$titleNo", publicUrl = "https://$domain/$languageCode/canvas/a/list?title_no=${titleNo}", rating = jo.getFloatOrDefault("starScoreAverage", -10f) / 10f, - isNsfw = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain), tags = setOf(parseTag(jo.getJSONObject("genreInfo"))), - author = jo.getStringOrNull("writingAuthorName"), + authors = author?.let { setOf(it) } ?: emptySet(), description = jo.getString("synopsis"), // I don't think the API provides this info state = null, @@ -150,6 +152,7 @@ internal abstract class LineWebtoonsParser( .getJSONArray("titleList") .mapJSON { jo -> val titleNo = jo.getLong("titleNo") + val author = jo.getStringOrNull("writingAuthorName") Manga( id = generateUid(titleNo), @@ -158,11 +161,11 @@ internal abstract class LineWebtoonsParser( url = titleNo.toString(), publicUrl = "https://$domain/$languageCode/canvas/a/list?title_no=$titleNo", rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), largeCoverUrl = null, tags = emptySet(), - author = jo.getStringOrNull("writingAuthorName"), + authors = author?.let { setOf(it) } ?: emptySet(), description = null, state = null, source = source, @@ -194,6 +197,8 @@ internal abstract class LineWebtoonsParser( .getJSONArray("titles") .mapJSON { jo -> val titleNo = jo.getLong("titleNo") + val isNsfwSource = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource) + val author = jo.getStringOrNull("writingAuthorName") Manga( id = generateUid(titleNo), @@ -202,11 +207,11 @@ internal abstract class LineWebtoonsParser( url = titleNo.toString(), publicUrl = "https://$domain/$languageCode/canvas/a/list?title_no=$titleNo", rating = jo.getFloatOrDefault("starScoreAverage", -10f) / 10f, - isNsfw = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain), tags = setOfNotNull(genres[jo.getString("representGenre")]), - author = jo.getStringOrNull("writingAuthorName"), + authors = author?.let { setOf(it) } ?: emptySet(), description = jo.getString("synopsis"), // I don't think the API provides this info state = null, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt index 002f1a58..5b5f8432 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt @@ -287,6 +287,9 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context ?.let { "https://uploads.$domain/covers/$id/$it" } + val author = (relations["author"] ?: relations["artist"]) + ?.getJSONObject("attributes") + ?.getStringOrNull("name") return Manga( id = generateUid(id), title = requireNotNull(attrs.getJSONObject("title").selectByLocale()) { @@ -322,9 +325,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context "cancelled" -> MangaState.ABANDONED else -> null }, - author = (relations["author"] ?: relations["artist"]) - ?.getJSONObject("attributes") - ?.getStringOrNull("name"), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = chapters, source = source, ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaFireParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaFireParser.kt index 84e36a6e..92444c16 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaFireParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaFireParser.kt @@ -165,7 +165,7 @@ internal abstract class MangaFireParser( source = source, altTitle = null, largeCoverUrl = null, - author = null, + authors = emptySet(), contentRating = null, rating = RATING_UNKNOWN, state = null, @@ -179,6 +179,8 @@ internal abstract class MangaFireParser( val availableTags = tags.get() var isAdult = false var isSuggestive = false + val author = document.select("div.meta a[href*=/author/]") + .joinToString { it.ownText() }.nullIfEmpty() return manga.copy( title = document.selectFirstOrThrow(".info > h1").ownText(), @@ -211,8 +213,7 @@ internal abstract class MangaFireParser( else -> null } }, - author = document.select("div.meta a[href*=/author/]") - .joinToString { it.ownText() }.nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), description = document.selectFirstOrThrow("#synopsis div.modal-content").html(), chapters = getChapters(manga.url, document), ) @@ -332,7 +333,7 @@ internal abstract class MangaFireParser( source = source, altTitle = null, largeCoverUrl = null, - author = null, + authors = emptySet(), contentRating = null, rating = RATING_UNKNOWN, state = null, @@ -355,7 +356,7 @@ internal abstract class MangaFireParser( source = source, altTitle = null, largeCoverUrl = null, - author = null, + authors = emptySet(), contentRating = null, rating = RATING_UNKNOWN, state = null, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPark.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPark.kt index c23bff75..552f7004 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPark.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPark.kt @@ -160,10 +160,10 @@ internal class MangaPark(context: MangaLoaderContext) : altTitle = null, rating = div.selectFirst("span.text-yellow-500")?.text()?.toFloatOrNull()?.div(10F) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -193,9 +193,10 @@ internal class MangaPark(context: MangaLoaderContext) : val tags = selectTag.mapNotNullToSet { tagMap[it.text()] } val nsfw = tags.any { t -> t.key == "hentai" || t.key == "adult" } val dateFormat = SimpleDateFormat("dd/MM/yyyy", sourceLocale) + val author = doc.selectFirst("div[q:key=tz_4]")?.textOrNull() manga.copy( altTitle = doc.selectFirst("div[q:key=tz_2]")?.textOrNull(), - author = doc.selectFirst("div[q:key=tz_4]")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirst("react-island[q:key=0a_9]")?.html(), state = when (doc.selectFirst("span[q:key=Yn_5]")?.text()?.lowercase()) { "ongoing" -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt index 76f2f094..d21c1842 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaPlusParser.kt @@ -122,8 +122,8 @@ internal abstract class MangaPlusParser( title = name, coverUrl = it.getString("portraitImageUrl"), altTitle = null, - author = author, - isNsfw = false, + authors = setOf(author), + contentRating = null, rating = RATING_UNKNOWN, state = null, source = source, @@ -143,13 +143,14 @@ internal abstract class MangaPlusParser( } val hiatus = json.getStringOrNull("nonAppearanceInfo")?.contains("on a hiatus") == true + val author = title.getString("author") + .split("/").joinToString(transform = String::trim) return manga.copy( title = title.getString("name"), publicUrl = "/titles/${title.getInt("titleId")}".toAbsoluteUrl(domain), coverUrl = title.getString("portraitImageUrl"), - author = title.getString("author") - .split("/").joinToString(transform = String::trim), + authors = setOf(author), description = buildString { json.getString("overview").let(::append) json.getStringOrNull("viewingPeriodDescription") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt index 28e7b052..feb9d46d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaReaderToParser.kt @@ -132,8 +132,8 @@ internal class MangaReaderToParser(context: MangaLoaderContext) : coverUrl = thumb.attr("src"), source = source, altTitle = null, - author = null, - isNsfw = false, + authors = emptySet(), + contentRating = null, rating = RATING_UNKNOWN, state = null, tags = emptySet(), @@ -155,7 +155,7 @@ internal class MangaReaderToParser(context: MangaLoaderContext) : coverUrl = thumb.attrAsAbsoluteUrlOrNull("src"), source = source, altTitle = null, - author = null, + authors = emptySet(), contentRating = null, rating = RATING_UNKNOWN, state = null, @@ -169,6 +169,8 @@ internal class MangaReaderToParser(context: MangaLoaderContext) : val availableTags = tags.get() var isAdult = false var isSuggestive = false + val author = document.select("div.anisc-info a[href*=/author/]") + .joinToString { it.ownText().replace(", ", " ") }.nullIfEmpty() return manga.copy( title = document.selectFirst("h2.manga-name")!!.ownText(), @@ -201,8 +203,7 @@ internal class MangaReaderToParser(context: MangaLoaderContext) : else -> null } }, - author = document.select("div.anisc-info a[href*=/author/]") - .joinToString { it.ownText().replace(", ", " ") }.nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), description = document.select("div.description").html(), chapters = parseChapters(document), source = source, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt index 370ac47c..89cb284f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt @@ -116,8 +116,8 @@ internal abstract class NineMangaParser( altTitle = null, coverUrl = node.selectFirst("img")?.src(), rating = RATING_UNKNOWN, - author = null, - isNsfw = false, + authors = emptySet(), + contentRating = null, tags = emptySet(), state = null, source = source, @@ -135,11 +135,12 @@ internal abstract class NineMangaParser( val tagMap = getOrCreateTagMap() val selectTag = infoRoot.getElementsByAttributeValue("itemprop", "genre").first()?.select("a") val tags = selectTag?.mapNotNullToSet { tagMap[it.text()] } + val author = infoRoot.getElementsByAttributeValue("itemprop", "author").first()?.textOrNull() return manga.copy( title = root.selectFirst("h1[itemprop=name]")?.textOrNull()?.removeSuffix("Manga")?.trimEnd() ?: manga.title, tags = tags.orEmpty(), - author = infoRoot.getElementsByAttributeValue("itemprop", "author").first()?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = parseStatus(infoRoot.select("li a.red").text()), description = infoRoot.getElementsByAttributeValue("itemprop", "description").first()?.html() ?.substringAfter(""), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt index 5d8f330b..379e6a25 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineNineNineHentaiParser.kt @@ -206,7 +206,7 @@ internal class NineNineNineHentaiParser(context: MangaLoaderContext) : cover == null -> null else -> "https://${cdnHost.get()}/$cover" }, - author = null, + authors = emptySet(), contentRating = ContentRating.ADULT, url = id, publicUrl = "/hchapter/$id".toAbsoluteUrl(domain), @@ -264,12 +264,13 @@ internal class NineNineNineHentaiParser(context: MangaLoaderContext) : type = it.getStringOrNull("tagType"), ) } + val author = tags?.filter { it.type == "artist" }?.joinToString { it.name.toCamelCase() }?.nullIfEmpty() return manga.copy( title = name.replace(shortenTitleRegex, "").trim(), altTitle = name, coverUrl = cover.first, largeCoverUrl = cover.second, - author = tags?.filter { it.type == "artist" }?.joinToString { it.name.toCamelCase() }?.nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), contentRating = ContentRating.ADULT, tags = tags?.mapToSet { MangaTag( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/WebtoonsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/WebtoonsParser.kt index 9e881508..da0313b2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/WebtoonsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/WebtoonsParser.kt @@ -123,6 +123,8 @@ internal abstract class WebtoonsParser( val chapters = chaptersDeferred.await() makeRequest("/lineWebtoon/webtoon/titleInfo.json?titleNo=${titleNo}&anyServiceStatus=false").getJSONObject("titleInfo") .let { jo -> + val isNsfwSource = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource) + val author = jo.getStringOrNull("writingAuthorName") MangaWebtoon( Manga( id = generateUid(titleNo), @@ -131,11 +133,11 @@ internal abstract class WebtoonsParser( url = "$titleNo", publicUrl = "https://$domain/$languageCode/originals/a/list?title_no=${titleNo}", rating = jo.getFloatOrDefault("starScoreAverage", -10f) / 10f, - isNsfw = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), largeCoverUrl = jo.getStringOrNull("thumbnailVertical")?.toAbsoluteUrl(staticDomain), tags = setOf(parseTag(jo.getJSONObject("genreInfo"))), - author = jo.getStringOrNull("writingAuthorName"), + authors = author?.let { setOf(it) } ?: emptySet(), description = jo.getString("synopsis"), // I don't think the API provides this info, state = null, @@ -158,6 +160,8 @@ internal abstract class WebtoonsParser( makeRequest("/lineWebtoon/webtoon/titleList.json?").getJSONObject("titleList").getJSONArray("titles") .mapJSON { jo -> val titleNo = jo.getLong("titleNo") + val isNsfwSource = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource) + val author = jo.getStringOrNull("writingAuthorName") MangaWebtoon( Manga( id = generateUid(titleNo), @@ -166,8 +170,8 @@ internal abstract class WebtoonsParser( title = jo.getString("title"), coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), altTitle = null, - author = jo.getStringOrNull("writingAuthorName"), - isNsfw = jo.getBooleanOrDefault("ageGradeNotice", isNsfwSource), + authors = author?.let { setOf(it) } ?: emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, rating = jo.getFloatOrDefault("starScoreAverage", -10f) / 10f, tags = setOfNotNull(allGenreCache.get()[jo.getString("representGenre")]), description = jo.getString("synopsis"), @@ -196,6 +200,7 @@ internal abstract class WebtoonsParser( makeRequest("/lineWebtoon/webtoon/searchWebtoon?query=${filter.query.urlEncoded()}").getJSONObject("webtoonSearch") .getJSONArray("titleList").mapJSON { jo -> val titleNo = jo.getLong("titleNo") + val author = jo.getStringOrNull("writingAuthorName") MangaWebtoon( Manga( id = generateUid(titleNo), @@ -204,11 +209,11 @@ internal abstract class WebtoonsParser( url = titleNo.toString(), publicUrl = "https://$domain/$languageCode/originals/a/list?title_no=$titleNo", rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = jo.getString("thumbnail").toAbsoluteUrl(staticDomain), largeCoverUrl = null, tags = emptySet(), - author = jo.getStringOrNull("writingAuthorName"), + authors = author?.let { setOf(it) } ?: emptySet(), description = null, state = null, source = source, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/AnimeBootstrapParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/AnimeBootstrapParser.kt index 083b1858..690e6ac2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/AnimeBootstrapParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/AnimeBootstrapParser.kt @@ -110,10 +110,10 @@ internal abstract class AnimeBootstrapParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/fr/PapScan.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/fr/PapScan.kt index 17575dc1..524c47ed 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/fr/PapScan.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/animebootstrap/fr/PapScan.kt @@ -72,10 +72,10 @@ internal class PapScan(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/FlixScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/FlixScans.kt index f0e92ddb..6123324e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/FlixScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/FlixScans.kt @@ -112,7 +112,7 @@ internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = cover, tags = emptySet(), state = when (j.getString("status")) { @@ -122,7 +122,7 @@ internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context "droped" -> MangaState.ABANDONED else -> null }, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/MangaStorm.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/MangaStorm.kt index 9e6c410f..2380610b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/MangaStorm.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/MangaStorm.kt @@ -74,11 +74,11 @@ internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(contex url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/TeamXNovel.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/TeamXNovel.kt index 838fef71..6fa4d04a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/TeamXNovel.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ar/TeamXNovel.kt @@ -108,7 +108,7 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").src()?.replace("thumbnail_", ""), tags = emptySet(), state = when (div.selectFirst(".status")?.text()) { @@ -117,7 +117,7 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex "متوقف" -> MangaState.ABANDONED else -> null }, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt index 04459d4a..681e6175 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/be/AnibelParser.kt @@ -90,8 +90,8 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context, coverUrl = jo.getString("poster").removePrefix("/cdn") .toAbsoluteUrl(getDomain("cdn")) + "?width=200&height=280", altTitle = title.optJSONArray("alt")?.optString(0)?.nullIfEmpty(), - author = null, - isNsfw = false, + authors = emptySet(), + contentRating = null, rating = jo.getDouble("rating").toFloat() / 10f, url = href, publicUrl = "https://${domain}/$href", @@ -237,8 +237,8 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context, coverUrl = jo.getString("poster").removePrefix("/cdn") .toAbsoluteUrl(getDomain("cdn")) + "?width=200&height=280", altTitle = title.getString("en").nullIfEmpty(), - author = null, - isNsfw = false, + authors = emptySet(), + contentRating = null, rating = RATING_UNKNOWN, url = href, publicUrl = "https://${domain}/$href", diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/cupfox/CupFoxParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/cupfox/CupFoxParser.kt index 95b362d4..5890f334 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/cupfox/CupFoxParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/cupfox/CupFoxParser.kt @@ -99,11 +99,11 @@ internal abstract class CupFoxParser( url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = li.selectFirst(selectMangasCover)?.src(), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -122,6 +122,7 @@ internal abstract class CupFoxParser( override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst(selectMangaDetailsAuthor)?.text()?.substringAfter(":")?.nullIfEmpty() return manga.copy( altTitle = doc.selectFirst(selectMangaDetailsAltTitle)?.text()?.substringAfter(":")?.nullIfEmpty(), tags = doc.select(selectMangaDetailsTags).mapToSet { a -> @@ -131,7 +132,7 @@ internal abstract class CupFoxParser( source = source, ) }, - author = doc.selectFirst(selectMangaDetailsAuthor)?.text()?.substringAfter(":")?.nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirst(selectMangaDescription)?.html(), chapters = doc.select(selectMangaChapters) .mapChapters { i, li -> @@ -164,11 +165,11 @@ internal abstract class CupFoxParser( url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = li.selectFirst(selectMangasCover)?.src(), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt index ad7208ad..1af43353 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/AsuraScansParser.kt @@ -116,7 +116,7 @@ internal class AsuraScansParser(context: MangaLoaderContext) : altTitle = null, rating = a.selectFirst("div.block label.ml-1")?.text()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = when (a.selectLast("span.status")?.text()) { "Ongoing" -> MangaState.ONGOING "Completed" -> MangaState.FINISHED @@ -126,7 +126,7 @@ internal class AsuraScansParser(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -159,10 +159,11 @@ internal class AsuraScansParser(context: MangaLoaderContext) : val tagMap = getOrCreateTagMap() val selectTag = doc.select("div[class^=space] > div.flex > button.text-white") val tags = selectTag.mapNotNullToSet { tagMap[it.text()] } + val author = doc.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Author)) > h3:eq(1)")?.text().orEmpty() return manga.copy( description = doc.selectFirst("span.font-medium.text-sm")?.text().orEmpty(), tags = tags, - author = doc.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Author)) > h3:eq(1)")?.text().orEmpty(), + authors = setOf(author), chapters = doc.select("div.scrollbar-thumb-themecolor > div.group").mapChapters(reversed = true) { i, div -> val a = div.selectLastOrThrow("a") val urlRelative = "/series/" + a.attrAsRelativeUrl("href") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/BeeToon.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/BeeToon.kt index 02139da4..8f27ab2a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/BeeToon.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/BeeToon.kt @@ -78,14 +78,14 @@ internal class BeeToon(context: MangaLoaderContext) : altTitle = null, rating = div.selectFirst(".counter")?.text()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = when (div.selectLastOrThrow(".status span").text()) { "Ongoing" -> MangaState.ONGOING "Completed" -> MangaState.FINISHED else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -103,6 +103,7 @@ internal class BeeToon(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst(".info .author a")?.text() return manga.copy( description = doc.getElementById("desc")?.text().orEmpty(), rating = doc.selectFirst(".counter")?.text()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, @@ -113,7 +114,7 @@ internal class BeeToon(context: MangaLoaderContext) : source = source, ) }, - author = doc.selectFirst(".info .author a")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = doc.select(".items-chapters a").mapChapters(reversed = true) { i, a -> val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain) MangaChapter( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/CloneMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/CloneMangaParser.kt index 1505eb1a..0223c86f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/CloneMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/CloneMangaParser.kt @@ -39,10 +39,10 @@ internal class CloneMangaParser(context: MangaLoaderContext) : title = item.selectFirst("h3")?.text() ?: return@mapNotNull null, coverUrl = "https://$domain/$cover", altTitle = null, - author = "Dan Kim", + authors = setOf("Dan Kim"), rating = RATING_UNKNOWN, url = href, - isNsfw = false, + contentRating = null, tags = emptySet(), state = null, publicUrl = href.toAbsoluteUrl(domain), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ComicExtra.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ComicExtra.kt index 99fc790b..ecc5f14b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ComicExtra.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ComicExtra.kt @@ -74,7 +74,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").attrAsAbsoluteUrl("src"), tags = div.select("div.egb-details a").mapToSet { a -> MangaTag( @@ -84,7 +84,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex ) }, state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -103,6 +103,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst("table.full-table tr:contains(Author:) td:nth-child(2)")?.textOrNull() return manga.copy( altTitle = doc.selectFirstOrThrow("div.anime-top h1.title").textOrNull(), state = when (doc.selectFirstOrThrow("ul.anime-genres li.status a").text()) { @@ -117,7 +118,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex source = source, ) }, - author = doc.selectFirst("table.full-table tr:contains(Author:) td:nth-child(2)")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirstOrThrow("div.detail-desc-content p").html(), chapters = doc.select("ul.basic-list li").let { elements -> elements.mapChapters { i, li -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/DynastyScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/DynastyScans.kt index 307cba23..97fa2bb9 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/DynastyScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/DynastyScans.kt @@ -90,11 +90,11 @@ internal class DynastyScans(context: MangaLoaderContext) : url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").attrAsAbsoluteUrl("src"), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -111,7 +111,7 @@ internal class DynastyScans(context: MangaLoaderContext) : url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = null, tags = div.select("span.tags a").mapToSet { a -> MangaTag( @@ -121,7 +121,7 @@ internal class DynastyScans(context: MangaLoaderContext) : ) }, state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlameComics.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlameComics.kt index 1d918536..67a15764 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlameComics.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlameComics.kt @@ -128,6 +128,7 @@ internal class FlameComics(context: MangaLoaderContext) : private fun parseManga(jo: JSONObject): Manga { val seriesId = jo.getLong("series_id") val cover = jo.getStringOrNull("cover") + val author = jo.getStringOrNull("author") return Manga( id = generateUid(seriesId), title = jo.getString("title"), @@ -137,7 +138,7 @@ internal class FlameComics(context: MangaLoaderContext) : url = seriesId.toString(), publicUrl = "https://${domain}/series/$seriesId", rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = if (cover != null) { imageUrl(seriesId, cover, 256) } else { @@ -153,7 +154,7 @@ internal class FlameComics(context: MangaLoaderContext) : "Ongoing" -> MangaState.ONGOING else -> null }, - author = jo.getStringOrNull("author"), + authors = author?.let { setOf(it) } ?: emptySet(), largeCoverUrl = if (cover != null) { imageUrl(seriesId, cover, 640) } else { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt index 7f2c8966..d7257f45 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/FlixScansOrg.kt @@ -91,7 +91,7 @@ internal class FlixScansOrg(context: MangaLoaderContext) : url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = cover, tags = emptySet(), state = when (j.getString("status")) { @@ -101,7 +101,7 @@ internal class FlixScansOrg(context: MangaLoaderContext) : "droped" -> MangaState.ABANDONED else -> null }, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaGeko.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaGeko.kt index 0a51a07a..a44db7e2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaGeko.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaGeko.kt @@ -77,6 +77,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context val doc = webClient.httpGet(url).parseHtml() return doc.select("li.novel-item").map { div -> val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") + val author = div.selectFirstOrThrow("h6").text().removePrefix("Author(S): ").nullIfEmpty() Manga( id = generateUid(href), title = div.selectFirstOrThrow("h4").text(), @@ -84,11 +85,11 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").src(), tags = emptySet(), state = null, - author = div.selectFirstOrThrow("h6").text().removePrefix("Author(S): ").nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), source = source, ) } @@ -108,6 +109,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context override suspend fun getDetails(manga: Manga): Manga = coroutineScope { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val chaptersDeferred = async { loadChapters(manga.url) } + val author = doc.selectFirstOrThrow(".author").textOrNull() manga.copy( altTitle = doc.selectFirstOrThrow(".alternative-title").textOrNull(), state = when (doc.selectFirstOrThrow(".header-stats span:contains(Status) strong").text()) { @@ -122,7 +124,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context source = source, ) }, - author = doc.selectFirstOrThrow(".author").textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirstOrThrow(".description").html(), chapters = chaptersDeferred.await(), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaKawaiiEn.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaKawaiiEn.kt index 6a9766da..49ea5853 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaKawaiiEn.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaKawaiiEn.kt @@ -86,10 +86,10 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -99,10 +99,11 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) : val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val firstChapter = doc.selectFirst("tr[class*='volume-'] a")?.attr("href") val chaptersDeferred = async { loadChapters(firstChapter) } + val author = doc.select("a[href*=author]").textOrNull() manga.copy( description = doc.selectFirst("dd.text-justify.text-break")?.html(), altTitle = doc.select("span[itemprop*=alternativeHeadline]").joinToString { ", " }.nullIfEmpty(), - author = doc.select("a[href*=author]").textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (doc.selectFirst("span.badge.bg-success.text-uppercase")?.text()) { "Ongoing" -> MangaState.ONGOING "" -> MangaState.FINISHED diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaTownParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaTownParser.kt index 21b0f34f..b3b65f0a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaTownParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MangaTownParser.kt @@ -110,6 +110,9 @@ internal class MangaTownParser(context: MangaLoaderContext) : val views = li.select("p.view") val status = views.firstNotNullOfOrNull { it.ownText().takeIf { x -> x.startsWith("Status:") } } ?.substringAfter(':')?.trim()?.lowercase(Locale.ROOT) + val author = views.firstNotNullOfOrNull { it.text().takeIf { x -> x.startsWith("Author:") } } + ?.substringAfter(':') + ?.trim() Manga( id = generateUid(href), title = a.attr("title"), @@ -118,9 +121,7 @@ internal class MangaTownParser(context: MangaLoaderContext) : altTitle = null, rating = li.selectFirst("p.score")?.selectFirst("b") ?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, - author = views.firstNotNullOfOrNull { it.text().takeIf { x -> x.startsWith("Author:") } } - ?.substringAfter(':') - ?.trim(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (status) { "ongoing" -> MangaState.ONGOING "completed" -> MangaState.FINISHED @@ -134,7 +135,7 @@ internal class MangaTownParser(context: MangaLoaderContext) : ) }.orEmpty(), url = href, - isNsfw = false, + contentRating = null, publicUrl = href.toAbsoluteUrl(a.host ?: domain), ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Mangaowl.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Mangaowl.kt index 6809c4f4..42d179ac 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Mangaowl.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Mangaowl.kt @@ -109,10 +109,10 @@ internal class Mangaowl(context: MangaLoaderContext) : altTitle = null, rating = div.select("span").last()?.text()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = false, + contentRating = null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Com.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Com.kt index e12df687..069f8cb3 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Com.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Com.kt @@ -129,11 +129,11 @@ internal class Manhwa18Com(context: MangaLoaderContext) : url = absUrl.toRelativeUrl(domain), publicUrl = absUrl, rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = it.selectFirst("div.img-in-ratio")?.attrAsAbsoluteUrl("data-bg"), tags = emptySet(), state = null, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, source = MangaParserSource.MANHWA18, @@ -166,7 +166,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) : return manga.copy( altTitle = cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull() ?.removePrefix(": "), - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), description = docs.selectFirst(".series-summary .summary-content")?.html(), tags = tags.orEmpty(), state = state, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Parser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Parser.kt index a8f05117..89362bee 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Parser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Manhwa18Parser.kt @@ -129,11 +129,11 @@ internal class Manhwa18Parser(context: MangaLoaderContext) : url = absUrl.toRelativeUrl(domain), publicUrl = absUrl, rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = it.selectFirst("div.img-in-ratio")?.attrAsAbsoluteUrl("data-bg"), tags = emptySet(), state = null, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, source = MangaParserSource.MANHWA18, @@ -166,7 +166,7 @@ internal class Manhwa18Parser(context: MangaLoaderContext) : return manga.copy( altTitle = cardInfoElement?.selectFirst("b:contains(Other names)")?.parent()?.ownTextOrNull() ?.removePrefix(": "), - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), description = docs.selectFirst(".series-summary .summary-content")?.html(), tags = tags.orEmpty(), state = state, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ManhwasMen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ManhwasMen.kt index 1e80f7bc..5f6efe8f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ManhwasMen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/ManhwasMen.kt @@ -88,10 +88,10 @@ internal class ManhwasMen(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MyComicList.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MyComicList.kt index 2a62d70b..bdaeba5d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MyComicList.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/MyComicList.kt @@ -74,10 +74,10 @@ internal class MyComicList(context: MangaLoaderContext) : PagedMangaParser(conte publicUrl = href.toAbsoluteUrl(domain), title = div.selectFirst("h3 a")?.text().orEmpty(), altTitle = null, - author = null, + authors = emptySet(), tags = emptySet(), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = img?.attrAsAbsoluteUrlOrNull("data-src"), state = null, source = source, @@ -87,6 +87,7 @@ internal class MyComicList(context: MangaLoaderContext) : PagedMangaParser(conte override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst("td:contains(Author:) + td")?.textOrNull() return manga.copy( tags = doc.select("td:contains(Genres:) + td a").mapToSet { a -> MangaTag( @@ -95,7 +96,7 @@ internal class MyComicList(context: MangaLoaderContext) : PagedMangaParser(conte source = source, ) }, - author = doc.selectFirst("td:contains(Author:) + td")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (doc.selectFirst("td:contains(Status:) + td a")?.text()?.lowercase()) { "ongoing" -> MangaState.ONGOING "completed" -> MangaState.FINISHED diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Po2Scans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Po2Scans.kt index 1aee7e95..5673dcd2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Po2Scans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Po2Scans.kt @@ -49,11 +49,11 @@ internal class Po2Scans(context: MangaLoaderContext) : SinglePageMangaParser(con url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -62,6 +62,7 @@ internal class Po2Scans(context: MangaLoaderContext) : SinglePageMangaParser(con override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("dd MMM, yy", Locale.ENGLISH) + val author = doc.selectLast(".author span")?.textOrNull() return manga.copy( state = when (doc.select(".status span").last()?.text()) { "Ongoing" -> MangaState.ONGOING @@ -69,7 +70,7 @@ internal class Po2Scans(context: MangaLoaderContext) : SinglePageMangaParser(con else -> null }, tags = emptySet(), - author = doc.selectLast(".author span")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirstOrThrow(".summary").html(), chapters = doc.select(".chap-section .chap") .mapChapters(reversed = true) { i, div -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Pururin.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Pururin.kt index a9ecefbe..3c5f6f42 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Pururin.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/Pururin.kt @@ -99,10 +99,10 @@ internal class Pururin(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -133,6 +133,7 @@ internal class Pururin(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga = coroutineScope { val fullUrl = manga.url.toAbsoluteUrl(domain) val doc = webClient.httpGet(fullUrl).parseHtml() + val author = doc.selectFirst("a[itemprop=author]")?.text() manga.copy( description = doc.selectFirst("p.mb-2")?.text().orEmpty(), rating = doc.selectFirst("td span.rating")?.attr("content")?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, @@ -144,7 +145,7 @@ internal class Pururin(context: MangaLoaderContext) : source = source, ) }, - author = doc.selectFirst("a[itemprop=author]")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = listOf( MangaChapter( id = manga.id, @@ -175,10 +176,10 @@ internal class Pururin(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = false, + contentRating = null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/VyManga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/VyManga.kt index b0f6869f..577a2a1b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/VyManga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/VyManga.kt @@ -110,10 +110,10 @@ internal class VyManga(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/WeebCentral.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/WeebCentral.kt index dd2d8389..6698df46 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/WeebCentral.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/en/WeebCentral.kt @@ -179,6 +179,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M .attrAsAbsoluteUrl("href") .toHttpUrl() .pathSegments[1] + val author = document.select("div:contains(author) a").eachText().joinToString().nullIfEmpty() Manga( id = generateUid(mangaId), url = mangaId, @@ -210,7 +211,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M "Hiatus" -> PAUSED else -> null }, - author = document.select("div:contains(author) a").eachText().joinToString().nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), largeCoverUrl = null, chapters = null, source = source, @@ -226,6 +227,8 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M val sectionLeft = document.select("section[x-data] > section")[0] val sectionRight = document.select("section[x-data] > section")[1] + val author = sectionLeft.select("ul > li:has(strong:contains(Author)) > span > a") + .eachText().joinToString() manga.copy( title = sectionRight.selectFirstOrThrow("h1").text(), @@ -253,8 +256,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M "Hiatus" -> PAUSED else -> null }, - author = sectionLeft.select("ul > li:has(strong:contains(Author)) > span > a") - .eachText().joinToString(), + authors = setOf(author), description = Element("div").also { desc -> sectionRight.selectFirst("li:has(strong:contains(Description)) > p")?.let { desc.appendChild(it) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TempleScanEsp.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TempleScanEsp.kt index d4fd978e..670a0584 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TempleScanEsp.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TempleScanEsp.kt @@ -47,10 +47,10 @@ internal class TempleScanEsp(context: MangaLoaderContext) : altTitle = it.getStringOrNull("alternativeName"), rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt index 06f18b9f..98ea850b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/es/TuMangaOnlineParser.kt @@ -151,6 +151,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars val doc = webClient.httpGet(url, getRequestHeaders()).parseHtml() val items = doc.body().select("div.element") return items.mapNotNull { item -> + val isNsfwSource = item.select("i").hasClass("fas fa-heartbeat fa-2x") val href = item.selectFirst("a")?.attrAsRelativeUrlOrNull("href")?.substringAfter(' ') ?: return@mapNotNull null Manga( @@ -158,10 +159,10 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars title = item.selectFirst("h4.text-truncate")?.text() ?: return@mapNotNull null, coverUrl = item.select("style").toString().substringAfter("('").substringBeforeLast("')"), altTitle = null, - author = null, + authors = emptySet(), rating = item.selectFirst("span.score")?.text()?.toFloatOrNull()?.div(10F) ?: RATING_UNKNOWN, url = href, - isNsfw = item.select("i").hasClass("fas fa-heartbeat fa-2x"), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, tags = emptySet(), state = null, publicUrl = href.toAbsoluteUrl(doc.host ?: domain), @@ -174,6 +175,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val contents = doc.body().selectFirstOrThrow("section.element-header-content") + val author = contents.selectFirst("h5.card-title")?.attr("title")?.substringAfter(", ") return manga.copy( description = contents.selectFirst("p.element-description")?.html(), tags = contents.select("h6 a").mapToSet { a -> @@ -185,7 +187,7 @@ internal class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaPars }, largeCoverUrl = contents.selectFirst(".book-thumbnail")?.attrAsAbsoluteUrlOrNull("src"), state = parseStatus(contents.select("span.book-status").text().orEmpty()), - author = contents.selectFirst("h5.card-title")?.attr("title")?.substringAfter(", "), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = if (doc.select("div.chapters").isEmpty()) { doc.select(oneShotChapterListSelector).mapChapters(reversed = true) { _, item -> oneShotChapterFromElement(item) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/FmreaderParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/FmreaderParser.kt index 0ee2cf06..7bf384de 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/FmreaderParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/FmreaderParser.kt @@ -147,10 +147,10 @@ internal abstract class FmreaderParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -190,7 +190,7 @@ internal abstract class FmreaderParser( } } val alt = doc.body().selectFirst(selectAlt)?.text()?.replace("Other names", "")?.nullIfEmpty() - val auth = doc.body().selectFirst(selectAut)?.textOrNull() + val author = doc.body().selectFirst(selectAut)?.textOrNull() manga.copy( tags = doc.body().select(selectTag).mapToSet { a -> MangaTag( @@ -201,7 +201,7 @@ internal abstract class FmreaderParser( }, description = desc, altTitle = alt, - author = auth, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = chaptersDeferred.await(), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/ja/Klz9.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/ja/Klz9.kt index c293b796..aa48819a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/ja/Klz9.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fmreader/ja/Klz9.kt @@ -35,10 +35,10 @@ internal class Klz9(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/FoolSlideParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/FoolSlideParser.kt index 76fd4689..eea61201 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/FoolSlideParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/FoolSlideParser.kt @@ -93,10 +93,10 @@ internal abstract class FoolSlideParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } @@ -126,7 +126,7 @@ internal abstract class FoolSlideParser( manga.copy( coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl, description = desc?.nullIfEmpty(), - author = author?.nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = chapters, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/en/Seinagi.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/en/Seinagi.kt index 137e085a..8fee3313 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/en/Seinagi.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/en/Seinagi.kt @@ -36,7 +36,7 @@ internal class Seinagi(context: MangaLoaderContext) : manga.copy( coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl, description = desc?.nullIfEmpty(), - author = author?.nullIfEmpty(), + authors = author?.nullIfEmpty()?.let { setOf(it) } ?: emptySet(), chapters = chapters, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/Pzykosis666hFansub.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/Pzykosis666hFansub.kt index ab087dd0..be2d25c5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/Pzykosis666hFansub.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/Pzykosis666hFansub.kt @@ -35,7 +35,7 @@ internal class Pzykosis666hFansub(context: MangaLoaderContext) : manga.copy( coverUrl = doc.selectFirst(".thumbnail img")?.src() ?: manga.coverUrl, description = desc?.nullIfEmpty(), - author = author?.nullIfEmpty(), + authors = author?.nullIfEmpty()?.let { setOf(it) } ?: emptySet(), chapters = chapters, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/SeinagiAdulto.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/SeinagiAdulto.kt index e2e6b368..fbf4d080 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/SeinagiAdulto.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/foolslide/es/SeinagiAdulto.kt @@ -35,7 +35,7 @@ internal class SeinagiAdulto(context: MangaLoaderContext) : manga.copy( coverUrl = doc.selectFirst(".thumbnail img")?.src(),// for manga result on search description = desc?.nullIfEmpty(), - author = author?.nullIfEmpty(), + authors = author?.nullIfEmpty()?.let { setOf(it) } ?: emptySet(), chapters = chapters, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/BentomangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/BentomangaParser.kt index d484ba13..c2f7ae44 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/BentomangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/BentomangaParser.kt @@ -111,6 +111,7 @@ internal class BentomangaParser(context: MangaLoaderContext) : return root.select(".manga[data-manga]").map { div -> val header = div.selectFirstOrThrow(".manga_header") val href = header.selectFirstOrThrow("a").attrAsRelativeUrl("href") + val isNsfwSource = div.selectFirst(".badge-adult_content") != null Manga( id = generateUid(href), title = div.selectFirst("h1")?.text().orEmpty(), @@ -123,7 +124,7 @@ internal class BentomangaParser(context: MangaLoaderContext) : ?.toFloatOrNull() ?.div(10f) ?: RATING_UNKNOWN, - isNsfw = div.selectFirst(".badge-adult_content") != null, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = div.selectFirst("img")?.src().assertNotNull("src"), tags = div.selectFirst(".component-manga-categories") .assertNotNull("tags") @@ -136,7 +137,7 @@ internal class BentomangaParser(context: MangaLoaderContext) : ) }.orEmpty(), state = null, - author = null, + authors = emptySet(), description = div.selectFirst(".manga_synopsis")?.html().assertNotNull("description"), source = source, ) @@ -147,6 +148,7 @@ internal class BentomangaParser(context: MangaLoaderContext) : val mangaUrl = manga.url.toAbsoluteUrl(domain) val root = webClient.httpGet(mangaUrl).parseHtml() .requireElementById("container_manga_show") + val author = root.selectFirst(".datas_more-authors-people")?.textOrNull() return manga.copy( altTitle = root.selectFirst(".component-manga-title_alt")?.textOrNull(), description = root.selectFirst(".datas_synopsis")?.html().assertNotNull("description") @@ -158,7 +160,7 @@ internal class BentomangaParser(context: MangaLoaderContext) : "En pause" -> MangaState.PAUSED else -> null }, - author = root.selectFirst(".datas_more-authors-people")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = run { val input = root.selectFirst("input[name=\"limit\"]") ?: return@run parseChapters(root) val max = input.attr("max").toInt() diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/FuryoSociety.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/FuryoSociety.kt index 0b977225..daffcf2a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/FuryoSociety.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/FuryoSociety.kt @@ -74,10 +74,10 @@ internal class FuryoSociety(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = false, + contentRating = null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LegacyScansParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LegacyScansParser.kt index b81accfb..f0b07ec8 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LegacyScansParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LegacyScansParser.kt @@ -136,11 +136,11 @@ internal class LegacyScansParser(context: MangaLoaderContext) : url = urlManga, publicUrl = urlManga, rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = "https://api.$domain/" + j.getString("cover"), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -157,11 +157,11 @@ internal class LegacyScansParser(context: MangaLoaderContext) : url = urlManga, publicUrl = urlManga, rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = null, tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -170,6 +170,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga { val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.FRENCH) + val author = root.select("div.serieAdd p:contains(Auteur:) strong").textOrNull() return manga.copy( tags = root.select("div.serieGenre span").mapToSet { span -> MangaTag( @@ -179,7 +180,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) : ) }, coverUrl = root.selectFirst("div.serieImg img")?.attrAsAbsoluteUrlOrNull("src"), - author = root.select("div.serieAdd p:contains(Auteur:) strong").textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = root.selectFirst("div.serieDescription div")?.html(), chapters = root.select("div.chapterList a") .mapChapters(reversed = true) { i, a -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LireScan.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LireScan.kt index c62617c3..da06d609 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LireScan.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LireScan.kt @@ -72,11 +72,11 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context, url = href, publicUrl = href.toAbsoluteUrl(domain), rating = div.selectFirstOrThrow(".item__rating").ownText().toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").attrAsAbsoluteUrl("src"), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -85,6 +85,9 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context, override suspend fun getDetails(manga: Manga): Manga { val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE) + val author = root.select("ul.pmovie__list li:contains(Artist(s):)").text() + .replace("Artist(s):", "") + .nullIfEmpty() return manga.copy( altTitle = root.select("ul.pmovie__list li:contains(Nom Alternatif:)").text() .replace("Nom Alternatif:", "").nullIfEmpty(), @@ -101,9 +104,7 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context, source = source, ) }, - author = root.select("ul.pmovie__list li:contains(Artist(s):)").text() - .replace("Artist(s):", "") - .nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), description = root.selectFirst("div.pmovie__text")?.html(), chapters = root.select("ul li div.chapter") .mapChapters(reversed = true) { i, div -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LugnicaScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LugnicaScans.kt index 1f04d9c1..c92024e1 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LugnicaScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/LugnicaScans.kt @@ -111,11 +111,11 @@ internal class LugnicaScans(context: MangaLoaderContext) : url = urlManga.toRelativeUrl(domain), publicUrl = urlManga.toAbsoluteUrl(domain), rating = j.getFloatOrDefault("manga_rate", RATING_UNKNOWN).div(5f), - isNsfw = false, + contentRating = null, coverUrl = img, tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -132,7 +132,7 @@ internal class LugnicaScans(context: MangaLoaderContext) : url = urlManga.toRelativeUrl(domain), publicUrl = urlManga.toAbsoluteUrl(domain), rating = j.getString("rate").toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = img, tags = setOf(), state = when (j.getString("status")) { @@ -141,7 +141,7 @@ internal class LugnicaScans(context: MangaLoaderContext) : "3" -> MangaState.ABANDONED else -> null }, - author = null, + authors = emptySet(), source = source, ) } @@ -161,6 +161,7 @@ internal class LugnicaScans(context: MangaLoaderContext) : } val slug = manga.url.substringAfterLast("/") val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE) + val author = jsonManga.getStringOrNull("author") return manga.copy( state = when (jsonManga.getString("status")) { "0" -> MangaState.ONGOING @@ -168,7 +169,7 @@ internal class LugnicaScans(context: MangaLoaderContext) : "3" -> MangaState.ABANDONED else -> null }, - author = jsonManga.getStringOrNull("author"), + authors = author?.let { setOf(it) } ?: emptySet(), description = jsonManga.getStringOrNull("description"), chapters = chapters.mapChapters { i, it -> val id = it.substringAfter("\"chapter\":").substringBefore(",") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaKawaii.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaKawaii.kt index 6b666f46..7227ceef 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaKawaii.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaKawaii.kt @@ -85,10 +85,10 @@ internal class MangaKawaii(context: MangaLoaderContext) : PagedMangaParser(conte altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -98,10 +98,11 @@ internal class MangaKawaii(context: MangaLoaderContext) : PagedMangaParser(conte val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val firstChapter = doc.selectFirst("tr[class*='volume-'] a")?.attr("href") val chaptersDeferred = async { loadChapters(firstChapter) } + val author = doc.select("a[href*=author]").text() manga.copy( description = doc.selectFirst("dd.text-justify.text-break")?.html(), altTitle = doc.select("span[itemprop*=alternativeHeadline]").joinToString { ", " }.nullIfEmpty(), - author = doc.select("a[href*=author]").text(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (doc.selectFirst("span.badge.bg-success.text-uppercase")?.text()) { "En Cours" -> MangaState.ONGOING "Terminé" -> MangaState.FINISHED diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaMana.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaMana.kt index 8a171e0c..05aaa5de 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaMana.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/MangaMana.kt @@ -68,17 +68,18 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context val slug = jo.getString("slug") ?: throw ParseException("Missing Slug", url) val url = "https://$domain/m/$slug" val img = "https://$domainCdn/uploads/manga/$slug/cover/cover_thumb.jpg" + val isNsfwSource = when (jo.getIntOrDefault("caution", 0)) { + 0 -> false + 2 -> true + else -> false + } Manga( id = generateUid(url), title = jo.getString("name").orEmpty(), coverUrl = img, altTitle = jo.getString("otherNames").orEmpty(), - author = null, - isNsfw = when (jo.getIntOrDefault("caution", 0)) { - 0 -> false - 2 -> true - else -> false - }, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, rating = RATING_UNKNOWN, url = url, description = jo.getString("summary_old").orEmpty(), @@ -107,8 +108,8 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context val doc = webClient.httpGet("https://$domain/?page=$page").parseHtml() return doc.select("div.row div.col_home").map { div -> val href = div.selectFirstOrThrow("h4 a").attrAsRelativeUrl("href") - val isNsfw = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() == true - val img = if (isNsfw) { + val isNsfwSource = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() == true + val img = if (isNsfwSource) { div.selectFirst("img")?.attr("data-adult") } else { div.selectFirst("img")?.attr("data-src")?.replace(" ", "") @@ -120,12 +121,12 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfw, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = img, description = null, tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -170,8 +171,8 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context return doc.select("div.p-2 div.col").map { div -> val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") - val isNsfw = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() == true - val img = if (isNsfw) { + val isNsfwSource = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() == true + val img = if (isNsfwSource) { div.selectFirst("img")?.attr("data-adult") } else { div.selectFirst("img")?.attr("data-src")?.replace(" ", "") @@ -183,7 +184,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context url = href, publicUrl = href.toAbsoluteUrl(domain), rating = div.getElementById("avgrating")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, - isNsfw = isNsfw, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = img, description = div.selectFirst(".mangalist_item_description")?.text().orEmpty(), tags = div.select("div.mb-1 a").mapToSet { @@ -195,7 +196,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context ) }, state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -228,6 +229,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context val doc = webClient.httpGet(mangaUrl).parseHtml() val maxPageChapterSelect = doc.select("ul.pagination a.page-link") var maxPageChapter = 1 + val author = doc.selectFirst("div.show_details span[itemprop=author]")?.text().orEmpty() if (!maxPageChapterSelect.isNullOrEmpty()) { maxPageChapterSelect.map { val i = it.attr("href").substringAfterLast("=").toInt() @@ -243,7 +245,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context "Abandonné" -> MangaState.ABANDONED else -> null }, - author = doc.selectFirst("div.show_details span[itemprop=author]")?.text().orEmpty(), + authors = setOf(author), description = doc.selectFirst("dd[itemprop=description]")?.text(), rating = doc.getElementById("avgrating")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = doc.select("ul.list-unstyled li a.category").mapToSet { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScansMangasMe.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScansMangasMe.kt index 8739e569..cf8295ce 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScansMangasMe.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScansMangasMe.kt @@ -87,10 +87,10 @@ internal class ScansMangasMe(context: MangaLoaderContext) : rating = div.selectFirstOrThrow("div.rating i").ownText().toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -114,7 +114,7 @@ internal class ScansMangasMe(context: MangaLoaderContext) : val chaptersDeferred = getChapters(doc) val desc = doc.selectFirstOrThrow("div.desc").html().nullIfEmpty() val alt = doc.body().select("div.infox span.alter").textOrNull() - val aut = doc.select("div.spe span")[2].text().replace("Auteur:", "").nullIfEmpty() + val author = doc.select("div.spe span")[2].text().replace("Auteur:", "").nullIfEmpty() manga.copy( tags = doc.select("div.spe span:contains(Genres) a").mapToSet { a -> MangaTag( @@ -125,7 +125,7 @@ internal class ScansMangasMe(context: MangaLoaderContext) : }, description = desc, altTitle = alt, - author = aut, + authors = author?.let { setOf(it) } ?: emptySet(), state = when (doc.selectFirstOrThrow("div.spe span:contains(Statut:)").textOrNull() ?.substringAfterLast(':')) { " En cours" -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScantradUnion.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScantradUnion.kt index 7291a7dd..26a377a9 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScantradUnion.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fr/ScantradUnion.kt @@ -88,11 +88,11 @@ internal class ScantradUnion(context: MangaLoaderContext) : url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = article.selectFirst("img.attachment-thumbnail")?.attrAsAbsoluteUrl("src"), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -108,11 +108,11 @@ internal class ScantradUnion(context: MangaLoaderContext) : url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = article.selectFirst("img")?.attrAsAbsoluteUrl("src"), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -122,6 +122,7 @@ internal class ScantradUnion(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga { val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml().requireElementById("main") val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.FRANCE) + val author = root.select("div.project-details a[href*=auteur]").textOrNull() return manga.copy( altTitle = root.select(".divider2:contains(Noms associés :)").firstOrNull()?.textOrNull(), @@ -137,7 +138,7 @@ internal class ScantradUnion(context: MangaLoaderContext) : source = source, ) }, - author = root.select("div.project-details a[href*=auteur]").textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = root.selectFirst("p.sContent")?.html(), chapters = root.select("div.chapter-list li") .mapChapters(reversed = true) { i, li -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fuzzydoodle/FuzzyDoodleParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fuzzydoodle/FuzzyDoodleParser.kt index 19b5e1fc..42f7a7dc 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fuzzydoodle/FuzzyDoodleParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/fuzzydoodle/FuzzyDoodleParser.kt @@ -152,10 +152,10 @@ internal abstract class FuzzyDoodleParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -181,6 +181,7 @@ internal abstract class FuzzyDoodleParser( } } } + val author = doc.selectFirst(selectAuthor)?.textOrNull() manga.copy( altTitle = doc.selectLast(selectAltTitle)?.textOrNull(), @@ -191,7 +192,7 @@ internal abstract class FuzzyDoodleParser( in paused -> MangaState.PAUSED else -> null }, - author = doc.selectFirst(selectAuthor)?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.select(selectDescription).html(), tags = doc.select(selectTagManga).mapToSet { val key = it.attr("href").substringAfterLast('=') diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt index 110ebda9..89a90e77 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt @@ -113,11 +113,11 @@ internal abstract class GalleryAdultsParser( url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = div.selectFirst(selectGalleryImg)?.src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -165,10 +165,11 @@ internal abstract class GalleryAdultsParser( val branch = doc.select(selectLanguageChapter).joinToString(separator = " / ") { it.html().substringBefore("<") } + val author = doc.selectFirst(selectAuthor)?.html()?.substringBefore(" MangaState.PAUSED else -> null }, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt index 30f726ac..3787f58f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt @@ -70,10 +70,10 @@ internal abstract class HeanCmsAlt( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/hotcomics/HotComicsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/hotcomics/HotComicsParser.kt index bad4b3af..12359e36 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/hotcomics/HotComicsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/hotcomics/HotComicsParser.kt @@ -100,6 +100,8 @@ internal abstract class HotComicsParser( } val tags = li.select(".etc span").mapNotNullToSet { tagMap[it.text()] } + val isNsfwSource = a.selectFirst(".ico-18plus") != null + val author = li.selectFirst(".writer")?.text().orEmpty() Manga( id = generateUid(url), @@ -111,14 +113,14 @@ internal abstract class HotComicsParser( rating = RATING_UNKNOWN, description = li.selectFirst("p[itemprop*=description]")?.text().orEmpty(), tags = tags, - author = li.selectFirst(".writer")?.text().orEmpty(), + authors = setOf(author), state = if (doc.selectFirst(".ico_fin") != null) { MangaState.FINISHED } else { MangaState.ONGOING }, source = source, - isNsfw = a.selectFirst(".ico-18plus") != null, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt index c4a0fa8d..8ded46b5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt @@ -120,11 +120,11 @@ internal class DoujinDesuParser(context: MangaLoaderContext) : url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = it.selectFirst(".thumbnail > img")?.src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, source = source, @@ -141,8 +141,9 @@ internal class DoujinDesuParser(context: MangaLoaderContext) : "Publishing" -> MangaState.ONGOING else -> null } + val author = metadataEl?.selectFirst("tr:contains(Author)")?.selectLast("td")?.text() return manga.copy( - author = metadataEl?.selectFirst("tr:contains(Author)")?.selectLast("td")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), description = docs.selectFirst(".wrapper > .metadata > .pb-2")?.selectFirst("p")?.html(), state = state, rating = metadataEl?.selectFirst(".rating-prc")?.ownText()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/HentaiCrot.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/HentaiCrot.kt index e4e987b6..ca49d753 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/HentaiCrot.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/HentaiCrot.kt @@ -71,10 +71,10 @@ internal class HentaiCrot(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -95,10 +95,11 @@ internal class HentaiCrot(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga { val fullUrl = manga.url.toAbsoluteUrl(domain) val doc = webClient.httpGet(fullUrl).parseHtml() + val author = doc.selectFirst("div.entry-content ul li:contains(Artists :) em")?.textOrNull() return manga.copy( 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(), + authors = author?.let { setOf(it) } ?: emptySet(), state = null, chapters = listOf( MangaChapter( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/PixHentai.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/PixHentai.kt index aed4b271..aefb5353 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/PixHentai.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/PixHentai.kt @@ -71,10 +71,10 @@ internal class PixHentai(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -95,10 +95,11 @@ internal class PixHentai(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga { val fullUrl = manga.url.toAbsoluteUrl(domain) val doc = webClient.httpGet(fullUrl).parseHtml() + val author = doc.selectFirst("div.entry-content ul li:contains(Artists :) em")?.textOrNull() return manga.copy( 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(), + authors = author?.let { setOf(it) } ?: emptySet(), state = null, chapters = listOf( MangaChapter( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt index c381a37e..25518665 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt @@ -101,6 +101,8 @@ internal abstract class IkenParser( protected open fun parseMangaList(json: JSONObject): List { return json.getJSONArray("posts").mapJSON { val url = "/series/${it.getString("slug")}" + val isNsfwSource = it.getBooleanOrDefault("hot", false) + val author = it.getString("author") Manga( id = it.getLong("id"), url = url, @@ -111,7 +113,7 @@ internal abstract class IkenParser( description = it.getString("postContent"), rating = RATING_UNKNOWN, tags = emptySet(), - author = it.getString("author"), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (it.getString("seriesStatus")) { "ONGOING" -> MangaState.ONGOING "COMPLETED" -> MangaState.FINISHED @@ -120,7 +122,7 @@ internal abstract class IkenParser( else -> null }, source = source, - isNsfw = it.getBooleanOrDefault("hot", false), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt index 7141392e..df0803f4 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ja/NicovideoSeigaParser.kt @@ -84,15 +84,16 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) : val href = item.selectFirst(".comic_icon > div > a")?.attrAsRelativeUrlOrNull("href") ?: return@mapNotNull null val statusText = item.selectFirst(".mg_description_header > .mg_icon > .content_status > span")?.text() + val author = item.selectFirst(".mg_description_header > .mg_author > a")?.text() Manga( id = generateUid(href), title = item.selectFirst(".mg_body > .title > a")?.text() ?: return@mapNotNull null, coverUrl = item.selectFirst(".comic_icon > div > a > img")?.attrAsAbsoluteUrl("src"), altTitle = null, - author = item.selectFirst(".mg_description_header > .mg_author > a")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), rating = RATING_UNKNOWN, url = href, - isNsfw = false, + contentRating = null, tags = item.getElementsByAttributeValueContaining("href", "?category=").mapToSet { a -> MangaTag( key = a.attr("href").substringAfterLast('='), @@ -193,11 +194,11 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) : title = item.selectFirst(".search_result__item__info > .search_result__item__info--title > a") ?.textOrNull() ?: return@mapNotNull null, altTitle = null, - author = null, + authors = emptySet(), tags = emptySet(), rating = RATING_UNKNOWN, state = null, - isNsfw = false, + contentRating = null, source = source, coverUrl = item.selectFirst(".search_result__item__thumbnail > a > img") ?.attrAsAbsoluteUrl("data-original"), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt index 901d7a6a..21244d91 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/keyoapp/KeyoappParser.kt @@ -138,10 +138,10 @@ internal abstract class KeyoappParser( source = source, ) }, - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt index 6971cde0..fa458e92 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/likemanga/LikeMangaParser.kt @@ -115,11 +115,11 @@ internal abstract class LikeMangaParser( url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -149,6 +149,7 @@ internal abstract class LikeMangaParser( } } } + val author = doc.selectLast("li.author p")?.textOrNull() return manga.copy( altTitle = doc.selectFirst(".list-info li.othername h2")?.textOrNull(), tags = doc.select("li.kind a").mapToSet { a -> @@ -158,7 +159,7 @@ internal abstract class LikeMangaParser( source = source, ) }, - author = doc.selectLast("li.author p")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.requireElementById("summary_shortened").html(), chapters = run { if (maxPageChapter == 1) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/LilianaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/LilianaParser.kt index 5fadc720..498e5f42 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/LilianaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/liliana/LilianaParser.kt @@ -119,10 +119,10 @@ internal abstract class LilianaParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } @@ -148,6 +148,9 @@ internal abstract class LilianaParser( override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst("div.y6x11p i.fas.fa-user + span.dt")?.textOrNull()?.takeUnless { + it.equals("updating", true) + } return manga.copy( description = doc.selectFirst("div#syn-target")?.html(), largeCoverUrl = doc.selectFirst(".a1 > figure img")?.src(), @@ -158,9 +161,7 @@ internal abstract class LilianaParser( source = source, ) }, - author = doc.selectFirst("div.y6x11p i.fas.fa-user + span.dt")?.textOrNull()?.takeUnless { - it.equals("updating", true) - }, + authors = author?.let { setOf(it) } ?: emptySet(), state = when (doc.selectFirst("div.y6x11p i.fas.fa-rss + span.dt")?.text()?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING in finished -> MangaState.FINISHED diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt index 4d3cdb00..2ab8ecb2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/MadaraParser.kt @@ -460,6 +460,7 @@ internal abstract class MadaraParser( }.map { div -> val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -476,7 +477,7 @@ internal abstract class MadaraParser( source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when ( summary?.selectFirst(".mg_status") ?.selectFirst(".summary-content") @@ -491,7 +492,7 @@ internal abstract class MadaraParser( else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -660,12 +661,12 @@ internal abstract class MadaraParser( publicUrl = href.toAbsoluteUrl(a.host ?: domain), altTitle = null, title = div.selectFirstOrThrow(".widget-title").text(), - author = null, + authors = emptySet(), coverUrl = div.selectFirst("img")?.src(), tags = emptySet(), rating = RATING_UNKNOWN, state = null, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manga18Fx.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manga18Fx.kt index ef0d03c3..7b12756b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manga18Fx.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manga18Fx.kt @@ -74,10 +74,10 @@ internal class Manga18Fx(context: MangaLoaderContext) : altTitle = null, rating = div.selectFirst("div.item-rate span")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manhwa18Cc.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manhwa18Cc.kt index 604c19f1..1d43f1de 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manhwa18Cc.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/all/Manhwa18Cc.kt @@ -80,10 +80,10 @@ internal class Manhwa18Cc(context: MangaLoaderContext) : altTitle = null, rating = div.selectFirst(".item-rate span")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/FireScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/FireScans.kt index eaa041cd..8cbcb61d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/FireScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/FireScans.kt @@ -3,10 +3,7 @@ package org.koitharu.kotatsu.parsers.site.madara.en import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser -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.MangaTag +import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.util.* @@ -20,6 +17,7 @@ internal class FireScans(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("h3 a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -36,7 +34,7 @@ internal class FireScans(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when ( summary?.selectFirst(".mg_status") ?.selectFirst(".summary-content") @@ -50,7 +48,7 @@ internal class FireScans(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Hentai4Free.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Hentai4Free.kt index 234ef9ca..3ff3a9e7 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Hentai4Free.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Hentai4Free.kt @@ -102,6 +102,7 @@ internal class Hentai4Free(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -118,7 +119,7 @@ internal class Hentai4Free(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING @@ -126,7 +127,7 @@ internal class Hentai4Free(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScan.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScan.kt index e8001bb3..201e9020 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScan.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScan.kt @@ -77,6 +77,7 @@ internal class IsekaiScan(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -92,7 +93,7 @@ internal class IsekaiScan(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase()) { "ongoing" -> MangaState.ONGOING @@ -100,7 +101,7 @@ internal class IsekaiScan(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScanEuParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScanEuParser.kt index 6bfa10c7..6300746e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScanEuParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/IsekaiScanEuParser.kt @@ -99,6 +99,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -115,7 +116,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING @@ -123,7 +124,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDass.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDass.kt index 1578df10..e35d49fc 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDass.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDass.kt @@ -75,6 +75,7 @@ internal class MangaDass(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -90,7 +91,7 @@ internal class MangaDass(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING @@ -98,7 +99,7 @@ internal class MangaDass(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDna.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDna.kt index fc50e95b..4774fe72 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDna.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaDna.kt @@ -68,6 +68,7 @@ internal class MangaDna(context: MangaLoaderContext) : return doc.select("div.home-item").map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".hcontent") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -83,7 +84,7 @@ internal class MangaDna(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING @@ -91,7 +92,7 @@ internal class MangaDna(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaPure.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaPure.kt index 031cf04c..86a754a5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaPure.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/MangaPure.kt @@ -82,6 +82,7 @@ internal class MangaPure(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -97,7 +98,7 @@ internal class MangaPure(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase()) { "ongoing" -> MangaState.ONGOING @@ -105,7 +106,7 @@ internal class MangaPure(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Manhwaz.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Manhwaz.kt index 49ea96a8..226592b5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Manhwaz.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/Manhwaz.kt @@ -71,6 +71,7 @@ internal class Manhwaz(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -86,7 +87,7 @@ internal class Manhwaz(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING @@ -94,7 +95,7 @@ internal class Manhwaz(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/ShibaManga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/ShibaManga.kt index 470c8e09..b69585a4 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/ShibaManga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/en/ShibaManga.kt @@ -3,10 +3,7 @@ package org.koitharu.kotatsu.parsers.site.madara.en import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser -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.MangaTag +import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.util.* @@ -21,6 +18,7 @@ internal class ShibaManga(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -37,7 +35,7 @@ internal class ShibaManga(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when ( summary?.selectFirst(".mg_status") ?.selectFirst(".summary-content") @@ -52,7 +50,7 @@ internal class ShibaManga(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/DragonTranslationParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/DragonTranslationParser.kt index 2ec549c3..660ccf6d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/DragonTranslationParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/DragonTranslationParser.kt @@ -2,10 +2,7 @@ package org.koitharu.kotatsu.parsers.site.madara.es import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser -import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaListFilter -import org.koitharu.kotatsu.parsers.model.MangaParserSource -import org.koitharu.kotatsu.parsers.model.SortOrder +import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.util.* import java.util.* @@ -67,10 +64,10 @@ internal class DragonTranslationParser(context: MangaLoaderContext) : altTitle = null, rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/MangasNoSekai.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/MangasNoSekai.kt index 40184626..58e11f70 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/MangasNoSekai.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/MangasNoSekai.kt @@ -20,6 +20,7 @@ internal class MangasNoSekai(context: MangaLoaderContext) : val doc = webClient.httpGet(fullUrl).parseHtml() val body = doc.body() val chaptersDeferred = async { loadChapters(manga.url, doc) } + val author = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Autor)) p a")?.textOrNull() manga.copy( tags = doc.body().select("#section-sinopsis a[href*=genre]").mapToSet { a -> MangaTag( @@ -28,8 +29,7 @@ internal class MangasNoSekai(context: MangaLoaderContext) : source = source, ) }, - author = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Autor)) p a") - ?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = body.selectFirst("#section-sinopsis p")?.text().orEmpty(), altTitle = doc.selectFirst("section#section-sinopsis div.d-flex:has(div:contains(Otros nombres)) p") ?.textOrNull(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/TmoManga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/TmoManga.kt index f0186c5f..f7d94d38 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/TmoManga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/es/TmoManga.kt @@ -75,10 +75,10 @@ internal class TmoManga(context: MangaLoaderContext) : altTitle = null, rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/id/ManhwaHub.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/id/ManhwaHub.kt index 9b43234a..89ffbf8f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/id/ManhwaHub.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/id/ManhwaHub.kt @@ -66,6 +66,7 @@ internal class ManhwaHub(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -82,7 +83,7 @@ internal class ManhwaHub(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING @@ -90,7 +91,7 @@ internal class ManhwaHub(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/ja/MangaFenxi.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/ja/MangaFenxi.kt index b3eba37c..7fdd383f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/ja/MangaFenxi.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/ja/MangaFenxi.kt @@ -4,10 +4,7 @@ import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser -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.MangaTag +import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.util.* import java.util.* @@ -25,6 +22,7 @@ internal class MangaFenxi(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -41,7 +39,7 @@ internal class MangaFenxi(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when ( summary?.selectFirst(".mg_status") ?.selectFirst(".summary-content") @@ -56,7 +54,7 @@ internal class MangaFenxi(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/Saytruyenhay.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/Saytruyenhay.kt index 86a78cc1..508c2ba7 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/Saytruyenhay.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/vi/Saytruyenhay.kt @@ -72,6 +72,7 @@ internal class Saytruyenhay(context: MangaLoaderContext) : }.map { div -> val href = div.selectFirst("a")?.attrAsRelativeUrlOrNull("href") ?: div.parseFailed("Link not found") val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary") + val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText() Manga( id = generateUid(href), url = href, @@ -87,7 +88,7 @@ internal class Saytruyenhay(context: MangaLoaderContext) : source = source, ) }.orEmpty(), - author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() ?.lowercase().orEmpty()) { in ongoing -> MangaState.ONGOING @@ -95,7 +96,7 @@ internal class Saytruyenhay(context: MangaLoaderContext) : else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madtheme/MadthemeParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madtheme/MadthemeParser.kt index 1d879cfe..f2a7c6ec 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madtheme/MadthemeParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madtheme/MadthemeParser.kt @@ -130,10 +130,10 @@ internal abstract class MadthemeParser( source = source, ) }, - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/Manga18Parser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/Manga18Parser.kt index ecf2bd24..36b9c05e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/Manga18Parser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/Manga18Parser.kt @@ -112,10 +112,10 @@ internal abstract class Manga18Parser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -166,7 +166,7 @@ internal abstract class Manga18Parser( }, description = desc?.nullIfEmpty(), altTitle = alt, - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = chaptersDeferred.await(), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/en/Hentai3zCc.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/en/Hentai3zCc.kt index b9d7a0aa..1723b8e4 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/en/Hentai3zCc.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/manga18/en/Hentai3zCc.kt @@ -3,10 +3,7 @@ package org.koitharu.kotatsu.parsers.site.manga18.en import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser -import org.koitharu.kotatsu.parsers.model.ContentType -import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaParserSource -import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN +import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.site.manga18.Manga18Parser import org.koitharu.kotatsu.parsers.util.* @@ -28,10 +25,10 @@ internal class Hentai3zCc(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/MangaboxParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/MangaboxParser.kt index 342f815e..9e3b9db7 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/MangaboxParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/MangaboxParser.kt @@ -131,10 +131,10 @@ internal abstract class MangaboxParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -175,7 +175,7 @@ internal abstract class MangaboxParser( } } val alt = doc.body().select(selectAlt).text().replace("Alternative : ", "").nullIfEmpty() - val aut = doc.body().select(selectAut).eachText().joinToString().nullIfEmpty() + val author = doc.body().select(selectAut).eachText().joinToString().nullIfEmpty() manga.copy( tags = doc.body().select(selectTag).mapToSet { a -> MangaTag( @@ -186,7 +186,7 @@ internal abstract class MangaboxParser( }, description = desc, altTitle = alt, - author = aut, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = chaptersDeferred.await(), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangairo.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangairo.kt index b62473b8..10985863 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangairo.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangairo.kt @@ -101,10 +101,10 @@ internal class Mangairo(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -137,7 +137,7 @@ internal class Mangairo(context: MangaLoaderContext) : } val alt = doc.body().select(selectAlt).text().replace("Alternative : ", "").nullIfEmpty() - val aut = doc.body().select(selectAut).eachText().joinToString().nullIfEmpty() + val author = doc.body().select(selectAut).eachText().joinToString().nullIfEmpty() manga.copy( tags = doc.body().select(selectTag).mapToSet { a -> MangaTag( @@ -149,7 +149,7 @@ internal class Mangairo(context: MangaLoaderContext) : }, description = desc, altTitle = alt, - author = aut, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = chaptersDeferred.await(), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangakakalot.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangakakalot.kt index 7b3512c5..856e7747 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangakakalot.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/Mangakakalot.kt @@ -90,10 +90,10 @@ internal class Mangakakalot(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/MangakakalotTv.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/MangakakalotTv.kt index 66b81b75..9d8a83b9 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/MangakakalotTv.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangabox/en/MangakakalotTv.kt @@ -87,10 +87,10 @@ internal class MangakakalotTv(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -109,7 +109,7 @@ internal class MangakakalotTv(context: MangaLoaderContext) : } } val alt = doc.body().select(selectAlt).text().replace("Alternative : ", "").nullIfEmpty() - val aut = doc.body().select(selectAut).eachText().joinToString().nullIfEmpty() + val author = doc.body().select(selectAut).eachText().joinToString().nullIfEmpty() manga.copy( tags = doc.body().select(selectTag).mapToSet { a -> MangaTag( @@ -120,7 +120,7 @@ internal class MangakakalotTv(context: MangaLoaderContext) : }, description = desc, altTitle = alt, - author = aut, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = chaptersDeferred.await(), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt index 11b1d603..e24c6f7c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangadventure/MangAdventureParser.kt @@ -105,21 +105,22 @@ internal abstract class MangAdventureParser( val details = requireNotNull(url.get()) val chapters = url.addEncodedPathSegment("chapters") .addEncodedQueryParameter("date_format", "timestamp").get() + val author = buildString { + val authors = details.getJSONArray("authors") + val artists = details.getJSONArray("artists") + if (authors.length() > 0 && artists.length() > 0) { + authors.joinTo(this, postfix = ", ") + artists.joinTo(this) + } else if (authors.length() > 0) { + authors.joinTo(this) + } else if (artists.length() > 0) { + artists.joinTo(this) + } + } return manga.copy( description = details.getStringOrNull("description"), altTitle = details.getJSONArray("aliases").joinToString().nullIfEmpty(), - author = buildString { - val authors = details.getJSONArray("authors") - val artists = details.getJSONArray("artists") - if (authors.length() > 0 && artists.length() > 0) { - authors.joinTo(this, postfix = ", ") - artists.joinTo(this) - } else if (authors.length() > 0) { - authors.joinTo(this) - } else if (artists.length() > 0) { - artists.joinTo(this) - } - }, + authors = setOf(author), tags = details.getJSONArray("categories").mapTo(HashSet()) { val name = it as String MangaTag(name, name, source) @@ -191,11 +192,11 @@ internal abstract class MangAdventureParser( url = path, publicUrl = publicUrl, rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = it.getString("cover"), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } ?: emptyList() diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt index 2424b5f5..dc420130 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt @@ -163,11 +163,11 @@ internal abstract class MangaReaderParser( altTitle = null, publicUrl = a.attrAsAbsoluteUrl("href"), rating = rating, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = it.selectFirst(selectMangaListImg)?.src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -275,7 +275,7 @@ internal abstract class MangaReaderParser( return manga.copy( description = docs.selectFirst(detailsDescriptionSelector)?.text(), state = mangaState, - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), contentRating = if (manga.isNsfw || nsfw) { ContentRating.ADULT } else { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/ar/Normoyun.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/ar/Normoyun.kt index 3604c37b..0c3240a6 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/ar/Normoyun.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/ar/Normoyun.kt @@ -110,7 +110,7 @@ internal class Normoyun(context: MangaLoaderContext) : return manga.copy( description = docs.selectFirst("span.desc")?.html(), state = mangaState, - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), contentRating = if (manga.isNsfw || nsfw) { ContentRating.ADULT } else { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/RizzComic.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/RizzComic.kt index 26e3257e..25597cda 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/RizzComic.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/en/RizzComic.kt @@ -115,6 +115,7 @@ internal class RizzComic(context: MangaLoaderContext) : .replace(slugRegex, "-") .replace("-s-", "s-") .replace("-ll-", "ll-") + val author = j.getStringOrNull("author") val manga = Manga( id = j.getLong("id"), @@ -123,7 +124,7 @@ internal class RizzComic(context: MangaLoaderContext) : url = urlManga.toRelativeUrl(domain), publicUrl = urlManga, rating = j.getFloatOrDefault("rating", RATING_UNKNOWN) / 10f, - isNsfw = false, + contentRating = null, coverUrl = "https://$domain/assets/images/" + j.getString("image_url"), tags = setOf(), state = when (j.getString("status")) { @@ -132,7 +133,7 @@ internal class RizzComic(context: MangaLoaderContext) : "hiatus" -> MangaState.PAUSED else -> null }, - author = j.getStringOrNull("author"), + authors = author?.let { setOf(it) } ?: emptySet(), source = source, description = j.getString("long_description"), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/RevolutionScantrad.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/RevolutionScantrad.kt index fa7b016e..b88018ef 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/RevolutionScantrad.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/RevolutionScantrad.kt @@ -100,11 +100,11 @@ internal class RevolutionScantrad(context: MangaLoaderContext) : altTitle = null, publicUrl = a.attrAsAbsoluteUrl("href"), rating = rating, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = it.selectFirst(selectMangaListImg)?.src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/XxxRevolutionScantrad.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/XxxRevolutionScantrad.kt index 90e0ce75..21aa7acd 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/XxxRevolutionScantrad.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/fr/XxxRevolutionScantrad.kt @@ -94,11 +94,11 @@ internal class XxxRevolutionScantrad(context: MangaLoaderContext) : altTitle = null, publicUrl = a.attrAsAbsoluteUrl("href"), rating = rating, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = it.selectFirst(selectMangaListImg)?.src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/id/Komikcast.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/id/Komikcast.kt index 45a7ce0a..4bdd6a64 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/id/Komikcast.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/id/Komikcast.kt @@ -123,7 +123,7 @@ internal class Komikcast(context: MangaLoaderContext) : return manga.copy( description = docs.selectFirst("div.komik_info-description-sinopsis")?.text(), state = mangaState, - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), contentRating = if (manga.isNsfw || nsfw) { ContentRating.ADULT } else { @@ -147,11 +147,11 @@ internal class Komikcast(context: MangaLoaderContext) : altTitle = null, publicUrl = a.attrAsAbsoluteUrl("href"), rating = rating, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = it.selectFirst("img.ts-post-image")?.src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangaworld/MangaWorldParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangaworld/MangaWorldParser.kt index f72621af..a62c2f14 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangaworld/MangaWorldParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangaworld/MangaWorldParser.kt @@ -144,6 +144,7 @@ internal abstract class MangaWorldParser( val href = div.selectFirstOrThrow("a.thumb").attrAsRelativeUrl("href") val tags = div.select(".genres a[href*=/archive?genre=]") .mapToSet { MangaTag(it.ownText().toTitleCase(sourceLocale), it.attr("href"), source) } + val author = div.selectFirst(".author a")?.text() Manga( id = generateUid(href), url = href, @@ -153,7 +154,7 @@ internal abstract class MangaWorldParser( altTitle = null, rating = RATING_UNKNOWN, tags = tags, - author = div.selectFirst(".author a")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (div.selectFirst(".status a")?.text()?.lowercase()) { "in corso" -> MangaState.ONGOING @@ -163,7 +164,7 @@ internal abstract class MangaWorldParser( else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/MmrcmsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/MmrcmsParser.kt index e47f938e..555c03aa 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/MmrcmsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/MmrcmsParser.kt @@ -131,10 +131,10 @@ internal abstract class MmrcmsParser( altTitle = null, rating = div.selectFirst("span")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -152,10 +152,10 @@ internal abstract class MmrcmsParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -194,7 +194,7 @@ internal abstract class MmrcmsParser( } } val alt = doc.body().selectFirst(selectAlt)?.nextElementSibling()?.textOrNull() - val auth = doc.body().selectFirst(selectAut)?.nextElementSibling()?.textOrNull() + val author = doc.body().selectFirst(selectAut)?.nextElementSibling()?.textOrNull() val tags = doc.body().selectFirst(selectTag)?.nextElementSibling()?.select("a") ?: emptySet() manga.copy( tags = tags.mapToSet { a -> @@ -204,7 +204,7 @@ internal abstract class MmrcmsParser( source = source, ) }, - author = auth, + authors = author?.let { setOf(it) } ?: emptySet(), description = desc, altTitle = alt, state = state, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/ar/Onma.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/ar/Onma.kt index ba298faf..5b48ee7c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/ar/Onma.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mmrcms/ar/Onma.kt @@ -35,10 +35,10 @@ internal class Onma(context: MangaLoaderContext) : altTitle = null, rating = div.selectFirstOrThrow("span").ownText().toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -58,7 +58,7 @@ internal class Onma(context: MangaLoaderContext) : } } val alt = doc.body().selectFirst(selectAlt)?.textOrNull() - val auth = doc.body().selectFirst(selectAut)?.textOrNull() + val author = doc.body().selectFirst(selectAut)?.textOrNull() val tags = doc.body().selectFirst(selectTag)?.select("a") ?: emptySet() manga.copy( tags = tags.mapToSet { a -> @@ -68,7 +68,7 @@ internal class Onma(context: MangaLoaderContext) : source = source, ) }, - author = auth, + authors = author?.let { setOf(it) } ?: emptySet(), description = desc, altTitle = alt, state = state, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt index b518dc12..f01e743c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt @@ -143,11 +143,11 @@ internal abstract class NepnepParser( url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = imgUrl, tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -182,6 +182,7 @@ internal abstract class NepnepParser( ) val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:SS", sourceLocale) + val author = doc.select(".list-group-item:contains(Author(s):) a").textOrNull() return manga.copy( state = when (doc.selectFirstOrThrow(".list-group-item:contains(Status:) a").text()) { @@ -207,7 +208,7 @@ internal abstract class NepnepParser( source = source, ) }, - author = doc.select(".list-group-item:contains(Author(s):) a").textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirstOrThrow(".top-5.Content").textOrNull(), chapters = chapter.mapJSONIndexed { i, j -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/onemanga/OneMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/onemanga/OneMangaParser.kt index 0b0bd09f..0e993d8a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/onemanga/OneMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/onemanga/OneMangaParser.kt @@ -31,6 +31,8 @@ internal abstract class OneMangaParser( val url = "https://$domain" val doc = webClient.httpGet(url).parseHtml() val manga = ArrayList() + val author = doc.selectFirst("div.elementor-widget-text-editor ul li:contains(Auteur(s))")?.text() + ?.replace("Auteur(s): ", "").orEmpty() manga.add( Manga( id = generateUid(url), @@ -42,12 +44,11 @@ internal abstract class OneMangaParser( ?.text()?.replace("Nom(s) Alternatif(s) :", "").orEmpty(), rating = RATING_UNKNOWN, tags = emptySet(), - author = doc.selectFirst("div.elementor-widget-text-editor ul li:contains(Auteur(s))")?.text() - ?.replace("Auteur(s): ", "").orEmpty(), + authors = setOf(author), description = doc.selectLast("div.elementor-widget-text-editor ul li")?.text().orEmpty(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ), ) return manga diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/otakusanctuary/OtakuSanctuaryParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/otakusanctuary/OtakuSanctuaryParser.kt index abeb1bc9..2f31dc42 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/otakusanctuary/OtakuSanctuaryParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/otakusanctuary/OtakuSanctuaryParser.kt @@ -115,10 +115,10 @@ internal abstract class OtakuSanctuaryParser( altTitle = null, rating = div.selectFirst(".rating")?.ownText()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -160,7 +160,7 @@ internal abstract class OtakuSanctuaryParser( } val alt = doc.body().selectFirst(selectAlt)?.textOrNull()?.replace("Other names", "")?.nullIfEmpty() - val auth = doc.body().selectFirst(selectAut)?.textOrNull() + val author = doc.body().selectFirst(selectAut)?.textOrNull() val dateFormat = SimpleDateFormat(datePattern, sourceLocale) @@ -175,7 +175,7 @@ internal abstract class OtakuSanctuaryParser( }, description = desc, altTitle = alt, - author = auth, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = doc.body().requireElementById("chapter").select("tr.chapter") .mapChapters(reversed = true) { i, tr -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt index 720c3a78..168b6200 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pizzareader/PizzaReaderParser.kt @@ -175,6 +175,12 @@ internal abstract class PizzaReaderParser( } private fun addManga(href: String, j: JSONObject): Manga { + val isNsfwSource = when (j.getString("adult").toInt()) { + 0 -> false + 1 -> true + else -> true + } + val author = j.getString("author") return Manga( id = generateUid(href), url = href, @@ -189,7 +195,7 @@ internal abstract class PizzaReaderParser( rating = j.getString("rating").toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, tags = emptySet(), - author = j.getString("author"), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (j.getString("status").lowercase()) { in ongoing -> MangaState.ONGOING in finished -> MangaState.FINISHED @@ -198,11 +204,7 @@ internal abstract class PizzaReaderParser( else -> null }, source = source, - isNsfw = when (j.getString("adult").toInt()) { - 0 -> false - 1 -> true - else -> true - }, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt index 345ba944..b2aceddd 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/BrMangas.kt @@ -98,11 +98,11 @@ internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context, url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -121,6 +121,7 @@ internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context, override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.select("div.serie-infos li:contains(Autor:)").text().replace("Autor:", "").nullIfEmpty() return manga.copy( tags = doc.select("div.serie-infos li:contains(Categorias:) a").mapToSet { a -> MangaTag( @@ -129,7 +130,7 @@ internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context, source = source, ) }, - author = doc.select("div.serie-infos li:contains(Autor:)").text().replace("Autor:", "").nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.select(".serie-texto p").html(), contentRating = if (doc.select("div.serie-infos li:contains(Categorias:)").text().contains("Hentai")) { ContentRating.ADULT diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerManga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerManga.kt index f81a9352..8670f89f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerManga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerManga.kt @@ -83,6 +83,7 @@ internal class LerManga(context: MangaLoaderContext) : PagedMangaParser(context, return doc.select(".tab-content .flw-item").map { div -> val a = div.selectFirstOrThrow("a.film-poster-ahref") val href = a.attrAsAbsoluteUrl("href") + val isNsfwSource = div.selectFirst(".tick-itemadult") != null Manga( id = generateUid(href), url = href, @@ -94,8 +95,8 @@ internal class LerManga(context: MangaLoaderContext) : PagedMangaParser(context, tags = emptySet(), description = null, state = null, - author = null, - isNsfw = div.selectFirst(".tick-itemadult") != null, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerMangaOnline.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerMangaOnline.kt index cbcf2e04..8c7e10e2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerMangaOnline.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LerMangaOnline.kt @@ -83,8 +83,8 @@ internal class LerMangaOnline(context: MangaLoaderContext) : tags = emptySet(), description = null, state = null, - author = null, - isNsfw = isNsfwSource, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LuratoonScansParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LuratoonScansParser.kt index e58848ab..6a367c57 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LuratoonScansParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/LuratoonScansParser.kt @@ -52,10 +52,10 @@ internal class LuratoonScansParser(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = false, + contentRating = null, ) } } @@ -65,6 +65,8 @@ internal class LuratoonScansParser(context: MangaLoaderContext) : val summaryContainer = doc.selectFirstOrThrow(".sumario__container") // 1 de Maio de 2024 às 20:15 val dateFormat = SimpleDateFormat("dd 'de' MMM 'de' YYYY 'às' HH:mm", sourceLocale) + val author = summaryContainer.getElementsContainingOwnText("Autor(es)").firstOrNull() + ?.nextElementSibling()?.textOrNull() return manga.copy( title = doc.selectFirst("h1.desc__titulo__comic")?.textOrNull() ?: manga.title, altTitle = summaryContainer.getElementsContainingOwnText("Alternativo").firstOrNull() @@ -83,8 +85,7 @@ internal class LuratoonScansParser(context: MangaLoaderContext) : "finalizado" -> MangaState.FINISHED else -> null }, - author = summaryContainer.getElementsContainingOwnText("Autor(es)").firstOrNull() - ?.nextElementSibling()?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), largeCoverUrl = doc.selectFirst("img.sumario__img")?.attrAsAbsoluteUrlOrNull("src"), description = summaryContainer.selectFirst(".sumario__sinopse__texto")?.html(), chapters = doc.selectFirstOrThrow("ul.capitulos__lista") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MangaOnline.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MangaOnline.kt index 678d2842..c7fea929 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MangaOnline.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MangaOnline.kt @@ -75,8 +75,8 @@ internal class MangaOnline(context: MangaLoaderContext) : PagedMangaParser(conte tags = emptySet(), description = null, state = null, - author = null, - isNsfw = isNsfwSource, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } @@ -141,8 +141,8 @@ internal class MangaOnline(context: MangaLoaderContext) : PagedMangaParser(conte tags = emptySet(), description = null, state = null, - author = null, - isNsfw = isNsfwSource, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MuitoHentai.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MuitoHentai.kt index a9c37629..e4fbe88a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MuitoHentai.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/MuitoHentai.kt @@ -70,8 +70,8 @@ internal class MuitoHentai(context: MangaLoaderContext) : PagedMangaParser(conte tags = emptySet(), description = null, state = null, - author = null, - isNsfw = isNsfwSource, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/OnePieceEx.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/OnePieceEx.kt index f224747b..804aff94 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/OnePieceEx.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/OnePieceEx.kt @@ -44,8 +44,8 @@ internal class OnePieceEx(context: MangaLoaderContext) : SinglePageMangaParser(c "que almeja ser pirata, embarca numa jornada com o sonho de se tornar " + "o Rei dos Piratas!!! (Fonte: MANGA Plus)", state = MangaState.ONGOING, - author = "Eiichiro Oda", - isNsfw = false, + authors = setOf("Eiichiro Oda"), + contentRating = null, source = source, ), @@ -64,8 +64,8 @@ internal class OnePieceEx(context: MangaLoaderContext) : SinglePageMangaParser(c "Eiichiro Oda respondendo as cartas de fãs sobre uma grande variedade " + "de assuntos. (Fonte: One Piece Wiki)", state = null, - author = "Eiichiro Oda", - isNsfw = false, + authors = setOf("Eiichiro Oda"), + contentRating = null, source = source, ), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/YugenMangas.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/YugenMangas.kt index c9c01d98..7bc31ba7 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/YugenMangas.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/pt/YugenMangas.kt @@ -87,8 +87,8 @@ internal class YugenMangas(context: MangaLoaderContext) : tags = emptySet(), description = null, state = null, - author = null, - isNsfw = isNsfwSource, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } @@ -103,11 +103,12 @@ internal class YugenMangas(context: MangaLoaderContext) : webClient.httpPost("https://api.$domain/api/chapters/get_chapters_by_serie/", body).parseJson() .getJSONArray("chapters") val dateFormat = SimpleDateFormat("dd/MM/yyyy", sourceLocale) + val author = detailManga.getStringOrNull("author") return manga.copy( description = detailManga.getString("synopsis"), coverUrl = detailManga.getString("cover"), altTitle = detailManga.getStringOrNull("alternative_names"), - author = detailManga.getStringOrNull("author"), + authors = author?.let { setOf(it) } ?: emptySet(), state = detailManga.getStringOrNull("status")?.let { when (it) { "ongoing" -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/AComics.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/AComics.kt index 6d78fb38..754b7b94 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/AComics.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/AComics.kt @@ -106,11 +106,11 @@ internal class AComics(context: MangaLoaderContext) : altTitle = null, publicUrl = url, rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = it.selectFirstOrThrow("img").src().orEmpty(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -141,10 +141,11 @@ internal class AComics(context: MangaLoaderContext) : val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val tagMap = getOrCreateTagMap() val tags = doc.select("p.serial-about-badges .category").mapNotNullToSet { tagMap[it.text()] } + val author = doc.selectFirst("p:contains(Автор оригинала:)")?.text()?.replace("Автор оригинала: ", "") return manga.copy( tags = tags, description = doc.selectFirst("section.serial-about-text p")?.text(), - author = doc.selectFirst("p:contains(Автор оригинала:)")?.text()?.replace("Автор оригинала: ", ""), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = listOf( MangaChapter( id = manga.id, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/DesuMeParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/DesuMeParser.kt index 8a091dab..237e31b5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/DesuMeParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/DesuMeParser.kt @@ -91,7 +91,7 @@ internal class DesuMeParser(context: MangaLoaderContext) : PagedMangaParser(cont }, rating = jo.getDouble("score").toFloat().coerceIn(0f, 1f), id = generateUid(id), - isNsfw = false, + contentRating = null, tags = if (!tagsMap.isNullOrEmpty()) { genres.mapNotNullToSet { g -> tagsMap[g.trim().toTitleCase()] @@ -99,7 +99,7 @@ internal class DesuMeParser(context: MangaLoaderContext) : PagedMangaParser(cont } else { emptySet() }, - author = null, + authors = emptySet(), description = jo.getString("description"), ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt index 4181644f..cc0d6b9d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/MangaWtfParser.kt @@ -125,6 +125,15 @@ internal class MangaWtfParser( .addPathSegment("books") .addPathSegment(manga.url) val jo = webClient.httpGet(url.build()).parseJson() + val isNsfwSource = jo.getStringOrNull("contentStatus").isNsfw() + val author = + jo.getJSONArray("relations").asTypedList().firstNotNullOfOrNull { + if (it.getStringOrNull("type") == "AUTHOR") { + it.getJSONObject("publisher").getStringOrNull("name") + } else { + null + } + } Manga( id = generateUid(jo.getString("id")), title = jo.getJSONObject("name").getString("ru"), @@ -132,18 +141,11 @@ internal class MangaWtfParser( url = jo.getString("id"), publicUrl = "https://$domain/manga/${jo.getString("slug")}", rating = jo.getFloatOrDefault("averageRating", -10f) / 10f, - isNsfw = jo.getStringOrNull("contentStatus").isNsfw(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = jo.getString("poster"), tags = jo.getJSONArray("labels").mapJSONToSet { it.toMangaTag() }, state = jo.getStringOrNull("status")?.toMangaState(), - author = - jo.getJSONArray("relations").asTypedList().firstNotNullOfOrNull { - if (it.getStringOrNull("type") == "AUTHOR") { - it.getJSONObject("publisher").getStringOrNull("name") - } else { - null - } - }, + authors = author?.let { setOf(it) } ?: emptySet(), source = source, largeCoverUrl = null, description = jo.getString("description").nl2br(), @@ -256,19 +258,21 @@ internal class MangaWtfParser( source = source, ) - private fun JSONObject.toManga() = - Manga( + private fun JSONObject.toManga(): Manga { + val isNsfwSource = getStringOrNull("contentStatus").isNsfw() + return Manga( id = generateUid(getString("id")), title = getJSONObject("name").getString("ru"), altTitle = getJSONObject("name").getStringOrNull("en"), url = getString("id"), publicUrl = "https://$domain/manga/${getString("slug")}", rating = getFloatOrDefault("averageRating", -10f) / 10f, - isNsfw = getStringOrNull("contentStatus").isNsfw(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = getString("poster"), tags = setOf(), state = getStringOrNull("status")?.toMangaState(), - author = null, + authors = emptySet(), source = source, ) + } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/NudeMoonParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/NudeMoonParser.kt index 7b1c0401..045b836d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/NudeMoonParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/NudeMoonParser.kt @@ -93,12 +93,13 @@ internal class NudeMoonParser( val a = row.selectFirstOrThrow("a") val href = a.attrAsRelativeUrl("href") val title = a.attr("title") + val author = row.getElementsByAttributeValueContaining("href", "/mangaka/").firstOrNull()?.textOrNull() Manga( id = generateUid(href), url = href, title = title.substringAfter(" / "), altTitle = title.substringBefore(" / ", "").takeUnless { it.isBlank() }, - author = row.getElementsByAttributeValueContaining("href", "/mangaka/").firstOrNull()?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), coverUrl = row.selectFirst("img")?.absUrl("src").orEmpty(), tags = row.selectFirst(".tag-links")?.select("a")?.mapToSet { MangaTag( @@ -110,7 +111,7 @@ internal class NudeMoonParser( source = source, publicUrl = a.absUrl("href"), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, description = row.selectFirst("div.description")?.html(), state = null, ) @@ -121,6 +122,7 @@ internal class NudeMoonParser( val body = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml().body() val root = body.selectFirstOrThrow("table.news_pic2") val dateFormat = SimpleDateFormat("dd MMMM yyyy", sourceLocale) + val author = root.getElementsByAttributeValueContaining("href", "/mangaka/").firstOrNull()?.text() return manga.copy( largeCoverUrl = body.selectFirstOrThrow("img[data-src]").attrAsAbsoluteUrl("data-src"), description = root.selectFirst(".description")?.html() ?: manga.description, @@ -131,8 +133,7 @@ internal class NudeMoonParser( source = source, ) } + manga.tags, - author = root.getElementsByAttributeValueContaining("href", "/mangaka/").firstOrNull()?.text() - ?: manga.author, + authors = author?.let { setOf(it) } ?: manga.authors, chapters = listOf( MangaChapter( id = manga.id, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/RemangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/RemangaParser.kt index 0c264b25..35165f08 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/RemangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/RemangaParser.kt @@ -115,8 +115,8 @@ internal class RemangaParser( rating = jo.getString("avg_rating").toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN, coverUrl = "https://api.$domain${img.getString("mid")}", largeCoverUrl = "https://api.$domain${img.getString("high")}", - author = null, - isNsfw = false, + authors = emptySet(), + contentRating = null, state = null, tags = jo.optJSONArray("genres")?.mapJSONToSet { g -> MangaTag( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/WaMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/WaMangaParser.kt index f8132c63..77e65234 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/WaMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/WaMangaParser.kt @@ -46,6 +46,7 @@ internal class WaMangaParser( private fun parseSmallMangaObject(doc: JSONObject): Manga { val url = doc.getString("url") + val author = doc.getStringOrNull("author") return Manga( id = generateUid(url), url = url, @@ -61,7 +62,7 @@ internal class WaMangaParser( "закончен" -> MangaState.FINISHED else -> MangaState.UPCOMING }, - author = doc.getStringOrNull("author"), + authors = author?.let { setOf(it) } ?: emptySet(), source = source, contentRating = if (doc.getIntOrDefault("adult", 0) == 0) { ContentRating.SAFE diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/grouple/GroupleParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/grouple/GroupleParser.kt index 274ccf3e..35dcc7db 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/grouple/GroupleParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/grouple/GroupleParser.kt @@ -137,6 +137,7 @@ internal abstract class GroupleParser( } val hashRegex = Regex("window.user_hash\\s*=\\s*\'([^\']+)\'") val userHash = doc.select("script").firstNotNullOfOrNull { it.html().findGroupValue(hashRegex) } + val author = root.selectFirst("a.person-link")?.textOrNull() return manga.copy( source = newSource, title = doc.metaValue("name") ?: manga.title, @@ -155,7 +156,7 @@ internal abstract class GroupleParser( source = source, ) }, - author = root.selectFirst("a.person-link")?.textOrNull() ?: manga.author, + authors = author?.let { setOf(it) } ?: manga.authors, contentRating = if (manga.isNsfw || root.select(".alert-warning") .any { it.ownText().contains(NSFW_ALERT) } ) { @@ -415,6 +416,7 @@ internal abstract class GroupleParser( if (relUrl.contains("://")) { return null } + val author = tileInfo?.selectFirst("a.person-link")?.text() return Manga( id = generateUid(relUrl), url = relUrl, @@ -425,8 +427,8 @@ internal abstract class GroupleParser( rating = runCatching { node.selectFirst(".compact-rate")?.attr("title")?.toFloatOrNull()?.div(5f) }.getOrNull() ?: RATING_UNKNOWN, - author = tileInfo?.selectFirst("a.person-link")?.text(), - isNsfw = defaultIsNsfw, + authors = author?.let { setOf(it) } ?: emptySet(), + contentRating = if (defaultIsNsfw) ContentRating.ADULT else null, tags = runCatching { tileInfo?.select("a.element-link")?.mapToSet { MangaTag( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt index 42083a4c..7c6ee593 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt @@ -50,16 +50,17 @@ internal abstract class ChanParser( ?: return@mapNotNull null val href = a.attrAsRelativeUrl("href") val title = a.text().parseTitle() + val author = row.getElementsByAttributeValueStarting( + "href", + "/mangaka", + ).firstOrNull()?.text() Manga( id = generateUid(href), url = href, publicUrl = href.toAbsoluteUrl(a.host ?: domain), altTitle = title.second, title = title.first, - author = row.getElementsByAttributeValueStarting( - "href", - "/mangaka", - ).firstOrNull()?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), coverUrl = row.selectFirst("div.manga_images")?.selectFirst("img") ?.absUrl("src").orEmpty(), tags = runCatching { @@ -73,7 +74,7 @@ internal abstract class ChanParser( }.getOrNull().orEmpty(), rating = RATING_UNKNOWN, state = null, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } @@ -165,21 +166,22 @@ internal abstract class ChanParser( val a = info.selectFirst("a") ?: return@mapNotNull null val href = a.attrAsRelativeUrl("href") val title = a.text().parseTitle() + val author = info.getElementsByAttributeValueStarting( + "href", + "/mangaka", + ).firstOrNull()?.text() Manga( id = generateUid(href), url = href, publicUrl = href.toAbsoluteUrl(a.host ?: domain), altTitle = title.second, title = title.first, - author = info.getElementsByAttributeValueStarting( - "href", - "/mangaka", - ).firstOrNull()?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), coverUrl = div.selectFirst("img")?.absUrl("src").orEmpty(), tags = emptySet(), rating = RATING_UNKNOWN, state = null, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/rulib/LibSocialParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/rulib/LibSocialParser.kt index ab80425c..938f210c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/rulib/LibSocialParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/rulib/LibSocialParser.kt @@ -143,11 +143,12 @@ internal abstract class LibSocialParser( val tags = json.getJSONArray("genres").mapJSON { jo -> MangaTag(title = jo.getString("name"), key = "t" + jo.getInt("id"), source = source) } + val author = json.getJSONArray("authors").optJSONObject(0)?.getStringOrNull("name") manga.copy( title = json.getStringOrNull("rus_name") ?: manga.title, altTitle = json.getStringOrNull("name"), tags = tagsSetOf(tags, genres), - author = json.getJSONArray("authors").optJSONObject(0)?.getStringOrNull("name"), + authors = author?.let { setOf(it) } ?: emptySet(), description = json.getString("summary").nl2br(), chapters = chapters.await(), ) @@ -204,6 +205,7 @@ internal abstract class LibSocialParser( private fun parseManga(jo: JSONObject): Manga { val cover = jo.getJSONObject("cover") + val isNsfwSource = jo.getJSONObject("ageRestriction").getIntOrDefault("id", 0) >= 3 return Manga( id = generateUid(jo.getLong("id")), title = jo.getString("rus_name").ifEmpty { jo.getString("name") }, @@ -212,11 +214,11 @@ internal abstract class LibSocialParser( publicUrl = "https://$siteDomain/ru/manga/" + jo.getString("slug_url"), rating = jo.optJSONObject("rating") ?.getFloatOrDefault("average", RATING_UNKNOWN * 10f)?.div(10f) ?: RATING_UNKNOWN, - isNsfw = jo.getJSONObject("ageRestriction").getIntOrDefault("id", 0) >= 3, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = cover.getString("thumbnail"), tags = setOf(), state = statesMap[jo.optJSONObject("status")?.getIntOrDefault("id", -1) ?: -1], - author = null, + authors = emptySet(), largeCoverUrl = cover.getString("default"), source = source, ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/ScanParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/ScanParser.kt index e2636664..1e626e44 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/ScanParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/ScanParser.kt @@ -102,10 +102,10 @@ internal abstract class ScanParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } @@ -140,13 +140,14 @@ internal abstract class ScanParser( val selectTag = doc.select(".card-series-detail .col-6:contains(Categorie) div, .card-series-about .mb-3:contains(Categorie) a, .card-series-about .mb-3:contains(Categorias) a") val tags = selectTag.mapNotNullToSet { tagMap[it.text()] } + val author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div, .card-series-about .mb-3:contains(Autore) a") + ?.textOrNull() return manga.copy( rating = doc.selectFirst(".card-series-detail .rate-value span, .card-series-about .rate-value span") ?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = tags, - author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div, .card-series-about .mb-3:contains(Autore) a") - ?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), 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") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/fr/MangaFr.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/fr/MangaFr.kt index c644882d..f7ae55e4 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/fr/MangaFr.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/fr/MangaFr.kt @@ -19,13 +19,14 @@ internal class MangaFr(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("MM-dd-yyyy", sourceLocale) + val author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div, .card-series-about .mb-3:contains(Autore) a") + ?.textOrNull() return manga.copy( rating = doc.selectFirst(".card-series-detail .rate-value span, .card-series-about .rate-value span") ?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = emptySet(), - author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div, .card-series-about .mb-3:contains(Autore) a") - ?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), 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") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/it/ScanIta.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/it/ScanIta.kt index ee5c1522..8e022ea5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/it/ScanIta.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/scan/it/ScanIta.kt @@ -23,11 +23,12 @@ internal class ScanIta(context: MangaLoaderContext) : val selectTag = doc.select(".card-series-detail .col-6:contains(Categorie) div") val tags = selectTag.mapNotNullToSet { tagMap[it.text()] } val chaptersDeferred = async { loadChapters(doc) } + val author = doc.selectFirst(".card-series-detail .col-6:contains(Autore) div")?.textOrNull() manga.copy( 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")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), 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(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/sinmh/SinmhParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/sinmh/SinmhParser.kt index 28a1eccf..089ed9cf 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/sinmh/SinmhParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/sinmh/SinmhParser.kt @@ -115,10 +115,10 @@ internal abstract class SinmhParser( altTitle = null, rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/MangaAy.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/MangaAy.kt index 21e28e92..6bddf557 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/MangaAy.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/MangaAy.kt @@ -96,8 +96,8 @@ internal class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context, tags = emptySet(), description = null, state = null, - author = null, - isNsfw = isNsfwSource, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } @@ -118,8 +118,8 @@ internal class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context, tags = emptySet(), description = null, state = null, - author = null, - isNsfw = isNsfwSource, + authors = emptySet(), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/SadScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/SadScans.kt index ccb6d26a..60f39fbe 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/SadScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/SadScans.kt @@ -50,11 +50,11 @@ internal class SadScans(context: MangaLoaderContext) : SinglePageMangaParser(con url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = div.selectFirstOrThrow("img").src()?.toAbsoluteUrl(domain).orEmpty(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -63,6 +63,7 @@ internal class SadScans(context: MangaLoaderContext) : SinglePageMangaParser(con override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("dd MMM, yy", Locale.ENGLISH) + val author = doc.selectLast(".author span")?.textOrNull() return manga.copy( state = when (doc.select(".status span").last()?.text()) { "Devam ediyor" -> MangaState.ONGOING @@ -70,7 +71,7 @@ internal class SadScans(context: MangaLoaderContext) : SinglePageMangaParser(con else -> null }, tags = emptySet(), - author = doc.selectLast(".author span")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirstOrThrow(".summary").html(), chapters = doc.select(".chap-section .chap") .mapChapters(reversed = true) { i, div -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt index 19d14bbd..be12e2bd 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/tr/TrWebtoon.kt @@ -110,14 +110,14 @@ internal class TrWebtoon(context: MangaLoaderContext) : rating = li.selectFirst(".row .col-xl-4 .mt-2 .my-1 .text-muted")?.text()?.substringBefore("/") ?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = when (doc.selectLast(".row .col-xl-4 .mt-2 .rounded-pill")?.text()) { "Devam Ediyor", "Güncel" -> MangaState.ONGOING "Tamamlandı" -> MangaState.FINISHED else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -134,14 +134,14 @@ internal class TrWebtoon(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = when (doc.selectFirst("d-inline .badge")?.text()) { "Devam Ediyor", "Güncel" -> MangaState.ONGOING "Tamamlandı" -> MangaState.FINISHED else -> null }, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt index b18e14c1..4b284921 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HentaiUkrParser.kt @@ -110,6 +110,7 @@ internal class HentaiUkrParser(context: MangaLoaderContext) : MangaParser(contex // Return to app return json.drop(offset).take(PAGE_SIZE).map { jo -> val id = jo.getAsLong() + val author = jo.getStringOrNull("author") Manga( id = generateUid(id), title = jo.getString("name"), @@ -117,11 +118,11 @@ internal class HentaiUkrParser(context: MangaLoaderContext) : MangaParser(contex url = jo.getString("url"), publicUrl = jo.getString("url").toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = jo.getString("thumb").toAbsoluteUrl(domain), tags = getTags(jo.optJSONArray("tags")), state = null, - author = jo.getStringOrNull("author"), + authors = author?.let { setOf(it) } ?: emptySet(), largeCoverUrl = null, description = null, chapters = null, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HoneyMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HoneyMangaParser.kt index 3c842804..67f9d1de 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HoneyMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/HoneyMangaParser.kt @@ -149,6 +149,7 @@ internal class HoneyMangaParser(context: MangaLoaderContext) : return content.mapJSON { jo -> val id = jo.getString("id") val posterUrl = jo.getString("posterUrl") + val isNsfwSource = isNsfw(jo.getStringOrNull("adult")) Manga( id = generateUid(id), title = jo.getString("title"), @@ -156,7 +157,7 @@ internal class HoneyMangaParser(context: MangaLoaderContext) : url = id, publicUrl = "https://$domain/book/$id", rating = RATING_UNKNOWN, - isNsfw = isNsfw(jo.getStringOrNull("adult")), + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = getCoverUrl(posterUrl, 256), tags = getTitleTags(jo.optJSONArray("genresAndTags")), state = when (jo.getStringOrNull("titleStatus")) { @@ -164,7 +165,7 @@ internal class HoneyMangaParser(context: MangaLoaderContext) : "Завершено" -> MangaState.FINISHED else -> null }, - author = null, + authors = emptySet(), largeCoverUrl = getCoverUrl(posterUrl, 1080), description = jo.getStringOrNull("description"), chapters = null, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/MangaInUaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/MangaInUaParser.kt index ef0755ba..9fbf70bb 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/MangaInUaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/uk/MangaInUaParser.kt @@ -69,6 +69,7 @@ internal class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser( val items = container.select("div.col-6") return items.mapNotNull { item -> val href = item.selectFirst("a")?.attrAsRelativeUrl("href") ?: return@mapNotNull null + val isNsfwSource = item.selectFirst("ul.card__list")?.select("li")?.lastOrNull()?.text() == "18+" Manga( id = generateUid(href), title = item.selectFirst("h3.card__title")?.text() ?: return@mapNotNull null, @@ -76,11 +77,11 @@ internal class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser( attrAsAbsoluteUrlOrNull("data-src") ?: attrAsAbsoluteUrlOrNull("src") }.orEmpty(), altTitle = null, - author = null, + authors = emptySet(), rating = item.selectFirst("div.card__short-rate--num")?.text()?.toFloatOrNull()?.div(10F) ?: RATING_UNKNOWN, url = href, - isNsfw = item.selectFirst("ul.card__list")?.select("li")?.lastOrNull()?.text() == "18+", + contentRating = if (isNsfwSource) ContentRating.ADULT else null, tags = runCatching { item.selectFirst("div.card__category")?.select("a")?.mapToSet { MangaTag( diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenParser.kt index eb7b86a0..eba7c8b0 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenParser.kt @@ -84,10 +84,10 @@ internal class BlogTruyenParser(context: MangaLoaderContext) : url = relativeUrl, publicUrl = relativeUrl.toAbsoluteUrl(domain), coverUrl = mangaInfo.selectFirst("div > img.img")?.src().orEmpty(), - isNsfw = false, + contentRating = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, ) @@ -125,10 +125,11 @@ internal class BlogTruyenParser(context: MangaLoaderContext) : val tagName = it.selectFirst("a")?.textOrNull() ?: return@mapNotNullToSet null tagMap[tagName] } + val author = descriptionElement.selectFirst("p:contains(Tác giả) > a")?.textOrNull() return manga.copy( tags = tags, - author = descriptionElement.selectFirst("p:contains(Tác giả) > a")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirst(".detail .content")?.html(), chapters = parseChapterList(doc), largeCoverUrl = doc.selectLast("div.thumbnail > img")?.src(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenVN.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenVN.kt index 74df4cc7..a4a18a72 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenVN.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BlogTruyenVN.kt @@ -97,9 +97,9 @@ internal class BlogTruyenVN(context: MangaLoaderContext) : coverUrl = linkTag.selectLast("img")?.src().orEmpty(), source = source, tags = tags ?: emptySet(), - isNsfw = false, + contentRating = null, rating = RATING_UNKNOWN, - author = null, + authors = emptySet(), state = null, ) } @@ -120,10 +120,10 @@ internal class BlogTruyenVN(context: MangaLoaderContext) : url = relativeUrl, publicUrl = relativeUrl.toAbsoluteUrl(domain), coverUrl = mangaInfo.selectFirst("div > img.img")?.src().orEmpty(), - isNsfw = false, + contentRating = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, ) @@ -177,10 +177,11 @@ internal class BlogTruyenVN(context: MangaLoaderContext) : tagMap[tagName] } } + val author = descriptionElement.selectFirst("p:contains(Tác giả) > a")?.textOrNull() return manga.copy( tags = tags ?: emptySet(), - author = descriptionElement.selectFirst("p:contains(Tác giả) > a")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirst(".detail .content")?.html(), chapters = parseChapterList(doc), largeCoverUrl = doc.selectLast("div.thumbnail > img")?.src(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BuonDuaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BuonDuaParser.kt index aa2e67c8..990bf4df 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BuonDuaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/BuonDuaParser.kt @@ -113,7 +113,7 @@ internal class BuonDuaParser(context: MangaLoaderContext) : MangaParser(context, ) }, state = MangaState.FINISHED, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, chapters = null, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CMangaParser.kt index 6043ef05..afd76828 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CMangaParser.kt @@ -184,7 +184,7 @@ internal class CMangaParser(context: MangaLoaderContext) : url = relativeUrl, publicUrl = relativeUrl.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = "/assets/tmp/album/${info.getString("avatar")}".toAbsoluteUrl(domain), tags = info.optJSONArray("tags")?.asTypedList() ?.mapNotNullToSet { tags.get()[it.lowercase()] } @@ -194,7 +194,7 @@ internal class CMangaParser(context: MangaLoaderContext) : "done" -> MangaState.FINISHED else -> null }, - author = null, + authors = emptySet(), largeCoverUrl = null, description = info.getStringOrNull("detail")?.replace("\\\"", "\""), chapters = emptyList(), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CuuTruyenParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CuuTruyenParser.kt index 7ede5846..108b80cb 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CuuTruyenParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/CuuTruyenParser.kt @@ -107,6 +107,7 @@ internal class CuuTruyenParser(context: MangaLoaderContext) : val data = json.optJSONArray("data") ?: json.getJSONObject("data").getJSONArray("mangas") return data.mapJSON { jo -> + val author = jo.getStringOrNull("author_name") Manga( id = generateUid(jo.getLong("id")), url = "/api/v2/mangas/${jo.getLong("id")}", @@ -115,11 +116,11 @@ internal class CuuTruyenParser(context: MangaLoaderContext) : altTitle = null, coverUrl = jo.getString("cover_mobile_url"), largeCoverUrl = jo.getString("cover_url"), - author = jo.getStringOrNull("author_name"), + authors = author?.let { setOf(it) } ?: emptySet(), tags = emptySet(), state = null, description = null, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, rating = RATING_UNKNOWN, ) @@ -152,6 +153,7 @@ internal class CuuTruyenParser(context: MangaLoaderContext) : // Remove old manga status from "tags" val newTags = tags.filter { it.key != "da-hoan-thanh" && it.key != "dang-tien-hanh" }.toSet() + val author = json.optJSONObject("author")?.getStringOrNull("name")?.substringBefore(',')?.nullIfEmpty() manga.copy( title = json.getStringOrNull("name") ?: manga.title, @@ -160,7 +162,7 @@ internal class CuuTruyenParser(context: MangaLoaderContext) : } else { ContentRating.SAFE }, - author = json.optJSONObject("author")?.getStringOrNull("name")?.substringBefore(',')?.nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), description = json.getStringOrNull("full_description"), tags = newTags, state = state, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt index 7758ed43..8ffb5ceb 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/DuaLeoTruyen.kt @@ -76,11 +76,11 @@ internal class DuaLeoTruyen(context: MangaLoaderContext) : url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = li.selectFirst("img")?.absUrl("data-src").orEmpty(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -89,6 +89,7 @@ internal class DuaLeoTruyen(context: MangaLoaderContext) : override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH) + val author = doc.selectFirst(".info-item:has(.fa-user)")?.textOrNull()?.removePrefix("Tác giả: ") return manga.copy( altTitle = doc.selectFirst(".box_info_right h2")?.textOrNull(), @@ -104,7 +105,7 @@ internal class DuaLeoTruyen(context: MangaLoaderContext) : "Full" -> MangaState.FINISHED else -> null }, - author = doc.selectFirst(".info-item:has(.fa-user)")?.textOrNull()?.removePrefix("Tác giả: "), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirst(".story-detail-info")?.html(), chapters = doc.select(".list-chapters .chapter-item").mapChapters(reversed = true) { i, div -> val a = div.selectFirstOrThrow(".chap_name a") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/GocTruyenTranh.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/GocTruyenTranh.kt index fa16abb2..39524a38 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/GocTruyenTranh.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/GocTruyenTranh.kt @@ -152,7 +152,7 @@ internal class GocTruyenTranh(context: MangaLoaderContext) : altTitle = item.optString("origin_name")?.takeUnless { it == "null" || it.isEmpty() }, description = item.optString("content"), rating = RATING_UNKNOWN, - isNsfw = checkNsfw || isNsfwSource, + contentRating = if (checkNsfw || isNsfwSource) ContentRating.ADULT else null, coverUrl = item.optString("thumbnail"), tags = tags, state = when (item.optString("status")) { @@ -161,16 +161,17 @@ internal class GocTruyenTranh(context: MangaLoaderContext) : else -> null }, source = source, - author = null, + authors = emptySet(), ) } } override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst("aside p:contains(Tác giả:) a[href^='/tac-gia/']")?.text() return manga.copy( rating = doc.selectFirst("div > span.leading-none")?.text()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN, - author = doc.selectFirst("aside p:contains(Tác giả:) a[href^='/tac-gia/']")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), chapters = doc.select("ul[itemtype='https://schema.org/ItemList'] li").mapChapters(reversed = true) { i, li -> val a = li.selectFirstOrThrow("a") val href = a.attrAsRelativeUrl("href") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/Hentai18VN.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/Hentai18VN.kt index 71ad6ec7..5f60b254 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/Hentai18VN.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/Hentai18VN.kt @@ -102,12 +102,12 @@ internal class Hentai18VN(context: MangaLoaderContext) : PagedMangaParser(contex publicUrl = href.toAbsoluteUrl(domain), title = mangaInfo.attr("alt"), altTitle = null, - author = null, + authors = emptySet(), tags = emptySet(), rating = RATING_UNKNOWN, state = null, coverUrl = mangaInfo.requireSrc(), - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source ) } @@ -124,13 +124,13 @@ internal class Hentai18VN(context: MangaLoaderContext) : PagedMangaParser(contex url = mangaUrl.removePrefix("https://$domain"), title = a.text(), altTitle = null, - author = null, + authors = emptySet(), description = null, tags = emptySet(), rating = RATING_UNKNOWN, state = null, coverUrl = img.attr("data-original").takeIf { it.isNotEmpty() } ?: img.attr("src"), - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, source = source, ) } @@ -172,7 +172,7 @@ internal class Hentai18VN(context: MangaLoaderContext) : PagedMangaParser(contex return manga.copy( tags = tags, - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), altTitle = altTitle, state = state, chapters = chapters, @@ -225,4 +225,4 @@ internal class Hentai18VN(context: MangaLoaderContext) : PagedMangaParser(contex 0L } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVNParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVNParser.kt index 08d7e495..d5e3ca6e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVNParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVNParser.kt @@ -110,11 +110,12 @@ internal class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context val tags = genre.mapNotNullToSet { tagMap[it.text()] } val infoEl = infoElDeferred.await() val stateDoc = stateDocDeferred.await() + val author = infoEl.select("p:contains(Tác giả:) a").textOrNull() manga.copy( altTitle = infoEl.selectFirst("span.info:contains(Tên Khác:)")?.parent()?.select("span:not(.info) > a") ?.joinToString { it.text() } ?.nullIfEmpty(), - author = infoEl.select("p:contains(Tác giả:) a").textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), 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 { @@ -198,11 +199,11 @@ internal class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context url = relativeUrl, publicUrl = relativeUrl.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = el.selectFirst("div.box-cover img, div.box-cover-2 img")?.src().orEmpty(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -225,11 +226,11 @@ internal class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context url = relativeUrl, publicUrl = relativeUrl.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = el.selectFirst("div.search-img img")?.attrAsAbsoluteUrlOrNull("data-cfsrc").orEmpty(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVnBuzz.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVnBuzz.kt index 50076ea0..a141fb9a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVnBuzz.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/HentaiVnBuzz.kt @@ -126,11 +126,11 @@ internal class HentaiVnBuzz(context: MangaLoaderContext) : PagedMangaParser(cont url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = coverUrl, tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -148,11 +148,11 @@ internal class HentaiVnBuzz(context: MangaLoaderContext) : PagedMangaParser(cont url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = coverUrl, tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -160,9 +160,10 @@ internal class HentaiVnBuzz(context: MangaLoaderContext) : PagedMangaParser(cont override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.select("p:contains(Tác giả:) a").text().nullIfEmpty() return manga.copy( altTitle = null, - author = doc.select("p:contains(Tác giả:) a").text().nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), tags = doc.select("div.mb-1 span a").mapToSet { element -> MangaTag( key = element.attr("href").substringAfter("/the-loai/"), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/KuroNeko.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/KuroNeko.kt index 2bd46af7..bfa3899e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/KuroNeko.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/KuroNeko.kt @@ -135,11 +135,11 @@ internal class KuroNeko(context: MangaLoaderContext) : PagedMangaParser(context, url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = coverUrl.orEmpty(), tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -147,6 +147,7 @@ internal class KuroNeko(context: MangaLoaderContext) : PagedMangaParser(context, override suspend fun getDetails(manga: Manga): Manga { val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = root.selectFirst("div.mt-2:contains(Tác giả) span a")?.textOrNull() return manga.copy( altTitle = root.selectLast("div.grow div:contains(Tên khác) span")?.textOrNull(), @@ -162,7 +163,7 @@ internal class KuroNeko(context: MangaLoaderContext) : PagedMangaParser(context, source = source, ) }, - author = root.selectFirst("div.mt-2:contains(Tác giả) span a")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = root.selectFirst("meta[name=description]")?.attrOrNull("content"), chapters = root.select("div.justify-between ul.overflow-y-auto.overflow-x-hidden a") .mapChapters(reversed = true) { i, a -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/LxManga.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/LxManga.kt index 4287cd03..b4138b75 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/LxManga.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/LxManga.kt @@ -136,11 +136,11 @@ internal class LxManga(context: MangaLoaderContext) : PagedMangaParser(context, url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = coverUrl, tags = setOf(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -148,6 +148,7 @@ internal class LxManga(context: MangaLoaderContext) : PagedMangaParser(context, override suspend fun getDetails(manga: Manga): Manga { val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = root.selectFirst("div.mt-2:contains(Tác giả) span a")?.textOrNull() return manga.copy( altTitle = root.selectLast("div.grow div:contains(Tên khác) span")?.textOrNull(), @@ -163,7 +164,7 @@ internal class LxManga(context: MangaLoaderContext) : PagedMangaParser(context, source = source, ) }, - author = root.selectFirst("div.mt-2:contains(Tác giả) span a")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), description = root.selectFirst("meta[name=description]")?.attrOrNull("content"), chapters = root.select("div.justify-between ul.overflow-y-auto.overflow-x-hidden a") .mapChapters(reversed = true) { i, a -> diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/SayHentai.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/SayHentai.kt index 79bd21ed..d59cd414 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/SayHentai.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/SayHentai.kt @@ -76,19 +76,20 @@ internal class SayHentai(context: MangaLoaderContext) : PagedMangaParser(context altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst("div.summary-heading:contains(Tác giả) + div.summary-content")?.textOrNull() return manga.copy( altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.selectFirst("div.summary-heading:contains(Tác giả) + div.summary-content")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), tags = doc.select("div.genres-content a[rel=tag]").mapToSet { a -> MangaTag( key = a.attr("href").substringAfterLast('/'), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenGG.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenGG.kt index d6524f8e..e5453085 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenGG.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenGG.kt @@ -126,11 +126,11 @@ internal class TruyenGG(context: MangaLoaderContext) : PagedMangaParser(context, url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = div.selectFirst(".image-cover img")?.attr("data-src").orEmpty(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -139,10 +139,11 @@ internal class TruyenGG(context: MangaLoaderContext) : PagedMangaParser(context, override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH) + val author = doc.select("p:contains(Tác Giả) + p").joinToString { it.text() }.nullIfEmpty() return manga.copy( altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.select("p:contains(Tác Giả) + p").joinToString { it.text() }.nullIfEmpty(), + authors = author?.let { setOf(it) } ?: emptySet(), tags = doc.select("a.clblue").mapToSet { MangaTag( key = it.attr("href").substringAfterLast('-').substringBeforeLast('.'), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenHentaiVN.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenHentaiVN.kt index 2c3bd5c9..a2b28fd7 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenHentaiVN.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenHentaiVN.kt @@ -81,12 +81,12 @@ internal class TruyenHentaiVN(context: MangaLoaderContext) : PagedMangaParser(co publicUrl = href.toAbsoluteUrl(domain), title = title, altTitle = null, - author = null, + authors = emptySet(), tags = emptySet(), rating = RATING_UNKNOWN, state = null, coverUrl = cover, - isNsfw = true, + contentRating = ContentRating.ADULT, source = source ) } @@ -94,8 +94,9 @@ internal class TruyenHentaiVN(context: MangaLoaderContext) : PagedMangaParser(co override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() + val author = doc.selectFirst("div.author i")?.text() return manga.copy( - author = doc.selectFirst("div.author i")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), tags = doc.select("div.genre.mb-3.mgen a").mapNotNull { a -> val key = a.attr("href").substringAfterLast("-") val title = a.text().trim() @@ -172,4 +173,4 @@ internal class TruyenHentaiVN(context: MangaLoaderContext) : PagedMangaParser(co } return tagMap } -} \ No newline at end of file +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenQQ.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenQQ.kt index 7200cb77..1d9d3997 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenQQ.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenQQ.kt @@ -126,11 +126,11 @@ internal class TruyenQQ(context: MangaLoaderContext) : PagedMangaParser(context, url = href, publicUrl = href.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, coverUrl = li.selectFirst("img")?.src().orEmpty(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -150,6 +150,7 @@ internal class TruyenQQ(context: MangaLoaderContext) : PagedMangaParser(context, override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH) + val author = doc.selectFirst("li.author a")?.text() return manga.copy( altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), tags = doc.select("ul.list01 li").mapToSet { @@ -165,7 +166,7 @@ internal class TruyenQQ(context: MangaLoaderContext) : PagedMangaParser(context, "Hoàn Thành" -> MangaState.FINISHED else -> null }, - author = doc.selectFirst("li.author a")?.text(), + authors = author?.let { setOf(it) } ?: emptySet(), description = doc.selectFirst(".story-detail-info")?.html(), chapters = doc.select("div.list_chapter div.works-chapter-item").mapChapters(reversed = true) { i, div -> val a = div.selectFirstOrThrow("a") diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenTranh3Q.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenTranh3Q.kt index bf75bb99..7b7bc483 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenTranh3Q.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/TruyenTranh3Q.kt @@ -124,11 +124,11 @@ internal class TruyenTranh3Q(context: MangaLoaderContext) : url = href, publicUrl = aTag.attrAsAbsoluteUrl("href"), rating = RATING_UNKNOWN, - isNsfw = isNsfw, + contentRating = if (isNsfw) ContentRating.ADULT else null, coverUrl = element.selectFirst(".book_avatar a img")?.src(), tags = tags, state = null, - author = null, + authors = emptySet(), source = source, ) } @@ -143,10 +143,11 @@ internal class TruyenTranh3Q(context: MangaLoaderContext) : source = source, ) } + val author = doc.selectFirst("li.author a")?.textOrNull() return manga.copy( altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.selectFirst("li.author a")?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), tags = tags, description = doc.selectFirst("div.story-detail-info")?.html(), state = when (doc.selectFirst(".status p.col-xs-9")?.text()) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt index 20ea712d..6e9f97c1 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/VcomycsParser.kt @@ -102,7 +102,7 @@ internal class VcomycsParser(context: MangaLoaderContext) : PagedMangaParser(con coverUrl = jo.getString("img"), tags = emptySet(), state = null, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, chapters = null, @@ -136,7 +136,7 @@ internal class VcomycsParser(context: MangaLoaderContext) : PagedMangaParser(con coverUrl = linkEl.selectFirstOrThrow(".img-thumbnail").src(), tags = emptySet(), state = null, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, chapters = null, @@ -148,6 +148,7 @@ internal class VcomycsParser(context: MangaLoaderContext) : PagedMangaParser(con override suspend fun getDetails(manga: Manga): Manga { val content = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val info = content.selectFirstOrThrow(".comic-info") + val author = info.selectFirst(".comic-intro-text > strong:contains(Tác giả:)")?.nextElementSibling()?.textOrNull() return manga.copy( rating = info.getElementById("cate-rating")?.let { val score = it.attrOrNull("data-score")?.toIntOrNull() @@ -157,8 +158,7 @@ internal class VcomycsParser(context: MangaLoaderContext) : PagedMangaParser(con } ?: RATING_UNKNOWN, altTitle = info.selectFirst(".comic-intro-text > strong:contains(Tên khác:)")?.nextElementSibling() ?.textOrNull(), - author = info.selectFirst(".comic-intro-text > strong:contains(Tác giả:)")?.nextElementSibling() - ?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = when (info.selectFirst(".comic-stt")?.text()) { "Đang tiến hành" -> MangaState.ONGOING "Trọn bộ" -> MangaState.FINISHED diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt index b4ed8840..7044726b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vi/YurinekoParser.kt @@ -63,6 +63,9 @@ internal class YurinekoParser(context: MangaLoaderContext) : PagedMangaParser(co .mapJSON { jo -> val id = jo.getLong("id") val relativeUrl = "/manga/$id" + val author = jo.getJSONArray("author") + .mapJSON { author -> author.getString("name") } + .joinToString { it } Manga( id = generateUid(id), title = jo.getString("originalName"), @@ -70,7 +73,7 @@ internal class YurinekoParser(context: MangaLoaderContext) : PagedMangaParser(co url = relativeUrl, publicUrl = relativeUrl.toAbsoluteUrl(domain), rating = RATING_UNKNOWN, - isNsfw = true, + contentRating = ContentRating.ADULT, coverUrl = "https://$storageDomain/${jo.getString("thumbnail")}", tags = jo.getJSONArray("tag").mapJSONToSet { tag -> MangaTag( @@ -85,9 +88,7 @@ internal class YurinekoParser(context: MangaLoaderContext) : PagedMangaParser(co 5, 6, 7 -> MangaState.ABANDONED else -> null }, - author = jo.getJSONArray("author") - .mapJSON { author -> author.getString("name") } - .joinToString { it }, + authors = setOf(author), description = jo.getStringOrNull("description"), source = source, ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vmp/VmpParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vmp/VmpParser.kt index eba126d6..f3c23294 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vmp/VmpParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/vmp/VmpParser.kt @@ -87,10 +87,10 @@ internal abstract class VmpParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/WpComicsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/WpComicsParser.kt index 6a1c7275..a6ab955f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/WpComicsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/WpComicsParser.kt @@ -155,6 +155,7 @@ internal abstract class WpComicsParser( val tagsElement = tooltipElement?.selectFirst("div.message_main > p:contains(Thể loại)")?.ownText().orEmpty() val mangaTags = tagsElement.split(',').mapNotNullToSet { tagMap[it.trim()] } + val author = tooltipElement?.selectFirst("div.message_main > p:contains(Tác giả)")?.ownText() Manga( id = generateUid(slug), title = item.selectFirst("div.box_tootip div.title, h3 a")?.text().orEmpty(), @@ -162,12 +163,12 @@ internal abstract class WpComicsParser( url = absUrl.toRelativeUrl(domain), publicUrl = absUrl, rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = item.selectFirst("div.image a img")?.findImageUrl().orEmpty(), largeCoverUrl = null, tags = mangaTags, state = mangaState, - author = tooltipElement?.selectFirst("div.message_main > p:contains(Tác giả)")?.ownText(), + authors = author?.let { setOf(it) } ?: emptySet(), description = tooltipElement?.selectFirst("div.box_text")?.text(), chapters = null, source = source, @@ -215,10 +216,11 @@ internal abstract class WpComicsParser( val tagMap = getOrCreateTagMap() val tagsElement = doc.select("li.kind p.col-xs-8 a") val mangaTags = tagsElement.mapNotNullToSet { tagMap[it.text()] } + val author = doc.body().select(selectAut).textOrNull() manga.copy( description = doc.selectFirst(selectDesc)?.html(), altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.body().select(selectAut).textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = doc.selectFirst(selectState)?.let { when (it.text()) { in ongoing -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/en/XoxoComics.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/en/XoxoComics.kt index 5ddf2c16..7ee80887 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/en/XoxoComics.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/en/XoxoComics.kt @@ -90,10 +90,10 @@ internal class XoxoComics(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -128,7 +128,7 @@ internal class XoxoComics(context: MangaLoaderContext) : else -> null } } - val aut = doc.body().select(selectAut).textOrNull() + val author = doc.body().select(selectAut).textOrNull() manga.copy( tags = doc.body().select(selectTag).mapToSet { a -> MangaTag( @@ -138,7 +138,7 @@ internal class XoxoComics(context: MangaLoaderContext) : ) }, description = desc, - author = aut, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = chaptersDeferred.await(), ) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt index 84c3f993..c8aaac78 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/DocTruyen3Q.kt @@ -104,10 +104,10 @@ internal class DocTruyen3Q(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = mangaTags, - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -147,7 +147,7 @@ internal class DocTruyen3Q(context: MangaLoaderContext) : } return manga.copy( - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), description = description, state = state, tags = tags, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/HamTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/HamTruyen.kt index 15913cf7..94da740f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/HamTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/HamTruyen.kt @@ -23,10 +23,11 @@ internal class HamTruyen(context: MangaLoaderContext) : val tagMap = getOrCreateTagMap() val tagsElement = doc.select("li.kind p.col-xs-8 a") val mangaTags = tagsElement.mapNotNullToSet { tagMap[it.text()] } + val author = doc.body().select(selectAut).textOrNull() manga.copy( description = doc.selectFirst(selectDesc)?.html(), altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.body().select(selectAut).textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = doc.selectFirst(selectState)?.let { when (it.text()) { in ongoing -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/MeHentaiVN.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/MeHentaiVN.kt index 301502eb..eb41ab10 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/MeHentaiVN.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/MeHentaiVN.kt @@ -37,11 +37,12 @@ internal class MeHentaiVN(context: MangaLoaderContext) : ) else null } + val author = doc.body().selectFirst(selectAut)?.textOrNull() manga.copy( description = doc.selectFirst(selectDesc)?.html(), altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.body().selectFirst(selectAut)?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = doc.selectFirst(selectState)?.let { when (it.text()) { in ongoing -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt index 8cfba795..82a37503 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyen.kt @@ -31,10 +31,11 @@ internal class NetTruyen(context: MangaLoaderContext) : val doc = docDeferred.await() val tagsElement = doc.select("li.kind p.col-xs-8 a") val mangaTags = tagsElement.mapNotNullToSet { tagMap[it.text()] } + val author = doc.body().select(selectAut).textOrNull() manga.copy( description = doc.selectFirst(selectDesc)?.html(), altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.body().select(selectAut).textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = doc.selectFirst(selectState)?.let { when (it.text()) { in ongoing -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenVie.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenVie.kt index baa2fa97..1afb055b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenVie.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NetTruyenVie.kt @@ -25,10 +25,11 @@ internal class NetTruyenVie(context: MangaLoaderContext) : val doc = docDeferred.await() val tagsElement = doc.select("li.kind p.col-xs-8 a") val mangaTags = tagsElement.mapNotNullToSet { tagMap[it.text()] } + val author = doc.body().select(selectAut).textOrNull() manga.copy( description = doc.selectFirst("div.detail-content > div")?.html(), altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.body().select(selectAut).textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = doc.selectFirst(selectState)?.let { when (it.text()) { in ongoing -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NewTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NewTruyen.kt index 501f1ad7..ac533845 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NewTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NewTruyen.kt @@ -36,10 +36,11 @@ internal class NewTruyen(context: MangaLoaderContext) : source = source ) }.toSet() + val author = doc.body().select(selectAut).textOrNull() manga.copy( description = doc.selectFirst(selectDesc)?.html(), - author = doc.body().select(selectAut).textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = doc.selectFirst(selectState)?.let { when (it.text()) { in ongoing -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NhatTruyenVN.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NhatTruyenVN.kt index da91c0e8..62ab029b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NhatTruyenVN.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/NhatTruyenVN.kt @@ -47,10 +47,11 @@ internal class NhatTruyenVN(context: MangaLoaderContext) : val tagMap = getOrCreateTagMap() val tagsElement = doc.select("li.kind p.col-xs-8 a") val mangaTags = tagsElement.mapNotNullToSet { tagMap[it.text()] } + val author = doc.body().selectFirst(selectAut)?.textOrNull() manga.copy( description = doc.selectFirst(selectDesc)?.html(), altTitle = doc.selectFirst("h2.other-name")?.textOrNull(), - author = doc.body().selectFirst(selectAut)?.textOrNull(), + authors = author?.let { setOf(it) } ?: emptySet(), state = doc.selectFirst(selectState)?.let { when (it.text()) { in ongoing -> MangaState.ONGOING diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt index 02202ddb..b14cd0f6 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/wpcomics/vi/TopTruyen.kt @@ -106,10 +106,10 @@ internal class TopTruyen(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = mangaTags, - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -149,7 +149,7 @@ internal class TopTruyen(context: MangaLoaderContext) : } return manga.copy( - author = author, + authors = author?.let { setOf(it) } ?: emptySet(), description = description, state = state, tags = tags, diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt index 6eebd3ae..b7658421 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zeistmanga/ZeistMangaParser.kt @@ -175,10 +175,10 @@ internal abstract class ZeistMangaParser( altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -220,11 +220,12 @@ internal abstract class ZeistMangaParser( ?: doc.selectFirst("div.y6x11p:contains(Yazar) .dt") ?: doc.selectFirst("ul.infonime li:contains(Author) span") + val desc = doc.getElementById("synopsis") ?: doc.getElementById("Sinopse") ?: doc.getElementById("sinopas") ?: doc.selectFirst(".sinopsis") ?: doc.selectFirst(".sinopas") val chaptersDeferred = async { loadChapters(manga.url, doc) } manga.copy( - author = author?.text(), + authors = author?.text()?.let { setOf(it) } ?: emptySet(), tags = doc.select(selectTags).mapToSet { a -> MangaTag( key = a.attr("href").substringAfterLast("label/").substringBefore("?"), diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zh/Baozimh.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zh/Baozimh.kt index ea2f8964..afb5c1c4 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zh/Baozimh.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zh/Baozimh.kt @@ -111,6 +111,7 @@ internal class Baozimh(context: MangaLoaderContext) : private fun parseMangaList(json: JSONArray): List { return json.mapJSON { j -> val href = "https://$domain/comic/" + j.getString("comic_id") + val author = j.getString("author") Manga( id = generateUid(href), url = href, @@ -120,10 +121,10 @@ internal class Baozimh(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = j.getString("author"), + authors = author?.let { setOf(it) } ?: emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -140,10 +141,10 @@ internal class Baozimh(context: MangaLoaderContext) : altTitle = null, rating = RATING_UNKNOWN, tags = emptySet(), - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zmanga/ZMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zmanga/ZMangaParser.kt index 161fe7fb..0f1e0b5b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zmanga/ZMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/zmanga/ZMangaParser.kt @@ -175,10 +175,10 @@ internal abstract class ZMangaParser( source = source, ) }, - author = null, + authors = emptySet(), state = null, source = source, - isNsfw = isNsfwSource, + contentRating = if (isNsfwSource) ContentRating.ADULT else null, ) } } @@ -222,7 +222,7 @@ internal abstract class ZMangaParser( val alt = doc.body().selectFirst(selectAlt)?.textOrNull() - val aut = doc.body().selectFirst(selectAut)?.textOrNull() + val author = doc.body().selectFirst(selectAut)?.textOrNull() manga.copy( tags = doc.body().select(selectTag).mapToSet { a -> @@ -234,7 +234,7 @@ internal abstract class ZMangaParser( }, description = desc, altTitle = alt, - author = aut, + authors = author?.let { setOf(it) } ?: emptySet(), state = state, chapters = chaptersDeferred.await(), contentRating = if (doc.getElementById("adt-warning") != null) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/LinkResolver.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/LinkResolver.kt index 3160fe50..ba8c728c 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/LinkResolver.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/LinkResolver.kt @@ -54,7 +54,7 @@ public class LinkResolver internal constructor( coverUrl = "", tags = emptySet(), state = null, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, chapters = null, @@ -70,7 +70,7 @@ public class LinkResolver internal constructor( val query = when { seed.title != STUB_TITLE && seed.title.isNotEmpty() -> seed.title !seed.altTitle.isNullOrEmpty() -> seed.altTitle - !seed.author.isNullOrEmpty() -> seed.author + seed.authors.isNotEmpty() -> seed.authors.first() else -> return seed // unfortunately we do not know a real manga title so unable to find it } val resolved = runCatchingCancellable { @@ -91,7 +91,7 @@ public class LinkResolver internal constructor( resolved.copy( chapters = seed.chapters ?: resolved.chapters, description = seed.description ?: resolved.description, - author = seed.author ?: resolved.author, + authors = seed.authors.ifEmpty { resolved.authors }, tags = seed.tags + resolved.tags, state = seed.state ?: resolved.state, coverUrl = seed.coverUrl ?: resolved.coverUrl, diff --git a/src/test/kotlin/org/koitharu/kotatsu/test_util/Util.kt b/src/test/kotlin/org/koitharu/kotatsu/test_util/Util.kt index 0aec98dc..f7bf470c 100644 --- a/src/test/kotlin/org/koitharu/kotatsu/test_util/Util.kt +++ b/src/test/kotlin/org/koitharu/kotatsu/test_util/Util.kt @@ -66,11 +66,11 @@ fun mangaOf(source: MangaParserSource, url: String): Manga { url = httpUrl?.let { url.toRelativeUrl(it.host) } ?: url, publicUrl = url, rating = RATING_UNKNOWN, - isNsfw = false, + contentRating = null, coverUrl = "", tags = emptySet(), state = null, - author = null, + authors = emptySet(), largeCoverUrl = null, description = null, chapters = null,