Improvements

Koitharu 1 year ago
parent 47263e641e
commit a0168a7d49
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

1
.gitignore vendored

@ -83,3 +83,4 @@ bin/
src/test/resources/cookies.txt
local.properties
.kotlin/
!/.idea/kotlin-statistics.xml

@ -4,8 +4,7 @@ import androidx.collection.ArrayMap
import org.koitharu.kotatsu.parsers.util.findById
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
@ExposedCopyVisibility
public data class Manga private constructor(
public data class Manga constructor(
/**
* Unique identifier for manga
*/
@ -72,6 +71,41 @@ public data class Manga private 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<MangaTag>,
state: MangaState?,
author: String?,
largeCoverUrl: String? = null,
description: String? = null,
chapters: List<MangaChapter>? = 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,
)
/**
* Return if manga has a specified rating
* @see rating
@ -102,174 +136,4 @@ public data class Manga private constructor(
}
return result
}
public companion object {
@Deprecated("")
public operator fun invoke(
/**
* Unique identifier for manga
*/
id: Long,
/**
* Manga title, human-readable
*/
title: String,
/**
* Alternative title (for example on other language), may be null
*/
altTitle: String?,
/**
* Relative url to manga (**without** a domain) or any other uri.
* Used principally in parsers
*/
url: String,
/**
* Absolute url to manga, must be ready to open in browser
*/
publicUrl: String,
/**
* Normalized manga rating, must be in range of 0..1 or [RATING_UNKNOWN] if rating s unknown
* @see hasRating
*/
rating: Float,
/**
* Indicates that manga may contain sensitive information (18+, NSFW)
*/
isNsfw: Boolean,
/**
* Absolute link to the cover
* @see largeCoverUrl
*/
coverUrl: String?,
/**
* Tags (genres) of the manga
*/
tags: Set<MangaTag>,
/**
* Manga status (ongoing, finished) or null if unknown
*/
state: MangaState?,
/**
* Author of the manga, may be null
*/
author: String?,
/**
* Large cover url (absolute), null if is no large cover
* @see coverUrl
*/
largeCoverUrl: String? = null,
/**
* Manga description, may be html or null
*/
description: String? = null,
/**
* List of chapters
*/
chapters: List<MangaChapter>? = null,
/**
* Manga source
*/
source: MangaSource,
): Manga = invoke(
id = id,
title = title,
altTitle = altTitle,
url = url,
publicUrl = publicUrl,
rating = rating,
contentRating = if (isNsfw) ContentRating.ADULT else ContentRating.SAFE,
coverUrl = coverUrl,
tags = tags,
state = state,
author = author,
largeCoverUrl = largeCoverUrl,
description = description,
chapters = chapters,
source = source,
)
public operator fun invoke(
/**
* Unique identifier for manga
*/
id: Long,
/**
* Manga title, human-readable
*/
title: String,
/**
* Alternative title (for example on other language), may be null
*/
altTitle: String?,
/**
* Relative url to manga (**without** a domain) or any other uri.
* Used principally in parsers
*/
url: String,
/**
* Absolute url to manga, must be ready to open in browser
*/
publicUrl: String,
/**
* Normalized manga rating, must be in range of 0..1 or [RATING_UNKNOWN] if rating s unknown
* @see hasRating
*/
rating: Float,
/**
* Indicates that manga may contain sensitive information (18+, NSFW)
*/
contentRating: ContentRating?,
/**
* Absolute link to the cover
* @see largeCoverUrl
*/
coverUrl: String?,
/**
* Tags (genres) of the manga
*/
tags: Set<MangaTag>,
/**
* Manga status (ongoing, finished) or null if unknown
*/
state: MangaState?,
/**
* Author of the manga, may be null
*/
author: String?,
/**
* Large cover url (absolute), null if is no large cover
* @see coverUrl
*/
largeCoverUrl: String? = null,
/**
* Manga description, may be html or null
*/
description: String? = null,
/**
* List of chapters
*/
chapters: List<MangaChapter>? = null,
/**
* Manga source
*/
source: MangaSource,
): Manga = Manga(
id = id,
title = title,
altTitle = altTitle?.nullIfEmpty(),
url = url,
publicUrl = publicUrl,
rating = rating,
contentRating = contentRating,
coverUrl = coverUrl?.nullIfEmpty(),
tags = tags,
state = state,
author = author?.nullIfEmpty(),
largeCoverUrl = largeCoverUrl?.nullIfEmpty(),
description = description?.nullIfEmpty(),
chapters = chapters,
source = source,
)
}
}

@ -116,7 +116,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
"zbato.net",
"zbato.org",
"fto.to",
"jto.to"
"jto.to",
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
@ -338,7 +338,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
publicUrl = a.absUrl("href"),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirst("img[src]")?.absUrl("src").orEmpty(),
coverUrl = div.selectFirst("img[src]")?.absUrl("src"),
largeCoverUrl = null,
description = null,
tags = div.selectFirst(".item-genre")?.parseTags().orEmpty(),

@ -156,8 +156,8 @@ internal class ComickFunParser(context: MangaLoaderContext) :
url = slug,
publicUrl = "https://$domain/comic/$slug",
rating = jo.getDoubleOrDefault("rating", -10.0).toFloat() / 10f,
isNsfw = false,
coverUrl = jo.getString("cover_url"),
contentRating = null,
coverUrl = jo.getStringOrNull("cover_url"),
largeCoverUrl = null,
description = jo.getStringOrNull("desc"),
tags = jo.selectGenres(tagsMap),
@ -179,10 +179,11 @@ internal class ComickFunParser(context: MangaLoaderContext) :
val url = "https://api.$domain/comic/${manga.url}?tachiyomi=true"
val jo = webClient.httpGet(url).parseJson()
val comic = jo.getJSONObject("comic")
var alt = ""
comic.getJSONArray("md_titles").mapJSON { alt += it.getString("title") + " - " }
val alt = comic.getJSONArray("md_titles").asTypedList<JSONObject>().joinToString("\n") {
it.getStringOrNull("title").orEmpty()
}
return manga.copy(
altTitle = alt.ifEmpty { comic.getStringOrNull("title") }?.nullIfEmpty(),
altTitle = alt.nullIfEmpty(),
contentRating = if (jo.getBooleanOrDefault("matureContent", false)
|| comic.getBooleanOrDefault("hentai", false)
) {

@ -167,9 +167,10 @@ internal class ExHentaiParser(
val a = gLink.parents().select("a").first() ?: gLink.parseFailed("link not found")
val href = a.attrAsRelativeUrl("href")
val tagsDiv = gLink.nextElementSibling() ?: gLink.parseFailed("tags div not found")
val rawTitle = gLink.text()
Manga(
id = generateUid(href),
title = gLink.text().cleanupTitle(),
title = rawTitle.cleanupTitle(),
altTitle = null,
url = href,
publicUrl = a.absUrl("href"),
@ -177,9 +178,12 @@ internal class ExHentaiParser(
contentRating = ContentRating.ADULT,
coverUrl = td1.selectFirst("img")?.attrAsAbsoluteUrlOrNull("src"),
tags = tagsDiv.parseTags(),
state = null,
state = when {
rawTitle.contains("(ongoing)", ignoreCase = true) -> MangaState.ONGOING
else -> null
},
author = tagsDiv.getElementsContainingOwnText("artist:").first()
?.nextElementSibling()?.text(),
?.nextElementSibling()?.textOrNull(),
source = source,
)
}

@ -120,7 +120,7 @@ internal class ImHentai(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img")?.src().orEmpty(),
coverUrl = a.selectFirst("img")?.src(),
title = div.selectFirst(".caption")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
@ -197,7 +197,7 @@ internal class ImHentai(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img")?.src().orEmpty(),
coverUrl = a.selectFirst("img")?.src(),
title = div.selectFirst(".caption")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -302,7 +302,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
"safe" -> ContentRating.SAFE
else -> null
},
coverUrl = cover?.plus(".256.jpg").orEmpty(),
coverUrl = cover?.plus(".256.jpg"),
largeCoverUrl = cover,
description = attrs.optJSONObject("description")?.selectByLocale(),
tags = attrs.getJSONArray("tags").mapJSONToSet { tag ->
@ -338,7 +338,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
getStringOrNull(locale.language)?.let { return it }
getStringOrNull(locale.toLanguageTag())?.let { return it }
}
return getStringOrNull(LOCALE_FALLBACK) ?: entries<String>().firstOrNull()?.value
return getStringOrNull(LOCALE_FALLBACK) ?: entries<String>().firstOrNull()?.value?.nullIfEmpty()
}
private fun JSONArray.flatten(): JSONObject {

@ -31,7 +31,7 @@ internal class MangaPark(context: MangaLoaderContext) :
"parkmanga.com",
"parkmanga.net",
"parkmanga.org",
"mpark.to"
"mpark.to",
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
@ -155,7 +155,7 @@ internal class MangaPark(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("h3")?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.text-yellow-500")?.text()?.toFloatOrNull()?.div(10F) ?: RATING_UNKNOWN,

@ -146,17 +146,17 @@ internal class MangaReaderToParser(context: MangaLoaderContext) :
return document.select(".block_area_authors-other .manga_list-sbs .manga-poster, .featured-block-ul .manga-poster")
.map {
val mangaUrl = it.attrAsRelativeUrl("href")
val thumb = it.select("img")
val thumb = it.selectFirstOrThrow("img")
Manga(
id = generateUid(mangaUrl),
url = mangaUrl,
publicUrl = mangaUrl.toAbsoluteUrl(domain),
title = thumb.attr("alt"),
coverUrl = thumb.attr("src"),
coverUrl = thumb.attrAsAbsoluteUrlOrNull("src"),
source = source,
altTitle = null,
author = null,
isNsfw = false,
contentRating = null,
rating = RATING_UNKNOWN,
state = null,
tags = emptySet(),

@ -114,7 +114,7 @@ internal abstract class NineMangaParser(
publicUrl = href,
title = dd?.selectFirst("a.bookname")?.text()?.toCamelCase().orEmpty(),
altTitle = null,
coverUrl = node.selectFirst("img")?.src().orEmpty(),
coverUrl = node.selectFirst("img")?.src(),
rating = RATING_UNKNOWN,
author = null,
isNsfw = false,

@ -203,7 +203,7 @@ internal class NineNineNineHentaiParser(context: MangaLoaderContext) :
altTitle = name,
coverUrl = when {
cover?.startsWith("http") == true -> cover
cover == null -> ""
cover == null -> null
else -> "https://${cdnHost.get()}/$cover"
},
author = null,

@ -104,7 +104,8 @@ internal abstract class AnimeBootstrapParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirstOrThrow("div.product__item__pic").attr("data-setbg").orEmpty(),
coverUrl = div.selectFirstOrThrow("div.product__item__pic")
.attrAsAbsoluteUrlOrNull("data-setbg"),
title = div.selectFirstOrThrow("div.product__item__text").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -66,7 +66,8 @@ internal class PapScan(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirstOrThrow("div.product__item__pic").attr("data-setbg").orEmpty(),
coverUrl = div.selectFirstOrThrow("div.product__item__pic")
.attrAsAbsoluteUrlOrNull("data-setbg"),
title = div.selectFirstOrThrow("div.product__item__text h5").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -75,7 +75,7 @@ internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(contex
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").src().orEmpty(),
coverUrl = div.selectFirstOrThrow("img").src(),
tags = emptySet(),
state = null,
author = null,

@ -109,7 +109,7 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").src()?.replace("thumbnail_", "").orEmpty(),
coverUrl = div.selectFirstOrThrow("img").src()?.replace("thumbnail_", ""),
tags = emptySet(),
state = when (div.selectFirst(".status")?.text()) {
"مستمرة" -> MangaState.ONGOING

@ -100,8 +100,7 @@ internal abstract class CupFoxParser(
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = li.selectFirst(selectMangasCover)
?.src().orEmpty(),
coverUrl = li.selectFirst(selectMangasCover)?.src(),
tags = setOf(),
state = null,
author = null,
@ -166,7 +165,7 @@ internal abstract class CupFoxParser(
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = li.selectFirst(selectMangasCover)?.src().orEmpty(),
coverUrl = li.selectFirst(selectMangasCover)?.src(),
tags = setOf(),
state = null,
author = null,

@ -111,7 +111,7 @@ internal class AsuraScansParser(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img")?.src().orEmpty(),
coverUrl = a.selectFirst("img")?.src(),
title = a.selectFirst("div.block > span.block")?.text().orEmpty(),
altTitle = null,
rating = a.selectFirst("div.block label.ml-1")?.text()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN,

@ -73,7 +73,7 @@ internal class BeeToon(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst(".name")?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst(".counter")?.text()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,

@ -112,7 +112,7 @@ internal class DynastyScans(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = "",
coverUrl = null,
tags = div.select("span.tags a").mapToSet { a ->
MangaTag(
key = a.attr("href").removeSuffix('/').substringAfterLast('/'),

@ -141,7 +141,7 @@ internal class FlameComics(context: MangaLoaderContext) :
coverUrl = if (cover != null) {
imageUrl(seriesId, cover, 256)
} else {
""
null
},
tags = jo.getStringOrNull("categories")?.let {
JSONArray(it).asTypedList<String>().mapToSet { tagName -> tagName.toMangaTag() }

@ -85,10 +85,10 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").src().orEmpty(),
coverUrl = div.selectFirstOrThrow("img").src(),
tags = emptySet(),
state = null,
author = div.selectFirstOrThrow("h6").text().removePrefix("Author(S): "),
author = div.selectFirstOrThrow("h6").text().removePrefix("Author(S): ").nullIfEmpty(),
source = source,
)
}

@ -81,7 +81,7 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = (div.selectFirst("img")?.src() ?: a.attr("data-bg")).orEmpty(),
coverUrl = div.selectFirst("img")?.src() ?: a.attrAsAbsoluteUrlOrNull("data-bg"),
title = div.selectFirstOrThrow("h4, .media-thumbnail__name").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -113,7 +113,7 @@ internal class MangaTownParser(context: MangaLoaderContext) :
Manga(
id = generateUid(href),
title = a.attr("title"),
coverUrl = a.selectFirst("img")?.absUrl("src").orEmpty(),
coverUrl = a.selectFirst("img")?.attrAsAbsoluteUrlOrNull("src"),
source = MangaParserSource.MANGATOWN,
altTitle = null,
rating = li.selectFirst("p.score")?.selectFirst("b")

@ -104,7 +104,7 @@ internal class Mangaowl(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("a.one-line")?.text().orEmpty(),
altTitle = null,
rating = div.select("span").last()?.text()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,

@ -130,7 +130,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
publicUrl = absUrl,
rating = RATING_UNKNOWN,
isNsfw = true,
coverUrl = it.selectFirst("div.img-in-ratio")?.attrAsAbsoluteUrl("data-bg").orEmpty(),
coverUrl = it.selectFirst("div.img-in-ratio")?.attrAsAbsoluteUrl("data-bg"),
tags = emptySet(),
state = null,
author = null,

@ -130,7 +130,7 @@ internal class Manhwa18Parser(context: MangaLoaderContext) :
publicUrl = absUrl,
rating = RATING_UNKNOWN,
isNsfw = true,
coverUrl = it.selectFirst("div.img-in-ratio")?.attrAsAbsoluteUrl("data-bg").orEmpty(),
coverUrl = it.selectFirst("div.img-in-ratio")?.attrAsAbsoluteUrl("data-bg"),
tags = emptySet(),
state = null,
author = null,

@ -83,7 +83,7 @@ internal class ManhwasMen(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = li.selectFirst("img")?.src().orEmpty(),
coverUrl = li.selectFirst("img")?.src(),
title = li.selectFirst(".title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -78,7 +78,7 @@ internal class MyComicList(context: MangaLoaderContext) : PagedMangaParser(conte
tags = emptySet(),
rating = RATING_UNKNOWN,
isNsfw = isNsfwSource,
coverUrl = img?.attr("data-src").orEmpty(),
coverUrl = img?.attrAsAbsoluteUrlOrNull("data-src"),
state = null,
source = source,
)

@ -50,7 +50,7 @@ internal class Po2Scans(context: MangaLoaderContext) : SinglePageMangaParser(con
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").src()?.toAbsoluteUrl(domain).orEmpty(),
coverUrl = div.selectFirstOrThrow("img").src(),
tags = emptySet(),
state = null,
author = null,

@ -94,7 +94,7 @@ internal class Pururin(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img.card-img-top")?.src().orEmpty(),
coverUrl = a.selectFirst("img.card-img-top")?.src(),
title = a.selectFirst(".title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,
@ -170,7 +170,7 @@ internal class Pururin(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = a.selectFirst("img.card-img-top")?.src().orEmpty(),
coverUrl = a.selectFirst("img.card-img-top")?.src(),
title = a.selectFirst(".title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -105,7 +105,7 @@ internal class VyManga(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = div.selectFirst(".comic-image img")?.src().orEmpty(),
coverUrl = div.selectFirst(".comic-image img")?.src(),
title = div.selectFirst(".comic-title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -1,20 +1,25 @@
package org.koitharu.kotatsu.parsers.site.en
import kotlinx.coroutines.*
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.jsoup.nodes.*
import org.koitharu.kotatsu.parsers.*
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.model.MangaState.*
import org.koitharu.kotatsu.parsers.model.ContentRating.SAFE
import org.koitharu.kotatsu.parsers.model.ContentRating.SUGGESTIVE
import org.koitharu.kotatsu.parsers.model.ContentType.*
import org.koitharu.kotatsu.parsers.model.MangaState.*
import org.koitharu.kotatsu.parsers.model.SortOrder.*
import org.koitharu.kotatsu.parsers.model.ContentRating.*
import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat
import java.util.EnumSet
import java.util.Locale
import java.util.*
@MangaSourceParser("WEEBCENTRAL", "Weeb Central", "en")
internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, MangaParserSource.WEEBCENTRAL),
@ -65,27 +70,27 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
MangaTag(
title = it.selectFirstOrThrow(".label-text").text(),
key = it.selectFirstOrThrow("input[id$=value]").attr("value"),
source = source
source = source,
)
}
val states = EnumSet.of(
ONGOING, FINISHED, ABANDONED, PAUSED
ONGOING, FINISHED, ABANDONED, PAUSED,
)
val types = EnumSet.of(
MANGA, MANHWA, MANHUA, COMICS
MANGA, MANHWA, MANHUA, COMICS,
)
val rating = EnumSet.of(
SAFE, SUGGESTIVE
SAFE, SUGGESTIVE,
)
return MangaListFilterOptions(
availableTags = tags,
availableStates = states,
availableContentTypes = types,
availableContentRating = rating
availableContentRating = rating,
)
}
@ -110,7 +115,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
ADDED, ADDED_ASC -> "Recently Added"
UPDATED, UPDATED_ASC -> "Latest Updates"
else -> throw UnsupportedOperationException("unsupported order: $order")
}
},
)
addQueryParameter(
name = "order",
@ -118,11 +123,11 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
RELEVANCE, ALPHABETICAL, POPULARITY_ASC, RATING_ASC, ADDED_ASC, UPDATED_ASC -> "Ascending"
ALPHABETICAL_DESC, POPULARITY, RATING, ADDED, UPDATED -> "Descending"
else -> throw UnsupportedOperationException("unsupported order: $order")
}
},
)
addQueryParameter("official", "Any")
addQueryParameter("anime", "Any")
with (filter.contentRating) {
with(filter.contentRating) {
addQueryParameter(
name = "adult",
value = when {
@ -131,7 +136,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
SAFE in this -> "False"
SUGGESTIVE in this -> "True"
else -> throw UnsupportedOperationException("unsupported content rating: $this")
}
},
)
}
filter.states.forEach { state ->
@ -143,7 +148,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
ABANDONED -> "Canceled"
PAUSED -> "Hiatus"
else -> throw UnsupportedOperationException("unsupported state: $state")
}
},
)
}
filter.types.forEach { type ->
@ -155,7 +160,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
MANHUA -> "Manhua"
COMICS -> "OEL"
else -> throw UnsupportedOperationException("unsupported type: $type")
}
},
)
}
filter.tags.forEach { tag ->
@ -194,21 +199,21 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
MangaTag(
title = it,
key = it,
source = source
source = source,
)
}
.orEmpty(),
state = when(document.selectFirst("div:contains(status) span")?.text()) {
state = when (document.selectFirst("div:contains(status) span")?.text()) {
"Ongoing" -> ONGOING
"Complete" -> FINISHED
"Canceled" -> ABANDONED
"Hiatus" -> PAUSED
else -> null
},
author = document.select("div:contains(author) a").eachText().joinToString(),
author = document.select("div:contains(author) a").eachText().joinToString().nullIfEmpty(),
largeCoverUrl = null,
chapters = null,
source = source
source = source,
)
}
}
@ -238,7 +243,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
MangaTag(
title = it.text(),
key = it.text(),
source = source
source = source,
)
},
state = when (sectionLeft.selectFirst("ul > li:has(strong:contains(Status)) > a")?.text()) {
@ -260,12 +265,12 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
abbr.selectFirst("a")?.attr("href")?.let { url ->
val a = Element("a")
.text(
abbr.attr("title")
abbr.attr("title"),
)
.attr("href", url)
ul.appendChild(
Element("li").appendChild(a)
Element("li").appendChild(a),
)
}
}
@ -276,7 +281,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
}
}.outerHtml(),
chapters = chapters.await(),
source = source
source = source,
)
}
@ -308,10 +313,10 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
else -> null
},
uploadDate = dateFormat.tryParse(
element.selectFirst("time[datetime]")?.attr("datetime")
element.selectFirst("time[datetime]")?.attr("datetime"),
),
branch = null,
source = source
source = source,
)
}
}
@ -336,7 +341,7 @@ internal class WeebCentral(context: MangaLoaderContext) : MangaParser(context, M
id = generateUid(pageUrl),
url = pageUrl,
preview = null,
source = source
source = source,
)
}
}

@ -8,6 +8,7 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSON
import java.text.DateFormat
import java.text.SimpleDateFormat
@ -41,9 +42,9 @@ internal class TempleScanEsp(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href,
coverUrl = it.getString("urlImg").orEmpty(),
coverUrl = it.getString("urlImg"),
title = it.getString("name").orEmpty(),
altTitle = it.getString("alternativeName").orEmpty(),
altTitle = it.getStringOrNull("alternativeName"),
rating = RATING_UNKNOWN,
tags = emptySet(),
author = null,

@ -142,7 +142,7 @@ internal abstract class FmreaderParser(
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = (div.selectFirst("div.img-in-ratio")?.attr("data-bg")
?: div.selectFirst("div.img-in-ratio")?.attr("style")?.substringAfter("(")
?.substringBefore(")"))?.toAbsoluteUrl(domain).orEmpty(),
?.substringBefore(")"))?.toAbsoluteUrl(domain),
title = div.selectFirst("div.series-title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -88,7 +88,7 @@ internal abstract class FoolSlideParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),// in search no img
coverUrl = div.selectFirst("img")?.src(),// in search no img
title = div.selectFirst(".title a")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

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

@ -124,7 +124,7 @@ internal class BentomangaParser(context: MangaLoaderContext) :
?.div(10f)
?: RATING_UNKNOWN,
isNsfw = div.selectFirst(".badge-adult_content") != null,
coverUrl = div.selectFirst("img")?.src().assertNotNull("src").orEmpty(),
coverUrl = div.selectFirst("img")?.src().assertNotNull("src"),
tags = div.selectFirst(".component-manga-categories")
.assertNotNull("tags")
?.select("a")

@ -69,7 +69,7 @@ internal class FuryoSociety(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (div.selectFirst("div.media-body") ?: div.selectFirst("a"))?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -158,7 +158,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
publicUrl = urlManga,
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = "",
coverUrl = null,
tags = setOf(),
state = null,
author = null,
@ -178,7 +178,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
source = source,
)
},
coverUrl = root.selectFirst("div.serieImg img")?.attr("src"),
coverUrl = root.selectFirst("div.serieImg img")?.attrAsAbsoluteUrlOrNull("src"),
author = root.select("div.serieAdd p:contains(Auteur:) strong").textOrNull(),
description = root.selectFirst("div.serieDescription div")?.html(),
chapters = root.select("div.chapterList a")

@ -80,7 +80,7 @@ internal class MangaKawaii(context: MangaLoaderContext) : PagedMangaParser(conte
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = (div.selectFirst("img")?.src() ?: a.attr("data-bg")).orEmpty(),
coverUrl = div.selectFirst("img")?.src() ?: a.attrAsAbsoluteUrlOrNull("data-bg"),
title = div.selectFirst("h4, .media-thumbnail__name")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -121,7 +121,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = isNsfw,
coverUrl = img.orEmpty(),
coverUrl = img,
description = null,
tags = emptySet(),
state = null,
@ -184,7 +184,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context
publicUrl = href.toAbsoluteUrl(domain),
rating = div.getElementById("avgrating")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
isNsfw = isNsfw,
coverUrl = img.orEmpty(),
coverUrl = img,
description = div.selectFirst(".mangalist_item_description")?.text().orEmpty(),
tags = div.select("div.mb-1 a").mapToSet {
val key = it.attr("href").substringAfterLast('=')

@ -81,7 +81,7 @@ internal class ScansMangasMe(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirstOrThrow("div.bigor div.tt").text().orEmpty(),
altTitle = null,
rating = div.selectFirstOrThrow("div.rating i").ownText().toFloatOrNull()?.div(10f)

@ -89,7 +89,7 @@ internal class ScantradUnion(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = article.selectFirst("img.attachment-thumbnail")?.attrAsAbsoluteUrl("src").orEmpty(),
coverUrl = article.selectFirst("img.attachment-thumbnail")?.attrAsAbsoluteUrl("src"),
tags = setOf(),
state = null,
author = null,
@ -109,7 +109,7 @@ internal class ScantradUnion(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = article.selectFirst("img")?.attrAsAbsoluteUrl("src").orEmpty(),
coverUrl = article.selectFirst("img")?.attrAsAbsoluteUrl("src"),
tags = setOf(),
state = null,
author = null,

@ -147,7 +147,7 @@ internal abstract class FuzzyDoodleParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("h2")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -114,7 +114,7 @@ internal abstract class GalleryAdultsParser(
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = isNsfwSource,
coverUrl = div.selectFirst(selectGalleryImg)?.src().orEmpty(),
coverUrl = div.selectFirst(selectGalleryImg)?.src(),
tags = emptySet(),
state = null,
author = null,

@ -44,7 +44,7 @@ internal class DoujinDesuUk(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = isNsfwSource,
coverUrl = div.selectLastOrThrow(selectGalleryImg).src().orEmpty(),
coverUrl = div.selectLastOrThrow(selectGalleryImg).src(),
tags = emptySet(),
state = null,
author = null,

@ -95,7 +95,7 @@ internal class NHentaiParser(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = isNsfwSource,
coverUrl = div.selectFirstOrThrow(selectGalleryImg).src().orEmpty(),
coverUrl = div.selectFirstOrThrow(selectGalleryImg).src(),
tags = emptySet(),
state = null,
author = null,

@ -85,12 +85,12 @@ internal class NHentaiToParser(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
contentRating = ContentRating.ADULT,
coverUrl = div.selectFirstOrThrow(selectGalleryImg).src().orEmpty(),
coverUrl = div.selectFirstOrThrow(selectGalleryImg).src(),
tags = emptySet(),
state = null,
author = null,
largeCoverUrl = null,
description = "N/A",
description = null,
chapters = null,
source = source,
)

@ -66,7 +66,7 @@ internal class NHentaiXxxParser(context: MangaLoaderContext) :
joiner.add(tag.title)
}
if(!filter.query.isNullOrEmpty()) {
if (!filter.query.isNullOrEmpty()) {
joiner.add(filter.query.urlEncoded())
}
append(joiner.complete())
@ -98,12 +98,12 @@ internal class NHentaiXxxParser(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
contentRating = ContentRating.ADULT,
coverUrl = div.selectFirstOrThrow(selectGalleryImg).src().orEmpty(),
coverUrl = div.selectFirstOrThrow(selectGalleryImg).src(),
tags = emptySet(),
state = null,
author = null,
largeCoverUrl = null,
description = "N/A",
description = null,
chapters = null,
source = source,
)

@ -78,7 +78,7 @@ internal abstract class GattsuParser(
url = href,
publicUrl = href,
title = li.selectLast(".thumb-titulo, .video-titulo")?.text().orEmpty(),
coverUrl = li.selectFirst("img")?.src().orEmpty(),
coverUrl = li.selectFirst("img")?.src(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),

@ -29,7 +29,7 @@ internal class MundoHentaiOficial(context: MangaLoaderContext) :
url = href,
publicUrl = href,
title = li.selectLastOrThrow(".thumb-titulo, .video-titulo").text(),
coverUrl = li.selectFirst("img")?.src().orEmpty(),
coverUrl = li.selectFirst("img")?.src(),
altTitle = null,
rating = RATING_UNKNOWN,
tags = emptySet(),

@ -65,7 +65,7 @@ internal abstract class HeanCmsAlt(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst(selectMangaTitle)?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -105,7 +105,7 @@ internal abstract class HotComicsParser(
id = generateUid(url),
url = url,
publicUrl = url.toAbsoluteUrl(domain),
coverUrl = li.selectFirst("img")?.src().orEmpty(),
coverUrl = li.selectFirst("img")?.src(),
title = li.selectFirst(".title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -121,7 +121,7 @@ internal class DoujinDesuParser(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = true,
coverUrl = it.selectFirst(".thumbnail > img")?.src().orEmpty(),
coverUrl = it.selectFirst(".thumbnail > img")?.src(),
tags = emptySet(),
state = null,
author = null,

@ -66,7 +66,7 @@ internal class HentaiCrot(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src()?.replace("-200x285", "").orEmpty(),
coverUrl = div.selectFirst("img")?.src()?.replace("-200x285", ""),
title = div.selectFirst("h2")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -66,7 +66,7 @@ internal class PixHentai(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src()?.replace("-200x285", "").orEmpty(),
coverUrl = div.selectFirst("img")?.src()?.replace("-200x285", ""),
title = div.selectFirst("h2")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -105,7 +105,7 @@ internal abstract class IkenParser(
id = it.getLong("id"),
url = url,
publicUrl = url.toAbsoluteUrl(domain),
coverUrl = it.getString("featuredImage").orEmpty(),
coverUrl = it.getString("featuredImage"),
title = it.getString("postTitle"),
altTitle = it.getString("alternativeTitles"),
description = it.getString("postContent"),

@ -87,7 +87,7 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
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").orEmpty(),
coverUrl = item.selectFirst(".comic_icon > div > a > img")?.attrAsAbsoluteUrl("src"),
altTitle = null,
author = item.selectFirst(".mg_description_header > .mg_author > a")?.text(),
rating = RATING_UNKNOWN,
@ -200,7 +200,7 @@ internal class NicovideoSeigaParser(context: MangaLoaderContext) :
isNsfw = false,
source = source,
coverUrl = item.selectFirst(".search_result__item__thumbnail > a > img")
?.attrAsAbsoluteUrl("data-original").orEmpty(),
?.attrAsAbsoluteUrl("data-original"),
)
}
}

@ -127,7 +127,7 @@ internal abstract class KeyoappParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = cover?.styleValueOrNull("background-image")?.cssUrl().orEmpty(),
coverUrl = cover?.styleValueOrNull("background-image")?.cssUrl(),
title = div.selectFirstOrThrow("h3").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -116,7 +116,7 @@ internal abstract class LikeMangaParser(
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").src().orEmpty(),
coverUrl = div.selectFirstOrThrow("img").src(),
tags = emptySet(),
state = null,
author = null,

@ -114,7 +114,7 @@ internal abstract class LilianaParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = element.selectFirst("img")?.src().orEmpty(),
coverUrl = element.selectFirst("img")?.src(),
title = element.selectFirst(".text-center a")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -464,7 +464,7 @@ internal abstract class MadaraParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3, h4") ?: div.selectFirst(".manga-name, .post-title"))?.text()
.orEmpty(),
altTitle = null,
@ -661,7 +661,7 @@ internal abstract class MadaraParser(
altTitle = null,
title = div.selectFirstOrThrow(".widget-title").text(),
author = null,
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
tags = emptySet(),
rating = RATING_UNKNOWN,
state = null,

@ -69,7 +69,7 @@ internal class Manga18Fx(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirstOrThrow("h3").text().orEmpty(),
altTitle = null,
rating = div.selectFirst("div.item-rate span")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -75,7 +75,7 @@ internal class Manhwa18Cc(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirstOrThrow("h3").text().orEmpty(),
altTitle = null,
rating = div.selectFirst(".item-rate span")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -24,7 +24,7 @@ internal class FireScans(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4")
?: div.selectFirst(".manga-name"))?.text().orEmpty(),
altTitle = null,

@ -106,7 +106,7 @@ internal class Hentai4Free(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4")
?: div.selectFirst(".manga-name"))?.text().orEmpty(),
altTitle = null,

@ -81,7 +81,7 @@ internal class IsekaiScan(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -103,7 +103,7 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4")
?: summary?.selectFirst("div.post-title p.juduldepan"))?.text().orEmpty(),
altTitle = null,

@ -79,7 +79,7 @@ internal class MangaDass(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -72,7 +72,7 @@ internal class MangaDna(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("div.hitem-rate span")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -86,7 +86,7 @@ internal class MangaPure(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -75,7 +75,7 @@ internal class Manhwaz(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -25,7 +25,7 @@ internal class ShibaManga(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4")
?: div.selectFirst("div.post-title a"))?.text().orEmpty(),
altTitle = null,

@ -62,7 +62,7 @@ internal class DragonTranslationParser(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img.thumb-img")?.src().orEmpty(),
coverUrl = div.selectFirst("img.thumb-img")?.src(),
title = div.selectFirst("div.series-box h5")?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -70,7 +70,7 @@ internal class TmoManga(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirstOrThrow("h3").text(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -70,7 +70,7 @@ internal class ManhwaHub(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4")
?: div.selectFirst("h5.series-title"))?.text().orEmpty(),
altTitle = null,

@ -9,16 +9,8 @@ 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.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.attrAsRelativeUrlOrNull
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.host
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.parseFailed
import org.koitharu.kotatsu.parsers.util.removeSuffix
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toTitleCase
import java.util.Locale
import org.koitharu.kotatsu.parsers.util.*
import java.util.*
@Broken
@MangaSourceParser("MANGAFENXI", "MangaFenxi", "ja")
@ -37,7 +29,7 @@ internal class MangaFenxi(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.attr("src")?.replace("-193x278", "").orEmpty(),
coverUrl = div.selectFirst("img")?.attr("src")?.replace("-193x278", ""),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4")
?: div.selectFirst(".manga-name") ?: div.selectFirst(".post-title"))?.text().orEmpty(),
altTitle = null,

@ -76,7 +76,7 @@ internal class Saytruyenhay(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (summary?.selectFirst("h3") ?: summary?.selectFirst("h4"))?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span.total_votes")?.ownText()?.toFloatOrNull()?.div(5f) ?: -1f,

@ -119,7 +119,7 @@ internal abstract class MadthemeParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("div.meta")?.selectFirst("div.title")?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("div.meta span.score")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,

@ -107,7 +107,7 @@ internal abstract class Manga18Parser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("div.mg_info")?.selectFirst("div.mg_name a")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -23,8 +23,7 @@ internal class Hentai3zCc(context: MangaLoaderContext) :
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src()
?.replace("cover_thumb_2.webp", "cover_250x350.jpg")
?.replace("admin.manga18.us", "bk.18porncomic.com")
.orEmpty(),
?.replace("admin.manga18.us", "bk.18porncomic.com"),
title = div.selectFirst("div.mg_info")?.selectFirst("div.mg_name a")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -126,7 +126,7 @@ internal abstract class MangaboxParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("h3")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -96,7 +96,7 @@ internal class Mangairo(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = (div.selectFirst("h2")?.text() ?: div.selectFirst("h3")?.text()).orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -85,7 +85,7 @@ internal class Mangakakalot(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("h3")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -82,7 +82,7 @@ internal class MangakakalotTv(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirstOrThrow("h3").text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -164,7 +164,7 @@ internal abstract class MangaReaderParser(
publicUrl = a.attrAsAbsoluteUrl("href"),
rating = rating,
isNsfw = isNsfwSource,
coverUrl = it.selectFirst(selectMangaListImg)?.src().orEmpty(),
coverUrl = it.selectFirst(selectMangaListImg)?.src(),
tags = emptySet(),
state = null,
author = null,

@ -101,7 +101,7 @@ internal class RevolutionScantrad(context: MangaLoaderContext) :
publicUrl = a.attrAsAbsoluteUrl("href"),
rating = rating,
isNsfw = isNsfwSource,
coverUrl = it.selectFirst(selectMangaListImg)?.src().orEmpty(),
coverUrl = it.selectFirst(selectMangaListImg)?.src(),
tags = emptySet(),
state = null,
author = null,

@ -95,7 +95,7 @@ internal class XxxRevolutionScantrad(context: MangaLoaderContext) :
publicUrl = a.attrAsAbsoluteUrl("href"),
rating = rating,
isNsfw = isNsfwSource,
coverUrl = it.selectFirst(selectMangaListImg)?.src().orEmpty(),
coverUrl = it.selectFirst(selectMangaListImg)?.src(),
tags = emptySet(),
state = null,
author = null,

@ -148,7 +148,7 @@ internal class Komikcast(context: MangaLoaderContext) :
publicUrl = a.attrAsAbsoluteUrl("href"),
rating = rating,
isNsfw = isNsfwSource,
coverUrl = it.selectFirst("img.ts-post-image")?.src().orEmpty(),
coverUrl = it.selectFirst("img.ts-post-image")?.src(),
tags = emptySet(),
state = null,
author = null,

@ -148,7 +148,7 @@ internal abstract class MangaWorldParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(domain),
coverUrl = div.selectFirst(".thumb img")?.attr("src").orEmpty(),
coverUrl = div.selectFirst(".thumb img")?.attr("src"),
title = div.selectFirst(".name a.manga-title")?.text().orEmpty(),
altTitle = null,
rating = RATING_UNKNOWN,

@ -126,7 +126,7 @@ internal abstract class MmrcmsParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("div.media-body h5")?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst("span")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,

@ -30,7 +30,7 @@ internal class Onma(context: MangaLoaderContext) :
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirstOrThrow("h5.media-heading").text().orEmpty(),
altTitle = null,
rating = div.selectFirstOrThrow("span").ownText().toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,

@ -36,7 +36,7 @@ internal abstract class OneMangaParser(
id = generateUid(url),
url = url,
publicUrl = url,
coverUrl = doc.selectFirst("div.elementor-widget-container img")?.src().orEmpty(),
coverUrl = doc.selectFirst("div.elementor-widget-container img")?.src(),
title = doc.selectFirst("ul.elementor-nav-menu li a")?.text().orEmpty(),
altTitle = doc.selectFirst("div.elementor-widget-text-editor ul li:contains(Nom(s) Alternatif(s))")
?.text()?.replace("Nom(s) Alternatif(s) :", "").orEmpty(),

@ -110,7 +110,7 @@ internal abstract class OtakuSanctuaryParser(
id = generateUid(href),
url = href,
publicUrl = href.toAbsoluteUrl(div.host ?: domain),
coverUrl = div.selectFirst("img")?.src().orEmpty(),
coverUrl = div.selectFirst("img")?.src(),
title = div.selectFirst("h4")?.text().orEmpty(),
altTitle = null,
rating = div.selectFirst(".rating")?.ownText()?.toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN,

@ -99,7 +99,7 @@ internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context,
publicUrl = href.toAbsoluteUrl(domain),
rating = RATING_UNKNOWN,
isNsfw = false,
coverUrl = div.selectFirstOrThrow("img").src().orEmpty(),
coverUrl = div.selectFirstOrThrow("img").src(),
tags = emptySet(),
state = null,
author = null,

@ -88,7 +88,7 @@ internal class LerManga(context: MangaLoaderContext) : PagedMangaParser(context,
url = href,
publicUrl = href,
title = div.selectLastOrThrow("h3.film-name").text(),
coverUrl = div.selectFirst("img.film-poster-img")?.src().orEmpty(),
coverUrl = div.selectFirst("img.film-poster-img")?.src(),
altTitle = null,
rating = div.selectFirst(".item__rating")?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
tags = emptySet(),

@ -63,7 +63,11 @@ internal class WaMangaParser(
},
author = doc.getStringOrNull("author"),
source = source,
contentRating = if (doc.getIntOrDefault("adult", 0) == 0) ContentRating.SAFE else ContentRating.ADULT,
contentRating = if (doc.getIntOrDefault("adult", 0) == 0) {
ContentRating.SAFE
} else {
ContentRating.ADULT
},
)
}

Loading…
Cancel
Save