Add multi tag some sources
Add SortOrder.POPULARITY some sources Add all language on GalleryAdultsParser fix YugenMangas (pt)
This commit is contained in:
@@ -149,6 +149,9 @@ internal abstract class GalleryAdultsParser(
|
||||
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
val urlChapters = doc.selectFirstOrThrow(selectUrlChapter).attr("href")
|
||||
val tag = doc.selectFirst(selectTag)?.parseTags()
|
||||
val branch = doc.select(selectLanguageChapter).joinToString(separator = " / ") {
|
||||
it.html().substringBefore("<")
|
||||
}
|
||||
return manga.copy(
|
||||
tags = tag.orEmpty(),
|
||||
author = doc.selectFirst(selectAuthor)?.html()?.substringBefore("<span"),
|
||||
@@ -160,7 +163,7 @@ internal abstract class GalleryAdultsParser(
|
||||
url = urlChapters,
|
||||
scanlator = null,
|
||||
uploadDate = 0,
|
||||
branch = doc.selectFirst(selectLanguageChapter)?.html()?.substringBefore("<"),
|
||||
branch = branch,
|
||||
source = source,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
|
||||
@MangaSourceParser("HENTAI3", "3Hentai", type = ContentType.HENTAI)
|
||||
internal class Hentai3(context: MangaLoaderContext) :
|
||||
@@ -14,10 +15,10 @@ internal class Hentai3(context: MangaLoaderContext) :
|
||||
override val selectGalleryLink = "a"
|
||||
override val selectGalleryTitle = ".title"
|
||||
override val pathTagUrl = "/tags-popular/"
|
||||
override val selectTags = "span.filter-elem"
|
||||
override val selectTag = "div.tag-container:contains(Tags :) .filter-elem"
|
||||
override val selectAuthor = "div.tag-container:contains(Artistes :) .filter-elem"
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Langues :) .filter-elem"
|
||||
override val selectTags = "div.tag-listing-container"
|
||||
override val selectTag = "div.tag-container:contains(Tags)"
|
||||
override val selectAuthor = "div.tag-container:contains(Artists) .filter-elem a"
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Languages) a"
|
||||
override val selectUrlChapter = "#main-cover a"
|
||||
override val idImg = ".js-main-img"
|
||||
override val listLanguage = arrayOf(
|
||||
@@ -30,31 +31,40 @@ internal class Hentai3(context: MangaLoaderContext) :
|
||||
"/japanese",
|
||||
)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getListPage(
|
||||
page: Int,
|
||||
query: String?,
|
||||
tags: Set<MangaTag>?,
|
||||
sortOrder: SortOrder,
|
||||
): List<Manga> {
|
||||
val tag = tags.oneOrThrowIfMany()
|
||||
if (query.isNullOrEmpty() && tags != null && tags.size > 1) {
|
||||
return getListPage(page, buildQuery(tags), emptySet(), sortOrder)
|
||||
}
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
if (!tags.isNullOrEmpty()) {
|
||||
if (tag?.key == "languageKey") {
|
||||
val tag = tags.single()
|
||||
if (tag.key == "languageKey") {
|
||||
append("/language")
|
||||
append(tag.title)
|
||||
append("/")
|
||||
append(page)
|
||||
} else {
|
||||
append("/tags/")
|
||||
append(tag?.key.orEmpty())
|
||||
append("/")
|
||||
append(page)
|
||||
append(tag.key)
|
||||
}
|
||||
append("/")
|
||||
append(page)
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("?sort=popular")
|
||||
}
|
||||
} else if (!query.isNullOrEmpty()) {
|
||||
append("/search/?q=")
|
||||
append("/search?q=")
|
||||
append(query.urlEncoded())
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("&sort=popular")
|
||||
}
|
||||
append("&page=")
|
||||
append(page)
|
||||
} else {
|
||||
@@ -69,4 +79,13 @@ internal class Hentai3(context: MangaLoaderContext) :
|
||||
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
return doc.selectFirstOrThrow(idImg).src() ?: doc.parseFailed("Image src not found")
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
"language:\"${tag.title.removePrefix("/")}\""
|
||||
} else {
|
||||
"tag:\"${tag.title}\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.koitharu.kotatsu.parsers.util.domain
|
||||
import org.koitharu.kotatsu.parsers.util.oneOrThrowIfMany
|
||||
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||
import org.koitharu.kotatsu.parsers.util.urlEncoded
|
||||
import java.util.EnumSet
|
||||
|
||||
@MangaSourceParser("HENTAIENVY", "HentaiEnvy", type = ContentType.HENTAI)
|
||||
internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
@@ -31,6 +32,8 @@ internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
"/portuguese",
|
||||
)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getListPage(
|
||||
page: Int,
|
||||
query: String?,
|
||||
@@ -49,6 +52,9 @@ internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(tag?.key.orEmpty())
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("/popular")
|
||||
}
|
||||
append("/?")
|
||||
}
|
||||
} else if (!query.isNullOrEmpty()) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
|
||||
@MangaSourceParser("HENTAIERA", "HentaiEra", type = ContentType.HENTAI)
|
||||
internal class HentaiEra(context: MangaLoaderContext) :
|
||||
@@ -24,6 +25,8 @@ internal class HentaiEra(context: MangaLoaderContext) :
|
||||
"/russian",
|
||||
)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override fun Element.parseTags() = select("a.tag, .gallery_title a").mapToSet {
|
||||
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
|
||||
val name = it.selectFirst(".item_name")?.text() ?: it.text()
|
||||
@@ -40,23 +43,33 @@ internal class HentaiEra(context: MangaLoaderContext) :
|
||||
tags: Set<MangaTag>?,
|
||||
sortOrder: SortOrder,
|
||||
): List<Manga> {
|
||||
val tag = tags.oneOrThrowIfMany()
|
||||
if (query.isNullOrEmpty() && tags != null && tags.size > 1) {
|
||||
return getListPage(page, buildQuery(tags), emptySet(), sortOrder)
|
||||
}
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
if (!tags.isNullOrEmpty()) {
|
||||
if (tag?.key == "languageKey") {
|
||||
val tag = tags.single()
|
||||
if (tag.key == "languageKey") {
|
||||
append("/language")
|
||||
append(tag.title)
|
||||
append("/?")
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(tag?.key.orEmpty())
|
||||
append("/?")
|
||||
append(tag.key)
|
||||
}
|
||||
append("/")
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular/")
|
||||
}
|
||||
append("?")
|
||||
} else if (!query.isNullOrEmpty()) {
|
||||
append("/search/?key=")
|
||||
append(query.urlEncoded())
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append(query.replace("<=1&dl=0&pp=0&tr=0", "<=0&dl=0&pp=1&tr=0"))
|
||||
} else {
|
||||
append(query)
|
||||
}
|
||||
append("&")
|
||||
} else {
|
||||
append("/?")
|
||||
@@ -67,10 +80,51 @@ internal class HentaiEra(context: MangaLoaderContext) :
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>): String {
|
||||
val queryDefault =
|
||||
"&search=&mg=1&dj=1&ws=1&is=1&ac=1&gc=1&en=0&jp=0&es=0&fr=0&kr=0&de=0&ru=0<=1&dl=0&pp=0&tr=0"
|
||||
var tag = ""
|
||||
var queryMod = ""
|
||||
tags.map {
|
||||
if (it.key == "languageKey" && it.title == "/english") {
|
||||
queryMod = queryDefault.replace("en=0", "en=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/japanese") {
|
||||
queryMod = queryDefault.replace("jp=0", "jp=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/spanish") {
|
||||
queryMod = queryDefault.replace("es=0", "es=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/french") {
|
||||
queryMod = queryDefault.replace("fr=0", "fr=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/korean") {
|
||||
queryMod = queryDefault.replace("kr=0", "kr=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/russian") {
|
||||
queryMod = queryDefault.replace("ru=0", "ru=1")
|
||||
}
|
||||
if (it.key == "languageKey" && it.title == "/german") {
|
||||
queryMod = queryDefault.replace("de=0", "de=1")
|
||||
}
|
||||
if (it.key != "languageKey") {
|
||||
tag += it.key + " "
|
||||
}
|
||||
}
|
||||
|
||||
if (queryMod.isEmpty()) {
|
||||
queryMod = "&search=&mg=1&dj=1&ws=1&is=1&ac=1&gc=1&en=1&jp=1&es=1&fr=1&kr=1&de=1&ru=1<=1&dl=0&pp=0&tr=0"
|
||||
}
|
||||
return tag + queryMod
|
||||
}
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
val urlChapters = doc.selectFirstOrThrow("#cover a, .cover a, .left_cover a").attr("href")
|
||||
val tag = doc.selectFirst(selectTag)?.parseTags()
|
||||
val branch = doc.select(selectLanguageChapter).joinToString(separator = " / ") {
|
||||
it.text()
|
||||
}
|
||||
return manga.copy(
|
||||
tags = tag.orEmpty(),
|
||||
author = doc.selectFirst(selectAuthor)?.text(),
|
||||
@@ -82,7 +136,7 @@ internal class HentaiEra(context: MangaLoaderContext) :
|
||||
url = urlChapters,
|
||||
scanlator = null,
|
||||
uploadDate = 0,
|
||||
branch = doc.selectFirst(selectLanguageChapter)?.text(),
|
||||
branch = branch,
|
||||
source = source,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
|
||||
@MangaSourceParser("HENTAIFORCE", "HentaiForce", type = ContentType.HENTAI)
|
||||
internal class HentaiForce(context: MangaLoaderContext) :
|
||||
@@ -34,6 +35,8 @@ internal class HentaiForce(context: MangaLoaderContext) :
|
||||
"/vietnamese",
|
||||
)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getPageUrl(page: MangaPage): String {
|
||||
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
return doc.selectFirstOrThrow(idImg).src() ?: doc.parseFailed("Image src not found")
|
||||
@@ -45,23 +48,31 @@ internal class HentaiForce(context: MangaLoaderContext) :
|
||||
tags: Set<MangaTag>?,
|
||||
sortOrder: SortOrder,
|
||||
): List<Manga> {
|
||||
val tag = tags.oneOrThrowIfMany()
|
||||
if (query.isNullOrEmpty() && tags != null && tags.size > 1) {
|
||||
return getListPage(page, buildQuery(tags), emptySet(), sortOrder)
|
||||
}
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
if (!tags.isNullOrEmpty()) {
|
||||
if (tag?.key == "languageKey") {
|
||||
val tag = tags.single()
|
||||
if (tag.key == "languageKey") {
|
||||
append("/language")
|
||||
append(tag.title)
|
||||
append("/")
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(tag?.key.orEmpty())
|
||||
append("/")
|
||||
append(tag.key)
|
||||
}
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("/popular")
|
||||
}
|
||||
append("/")
|
||||
} else if (!query.isNullOrEmpty()) {
|
||||
append("search?q=")
|
||||
append("/search?q=")
|
||||
append(query.urlEncoded())
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("&sort=popular")
|
||||
}
|
||||
append("&page=")
|
||||
} else {
|
||||
append("/page/")
|
||||
@@ -70,4 +81,13 @@ internal class HentaiForce(context: MangaLoaderContext) :
|
||||
}
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
"language:${tag.title.removePrefix("/")}"
|
||||
} else {
|
||||
"tag:${tag.title}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
|
||||
@MangaSourceParser("HENTAIFOX", "HentaiFox", type = ContentType.HENTAI)
|
||||
internal class HentaiFox(context: MangaLoaderContext) :
|
||||
@@ -30,33 +32,43 @@ internal class HentaiFox(context: MangaLoaderContext) :
|
||||
"/vietnamese",
|
||||
)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getListPage(
|
||||
page: Int,
|
||||
query: String?,
|
||||
tags: Set<MangaTag>?,
|
||||
sortOrder: SortOrder,
|
||||
): List<Manga> {
|
||||
val tag = tags.oneOrThrowIfMany()
|
||||
if (query.isNullOrEmpty() && tags != null && tags.size > 1) {
|
||||
return getListPage(page, buildQuery(tags), emptySet(), sortOrder)
|
||||
}
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
if (!tags.isNullOrEmpty()) {
|
||||
if (tag?.key == "languageKey") {
|
||||
val tag = tags.single()
|
||||
if (tag.key == "languageKey") {
|
||||
append("/language")
|
||||
append(tag.title)
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(tag?.key.orEmpty())
|
||||
append(tag.key)
|
||||
}
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("/popular")
|
||||
}
|
||||
if (page > 1) {
|
||||
append("/pag/")
|
||||
append(page)
|
||||
append("/")
|
||||
}
|
||||
|
||||
} else if (!query.isNullOrEmpty()) {
|
||||
append("/search/?q=")
|
||||
append(query.urlEncoded())
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("&sort=popular")
|
||||
}
|
||||
if (page > 1) {
|
||||
append("&page=")
|
||||
append(page)
|
||||
@@ -75,4 +87,23 @@ internal class HentaiFox(context: MangaLoaderContext) :
|
||||
}
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
}
|
||||
|
||||
override fun Element.parseTags() = select("a").mapToSet {
|
||||
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
|
||||
val name = it.selectFirst(".list_tag")?.text() ?: it.html().substringBefore("<")
|
||||
MangaTag(
|
||||
key = key,
|
||||
title = name,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
tag.title.removePrefix("/")
|
||||
} else {
|
||||
tag.key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.EnumSet
|
||||
|
||||
@MangaSourceParser("NHENTAI", "NHentai.net", type = ContentType.HENTAI)
|
||||
internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
@@ -14,7 +15,7 @@ internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
override val selectGalleryLink = "a"
|
||||
override val selectGalleryTitle = ".caption"
|
||||
override val pathTagUrl = "/tags/popular?page="
|
||||
override val selectTags = "#tag-container a"
|
||||
override val selectTags = "#tag-container"
|
||||
override val selectTag = ".tag-container:contains(Tags:) span.tags"
|
||||
override val selectAuthor = "#tags div.tag-container:contains(Artists:) span.name"
|
||||
override val selectLanguageChapter =
|
||||
@@ -26,6 +27,8 @@ internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
"/chinese",
|
||||
)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getListPage(
|
||||
page: Int,
|
||||
query: String?,
|
||||
@@ -43,18 +46,28 @@ internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
if (tag.key == "languageKey") {
|
||||
append("/language")
|
||||
append(tag.title)
|
||||
append("/?")
|
||||
} else {
|
||||
append("/tag/")
|
||||
append(tag.key)
|
||||
append("/?")
|
||||
}
|
||||
append("/")
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("popular")
|
||||
}
|
||||
append("?")
|
||||
} else if (!query.isNullOrEmpty()) {
|
||||
append("/search/?q=")
|
||||
append(query.urlEncoded())
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("&sort=popular")
|
||||
}
|
||||
append("&")
|
||||
} else {
|
||||
append("/?")
|
||||
if (sortOrder == SortOrder.POPULARITY) {
|
||||
append("/?sort=popular&")
|
||||
} else {
|
||||
append("/?")
|
||||
}
|
||||
}
|
||||
append("page=")
|
||||
append(page)
|
||||
@@ -78,7 +91,12 @@ internal class NHentaiParser(context: MangaLoaderContext) :
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildQuery(tags: Collection<MangaTag>) = tags.joinToString(separator = " ") { tag ->
|
||||
"tag:\"${tag.key}\""
|
||||
}
|
||||
private fun buildQuery(tags: Collection<MangaTag>) =
|
||||
tags.joinToString(separator = " ") { tag ->
|
||||
if (tag.key == "languageKey") {
|
||||
"language:\"${tag.title.removePrefix("/")}\""
|
||||
} else {
|
||||
"tag:\"${tag.key}\""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.parsers.site.pt
|
||||
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
@@ -7,14 +8,16 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("YUGENMANGAS", "YugenMangas.org", "pt")
|
||||
@MangaSourceParser("YUGENMANGAS", "YugenMangas.net.br", "pt")
|
||||
class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.YUGENMANGAS, 28) {
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.UPDATED)
|
||||
override val configKeyDomain = ConfigKey.Domain("yugenmangas.org")
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
|
||||
override val configKeyDomain = ConfigKey.Domain("yugenmangas.net.br")
|
||||
|
||||
override suspend fun getListPage(
|
||||
page: Int,
|
||||
@@ -22,114 +25,114 @@ class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, Manga
|
||||
tags: Set<MangaTag>?,
|
||||
sortOrder: SortOrder,
|
||||
): List<Manga> {
|
||||
if (!query.isNullOrEmpty()) {
|
||||
if (page > 1) {
|
||||
return emptyList()
|
||||
}
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
append("/api/series/list/?query=")
|
||||
append(query.urlEncoded())
|
||||
}
|
||||
val json = webClient.httpGet(url).parseJsonArray()
|
||||
return json.mapJSON { j ->
|
||||
val urlManga = "https://$domain/series/${j.getString("slug")}/"
|
||||
Manga(
|
||||
id = generateUid(urlManga),
|
||||
url = urlManga,
|
||||
publicUrl = urlManga,
|
||||
title = j.getString("name"),
|
||||
coverUrl = "",
|
||||
altTitle = null,
|
||||
rating = RATING_UNKNOWN,
|
||||
tags = emptySet(),
|
||||
description = null,
|
||||
state = null,
|
||||
author = null,
|
||||
isNsfw = false,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
when (sortOrder) {
|
||||
SortOrder.ALPHABETICAL -> append("/series")
|
||||
SortOrder.UPDATED -> append("/updates")
|
||||
else -> append("/updates")
|
||||
}
|
||||
val json =
|
||||
if (!query.isNullOrEmpty()) {
|
||||
if (page > 1) {
|
||||
append("?page=")
|
||||
append(page)
|
||||
return emptyList()
|
||||
}
|
||||
val url = buildString {
|
||||
append("https://api.")
|
||||
append(domain)
|
||||
append("/api/series/list/?query=")
|
||||
append(query.urlEncoded())
|
||||
}
|
||||
webClient.httpGet(url).parseJsonArray()
|
||||
} else {
|
||||
if (page > 1) {
|
||||
return emptyList()
|
||||
}
|
||||
val url = buildString {
|
||||
append("https://api.")
|
||||
append(domain)
|
||||
append("/api/all_series/?page=1")
|
||||
}
|
||||
webClient.httpGet(url).parseJson().getJSONArray("series")
|
||||
}
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
return doc.select(".gallery .mangas-gallery, .container-update-series .card-series-updates").map { div ->
|
||||
val a = div.selectFirstOrThrow("a")
|
||||
val href = a.attrAsRelativeUrl("href")
|
||||
Manga(
|
||||
id = generateUid(href),
|
||||
url = href,
|
||||
publicUrl = a.attrAsAbsoluteUrl("href"),
|
||||
title = div.selectLastOrThrow(".title-serie, .name-manga").text(),
|
||||
coverUrl = div.selectFirst("img")?.src().orEmpty(),
|
||||
altTitle = null,
|
||||
rating = RATING_UNKNOWN,
|
||||
tags = emptySet(),
|
||||
description = null,
|
||||
state = null,
|
||||
author = null,
|
||||
isNsfw = false,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
|
||||
return json.mapJSON { j ->
|
||||
val slug = j.getString("slug")
|
||||
Manga(
|
||||
id = generateUid(slug),
|
||||
url = slug,
|
||||
publicUrl = slug,
|
||||
title = j.getString("name"),
|
||||
coverUrl = j.getString("cover"),
|
||||
altTitle = null,
|
||||
rating = RATING_UNKNOWN,
|
||||
tags = emptySet(),
|
||||
description = null,
|
||||
state = null,
|
||||
author = null,
|
||||
isNsfw = isNsfwSource,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
val dateFormat = SimpleDateFormat("dd.MM.yyyy", Locale.ROOT)
|
||||
val chapters = doc.requireElementById("listadecapitulos")
|
||||
val detailManga =
|
||||
webClient.httpPost("https://api.$domain/api/serie_details/${manga.url}", emptyMap()).parseJson()
|
||||
val body = JSONObject()
|
||||
body.put("serie_slug", manga.url)
|
||||
val chapterManga = webClient.httpPost("https://api.$domain/api/get_chapters_by_serie/", body).parseJson()
|
||||
.getJSONArray("chapters")
|
||||
val dateFormat = SimpleDateFormat("dd/MM/yyyy", sourceLocale)
|
||||
return manga.copy(
|
||||
description = doc.selectFirst(".sinopse .sinopse")?.html(),
|
||||
author = doc.selectFirst(".author")?.text(),
|
||||
coverUrl = doc.selectFirst(".side img")?.src().orEmpty(),
|
||||
state = doc.selectFirst(".lancamento p")?.let {
|
||||
when (it.text().lowercase()) {
|
||||
description = detailManga.getString("synopsis"),
|
||||
coverUrl = detailManga.getString("cover"),
|
||||
altTitle = detailManga.getString("alternative_names"),
|
||||
author = detailManga.getString("author"),
|
||||
state = detailManga.getString("status")?.let {
|
||||
when (it) {
|
||||
"ongoing" -> MangaState.ONGOING
|
||||
"completed", "finished" -> MangaState.FINISHED
|
||||
"completed" -> MangaState.FINISHED
|
||||
//"hiatus" -> MangaState.PAUSED
|
||||
else -> null
|
||||
}
|
||||
},
|
||||
chapters = chapters.select(".chapter").mapChapters(reversed = true) { i, div ->
|
||||
val a = div.selectFirstOrThrow("a")
|
||||
val href = a.attrAsRelativeUrl("href")
|
||||
val title = div.selectFirstOrThrow(".chapter-title").text()
|
||||
val dateText = div.selectFirstOrThrow(".chapter-lancado").text()
|
||||
chapters = chapterManga.mapJSONIndexed { i, j ->
|
||||
val url = "https://api.$domain/api/serie/${manga.url}/chapter/${j.getString("slug")}/images/imgs/"
|
||||
MangaChapter(
|
||||
id = generateUid(href),
|
||||
name = title,
|
||||
number = i + 1,
|
||||
url = href,
|
||||
id = generateUid(url),
|
||||
name = j.getString("name"),
|
||||
number = j.getString("name").removePrefix("Capítulo ").toInt(),
|
||||
url = url,
|
||||
scanlator = null,
|
||||
uploadDate = dateFormat.tryParse(dateText),
|
||||
uploadDate = parseChapterDate(
|
||||
dateFormat,
|
||||
j.getString("upload_date"),
|
||||
),
|
||||
branch = null,
|
||||
source = source,
|
||||
)
|
||||
},
|
||||
}.sortedBy { it.name },
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
d.endsWith(" atrás") -> parseRelativeDate(date)
|
||||
else -> dateFormat.tryParse(date)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseRelativeDate(date: String): Long {
|
||||
val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0
|
||||
val cal = Calendar.getInstance()
|
||||
|
||||
return when {
|
||||
WordSet("dia", "dias").anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
WordSet("hora", "horas").anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val fullUrl = chapter.url.toAbsoluteUrl(domain)
|
||||
val apiUrl = webClient.httpGet(fullUrl).parseHtml().selectFirstOrThrow("script:containsData(imageUrls)").data()
|
||||
.substringAfter("apiUrl = \"").substringBefore("\";")
|
||||
val json = webClient.httpGet(apiUrl.toAbsoluteUrl(domain)).parseJson().getJSONArray("chapter_images")
|
||||
val pages = ArrayList<MangaPage>(json.length())
|
||||
for (i in 0 until json.length()) {
|
||||
val img = "https://media.$domain/${json.getString(i)}"
|
||||
val jsonPages = webClient.httpPost(chapter.url, emptyMap()).parseJson().getJSONArray("chapter_images")
|
||||
val pages = ArrayList<MangaPage>(jsonPages.length())
|
||||
for (i in 0 until jsonPages.length()) {
|
||||
val img = "https://$domain/${jsonPages.getString(i)}"
|
||||
pages.add(
|
||||
MangaPage(
|
||||
id = generateUid(img),
|
||||
|
||||
Reference in New Issue
Block a user