Merge pull request #355 from KotatsuApp/GalleryAdultsParser
Add GalleryAdultsParser
commit
face1d5b26
@ -1,187 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.parsers.site.all
|
|
||||||
|
|
||||||
import androidx.collection.ArraySet
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.coroutineScope
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
|
||||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
|
||||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
|
||||||
import org.koitharu.kotatsu.parsers.model.*
|
|
||||||
import org.koitharu.kotatsu.parsers.util.*
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@MangaSourceParser("NHENTAI", "N-Hentai", type = ContentType.HENTAI)
|
|
||||||
class NHentaiParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.NHENTAI, pageSize = 25) {
|
|
||||||
|
|
||||||
override val configKeyDomain: ConfigKey.Domain
|
|
||||||
get() = ConfigKey.Domain("nhentai.net")
|
|
||||||
|
|
||||||
override val sortOrders: Set<SortOrder>
|
|
||||||
get() = EnumSet.of(SortOrder.NEWEST, SortOrder.POPULARITY)
|
|
||||||
|
|
||||||
override suspend fun getListPage(
|
|
||||||
page: Int,
|
|
||||||
query: String?,
|
|
||||||
tags: Set<MangaTag>?,
|
|
||||||
sortOrder: SortOrder,
|
|
||||||
): List<Manga> {
|
|
||||||
if (query.isNullOrEmpty() && tags != null && tags.size > 1) {
|
|
||||||
return getListPage(page, buildQuery(tags), emptySet(), sortOrder)
|
|
||||||
}
|
|
||||||
val domain = domain
|
|
||||||
val url = buildString {
|
|
||||||
append("https://")
|
|
||||||
append(domain)
|
|
||||||
if (!query.isNullOrEmpty()) {
|
|
||||||
append("/search/?q=")
|
|
||||||
append(query.urlEncoded())
|
|
||||||
append("&page=")
|
|
||||||
append(page)
|
|
||||||
if (sortOrder == SortOrder.POPULARITY) {
|
|
||||||
append("&sort=popular")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
append('/')
|
|
||||||
if (!tags.isNullOrEmpty()) {
|
|
||||||
val tag = tags.single()
|
|
||||||
append("tag/")
|
|
||||||
append(tag.key)
|
|
||||||
append('/')
|
|
||||||
if (sortOrder == SortOrder.POPULARITY) {
|
|
||||||
append("popular")
|
|
||||||
}
|
|
||||||
append("?page=")
|
|
||||||
append(page)
|
|
||||||
} else {
|
|
||||||
if (sortOrder == SortOrder.POPULARITY) {
|
|
||||||
append("?sort=popular&page=")
|
|
||||||
} else {
|
|
||||||
append("?page=")
|
|
||||||
}
|
|
||||||
append(page)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val root = webClient.httpGet(url).parseHtml().body().requireElementById("content")
|
|
||||||
.selectLastOrThrow("div.index-container")
|
|
||||||
val regexBrackets = Regex("\\[[^]]+]|\\([^)]+\\)")
|
|
||||||
val regexSpaces = Regex("\\s+")
|
|
||||||
return root.select(".gallery").map { div ->
|
|
||||||
val a = div.selectFirstOrThrow("a.cover")
|
|
||||||
val href = a.attrAsRelativeUrl("href")
|
|
||||||
val img = div.selectFirstOrThrow("img")
|
|
||||||
val title = div.selectFirstOrThrow(".caption").text()
|
|
||||||
Manga(
|
|
||||||
id = generateUid(href),
|
|
||||||
title = title.replace(regexBrackets, "")
|
|
||||||
.replace(regexSpaces, " ")
|
|
||||||
.trim(),
|
|
||||||
altTitle = null,
|
|
||||||
url = href,
|
|
||||||
publicUrl = href.toAbsoluteUrl(domain),
|
|
||||||
rating = RATING_UNKNOWN,
|
|
||||||
isNsfw = true,
|
|
||||||
coverUrl = img.attrAsAbsoluteUrlOrNull("data-src")
|
|
||||||
?: img.attrAsAbsoluteUrl("src"),
|
|
||||||
tags = setOf(),
|
|
||||||
state = null,
|
|
||||||
author = null,
|
|
||||||
largeCoverUrl = null,
|
|
||||||
description = null,
|
|
||||||
chapters = listOf(),
|
|
||||||
source = source,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getDetails(manga: Manga): Manga {
|
|
||||||
val root = webClient.httpGet(
|
|
||||||
url = manga.url.toAbsoluteUrl(domain),
|
|
||||||
).parseHtml().body().requireElementById("bigcontainer")
|
|
||||||
val img = root.requireElementById("cover").selectFirstOrThrow("img")
|
|
||||||
val tagContainers = root.requireElementById("tags").select(".tag-container")
|
|
||||||
val dateFormat = SimpleDateFormat(
|
|
||||||
"yyyy-MM-dd'T'HH:mm:ss.SSSSSS'+00:00'",
|
|
||||||
Locale.ROOT,
|
|
||||||
)
|
|
||||||
return manga.copy(
|
|
||||||
tags = tagContainers.find { x -> x.ownText() == "Tags:" }?.parseTags() ?: manga.tags,
|
|
||||||
author = tagContainers.find { x -> x.ownText() == "Artists:" }
|
|
||||||
?.selectFirst("span.name")?.text()?.toCamelCase(),
|
|
||||||
largeCoverUrl = img.attrAsAbsoluteUrlOrNull("data-src")
|
|
||||||
?: img.attrAsAbsoluteUrl("src"),
|
|
||||||
description = null,
|
|
||||||
chapters = listOf(
|
|
||||||
MangaChapter(
|
|
||||||
id = manga.id,
|
|
||||||
name = manga.title,
|
|
||||||
number = 1,
|
|
||||||
url = manga.url,
|
|
||||||
scanlator = null,
|
|
||||||
uploadDate = dateFormat.tryParse(
|
|
||||||
tagContainers.find { x -> x.ownText() == "Uploaded:" }
|
|
||||||
?.selectFirst("time")
|
|
||||||
?.attr("datetime"),
|
|
||||||
),
|
|
||||||
branch = null,
|
|
||||||
source = source,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
|
||||||
val url = chapter.url.toAbsoluteUrl(domain)
|
|
||||||
val root = webClient.httpGet(url).parseHtml().requireElementById("thumbnail-container")
|
|
||||||
return root.select(".thumb-container").map { div ->
|
|
||||||
val a = div.selectFirstOrThrow("a")
|
|
||||||
val img = div.selectFirstOrThrow("img")
|
|
||||||
val href = a.attrAsRelativeUrl("href")
|
|
||||||
MangaPage(
|
|
||||||
id = generateUid(href),
|
|
||||||
url = href,
|
|
||||||
preview = img.attrAsAbsoluteUrlOrNull("data-src")
|
|
||||||
?: img.attrAsAbsoluteUrl("src"),
|
|
||||||
source = source,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getPageUrl(page: MangaPage): String {
|
|
||||||
val root = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml().body()
|
|
||||||
.requireElementById("image-container")
|
|
||||||
return root.selectFirstOrThrow("img").attrAsAbsoluteUrl("src")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getTags(): Set<MangaTag> {
|
|
||||||
return coroutineScope {
|
|
||||||
// parse first 3 pages of tags
|
|
||||||
(1..3).map { page ->
|
|
||||||
async { getTags(page) }
|
|
||||||
}
|
|
||||||
}.awaitAll().flattenTo(ArraySet(360))
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun getTags(page: Int): Set<MangaTag> {
|
|
||||||
val root = webClient.httpGet("https://${domain}/tags/popular?page=$page").parseHtml().body()
|
|
||||||
.getElementById("tag-container")
|
|
||||||
return root?.parseTags().orEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Element.parseTags() = select("a.tag").mapToSet { a ->
|
|
||||||
val href = a.attr("href").removeSuffix('/')
|
|
||||||
MangaTag(
|
|
||||||
title = a.selectFirstOrThrow(".name").text().toTitleCase(),
|
|
||||||
key = href.substringAfterLast('/'),
|
|
||||||
source = source,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildQuery(tags: Collection<MangaTag>) = tags.joinToString(separator = " ") { tag ->
|
|
||||||
"tag:\"${tag.key}\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
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.mapToSet
|
||||||
|
import org.koitharu.kotatsu.parsers.util.removeSuffix
|
||||||
|
|
||||||
|
@MangaSourceParser("ASMHENTAI", "AsmHentai", type = ContentType.HENTAI)
|
||||||
|
internal class AsmHentai(context: MangaLoaderContext) :
|
||||||
|
GalleryAdultsParser(context, MangaSource.ASMHENTAI, "asmhentai.com") {
|
||||||
|
override val selectGalleryLink = ".image a"
|
||||||
|
override val selectGalleryImg = ".image img"
|
||||||
|
override val pathTagUrl = "/tags/?page="
|
||||||
|
override val selectAuthor = "div.tags:contains(Artists:) .tag_list a span.tag"
|
||||||
|
override val selectTotalPage = ".tp"
|
||||||
|
override val idImg = "fimg"
|
||||||
|
|
||||||
|
override fun Element.parseTags() = select("a").mapToSet {
|
||||||
|
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
|
||||||
|
val name = it.selectFirst(".tag")?.html()?.substringBefore("<") ?: it.html().substringBefore("<")
|
||||||
|
MangaTag(
|
||||||
|
key = key,
|
||||||
|
title = name,
|
||||||
|
source = source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||||
|
|
||||||
|
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.domain
|
||||||
|
import org.koitharu.kotatsu.parsers.util.oneOrThrowIfMany
|
||||||
|
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||||
|
import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow
|
||||||
|
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
|
||||||
|
import org.koitharu.kotatsu.parsers.util.urlEncoded
|
||||||
|
|
||||||
|
@MangaSourceParser("HENTAIERA", "HentaiEra", type = ContentType.HENTAI)
|
||||||
|
internal class HentaiEra(context: MangaLoaderContext) :
|
||||||
|
GalleryAdultsParser(context, MangaSource.HENTAIERA, "hentaiera.com", 25) {
|
||||||
|
override val selectGallery = ".thumb"
|
||||||
|
override val pathTagUrl = "/tags/popular?page="
|
||||||
|
override val selectTags = ".tags_section"
|
||||||
|
override val selectTag = ".galleries_info li:contains(Tags) div.info_tags"
|
||||||
|
override val selectAuthor = ".galleries_info li:contains(Artists) span.item_name"
|
||||||
|
override val urlReplaceBefore = "/gallery/"
|
||||||
|
override val urlReplaceAfter = "/view/"
|
||||||
|
override val selectLanguageChapter = ".galleries_info li:contains(Languages) div.info_tags .item_name"
|
||||||
|
|
||||||
|
override suspend fun getListPage(
|
||||||
|
page: Int,
|
||||||
|
query: String?,
|
||||||
|
tags: Set<MangaTag>?,
|
||||||
|
sortOrder: SortOrder,
|
||||||
|
): List<Manga> {
|
||||||
|
val tag = tags.oneOrThrowIfMany()
|
||||||
|
val url = buildString {
|
||||||
|
append("https://")
|
||||||
|
append(domain)
|
||||||
|
if (!tags.isNullOrEmpty()) {
|
||||||
|
append("/tag/")
|
||||||
|
append(tag?.key.orEmpty())
|
||||||
|
append("/?")
|
||||||
|
|
||||||
|
} else if (!query.isNullOrEmpty()) {
|
||||||
|
append("/search/?key=")
|
||||||
|
append(query.urlEncoded())
|
||||||
|
append("&")
|
||||||
|
} else {
|
||||||
|
append("/?")
|
||||||
|
}
|
||||||
|
append("page=")
|
||||||
|
append(page)
|
||||||
|
}
|
||||||
|
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getDetails(manga: Manga): Manga {
|
||||||
|
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
|
||||||
|
val urlChapters = manga.url.replace(urlReplaceBefore, urlReplaceAfter) + "1/"
|
||||||
|
val tag = doc.selectFirstOrThrow(selectTag)
|
||||||
|
return manga.copy(
|
||||||
|
tags = tag.parseTags(),
|
||||||
|
author = doc.selectFirst(selectAuthor)?.text(),
|
||||||
|
chapters = listOf(
|
||||||
|
MangaChapter(
|
||||||
|
id = manga.id,
|
||||||
|
name = manga.title,
|
||||||
|
number = 1,
|
||||||
|
url = urlChapters,
|
||||||
|
scanlator = null,
|
||||||
|
uploadDate = 0,
|
||||||
|
branch = doc.selectFirst(selectLanguageChapter)?.text(),
|
||||||
|
source = source,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
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.*
|
||||||
|
|
||||||
|
@MangaSourceParser("HENTAIFOX", "HentaiFox", type = ContentType.HENTAI)
|
||||||
|
internal class HentaiFox(context: MangaLoaderContext) :
|
||||||
|
GalleryAdultsParser(context, MangaSource.HENTAIFOX, "hentaifox.com") {
|
||||||
|
override val selectGallery = ".lc_galleries .thumb, .related_galleries .thumb"
|
||||||
|
override val selectTags = ".list_tags"
|
||||||
|
override val selectTag = "ul.tags"
|
||||||
|
override val urlReplaceBefore = "/gallery/"
|
||||||
|
override val urlReplaceAfter = "/g/"
|
||||||
|
override val selectLanguageChapter = "ul.languages a.tag_btn"
|
||||||
|
|
||||||
|
override val selectTotalPage = ".total_pages"
|
||||||
|
|
||||||
|
override suspend fun getListPage(
|
||||||
|
page: Int,
|
||||||
|
query: String?,
|
||||||
|
tags: Set<MangaTag>?,
|
||||||
|
sortOrder: SortOrder,
|
||||||
|
): List<Manga> {
|
||||||
|
val tag = tags.oneOrThrowIfMany()
|
||||||
|
val url = buildString {
|
||||||
|
append("https://")
|
||||||
|
append(domain)
|
||||||
|
if (!tags.isNullOrEmpty()) {
|
||||||
|
append("/tag/")
|
||||||
|
append(tag?.key.orEmpty())
|
||||||
|
if (page > 1) {
|
||||||
|
append("/pag/")
|
||||||
|
append(page)
|
||||||
|
append("/")
|
||||||
|
}
|
||||||
|
} else if (!query.isNullOrEmpty()) {
|
||||||
|
append("/search/?q=")
|
||||||
|
append(query.urlEncoded())
|
||||||
|
if (page > 1) {
|
||||||
|
append("&page=")
|
||||||
|
append(page)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (page > 2) {
|
||||||
|
append("/pag/")
|
||||||
|
append(page)
|
||||||
|
append("/")
|
||||||
|
} else if (page > 1) {
|
||||||
|
append("/page/")
|
||||||
|
append(page)
|
||||||
|
append("/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun Element.parseTags() = select("a").mapToSet {
|
||||||
|
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
|
||||||
|
val name = it.html().substringBefore("<")
|
||||||
|
MangaTag(
|
||||||
|
key = key,
|
||||||
|
title = name,
|
||||||
|
source = source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package org.koitharu.kotatsu.parsers.site.galleryadults.all
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@MangaSourceParser("HENTAIROX", "HentaiRox", type = ContentType.HENTAI)
|
||||||
|
internal class HentaiRox(context: MangaLoaderContext) :
|
||||||
|
GalleryAdultsParser(context, MangaSource.HENTAIROX, "hentairox.com") {
|
||||||
|
override val selectGallery = ".thumb"
|
||||||
|
override val pathTagUrl = "/tags/popular?page="
|
||||||
|
override val selectTags = ".gtags"
|
||||||
|
override val selectTag = "li:contains(Tags:)"
|
||||||
|
override val selectAuthor = "li:contains(Artists:) span.item_name"
|
||||||
|
override val urlReplaceBefore = "/gallery/"
|
||||||
|
override val urlReplaceAfter = "/view/"
|
||||||
|
override val selectLanguageChapter = "li:contains(Languages:) .item_name"
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
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.*
|
||||||
|
|
||||||
|
@MangaSourceParser("NHENTAI", "NHentai", type = ContentType.HENTAI)
|
||||||
|
internal class NHentaiParser(context: MangaLoaderContext) :
|
||||||
|
GalleryAdultsParser(context, MangaSource.NHENTAI, "nhentai.net", 25) {
|
||||||
|
override val selectGallery = "div.index-container:not(.index-popular) .gallery, #related-container .gallery"
|
||||||
|
override val selectGalleryLink = "a"
|
||||||
|
override val selectGalleryImg = "img"
|
||||||
|
override val selectGalleryTitle = ".caption"
|
||||||
|
override val pathTagUrl = "/tags/popular?page="
|
||||||
|
override val selectTags = "#tag-container a"
|
||||||
|
override val selectTag = ".tag-container:contains(Tags:) span.tags"
|
||||||
|
override val selectAuthor = "#tags div.tag-container:contains(Artists:) span.name"
|
||||||
|
override val urlReplaceBefore = "/g/"
|
||||||
|
override val urlReplaceAfter = "/g/"
|
||||||
|
override val selectLanguageChapter =
|
||||||
|
".tag-container:contains(Languages:) span.tags a:not(.tag-17249) span.name" // tag-17249 = translated
|
||||||
|
|
||||||
|
override val selectTotalPage = ".num-pages"
|
||||||
|
override val idImg = "image-container"
|
||||||
|
|
||||||
|
override suspend fun getListPage(
|
||||||
|
page: Int,
|
||||||
|
query: String?,
|
||||||
|
tags: Set<MangaTag>?,
|
||||||
|
sortOrder: SortOrder,
|
||||||
|
): List<Manga> {
|
||||||
|
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()) {
|
||||||
|
val tag = tags.single()
|
||||||
|
append("/tag/")
|
||||||
|
append(tag.key)
|
||||||
|
append("/?")
|
||||||
|
|
||||||
|
} else if (!query.isNullOrEmpty()) {
|
||||||
|
append("/search/?q=")
|
||||||
|
append(query.urlEncoded())
|
||||||
|
append("&")
|
||||||
|
} else {
|
||||||
|
append("/?")
|
||||||
|
}
|
||||||
|
append("page=")
|
||||||
|
append(page)
|
||||||
|
}
|
||||||
|
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getPageUrl(page: MangaPage): String {
|
||||||
|
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
|
||||||
|
val root = doc.body()
|
||||||
|
return root.requireElementById(idImg).selectFirstOrThrow("img").src() ?: root.parseFailed("Image src not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun Element.parseTags() = select("a").mapToSet {
|
||||||
|
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
|
||||||
|
val name = it.selectFirst(".name")?.text() ?: it.text()
|
||||||
|
MangaTag(
|
||||||
|
key = key,
|
||||||
|
title = name,
|
||||||
|
source = source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildQuery(tags: Collection<MangaTag>) = tags.joinToString(separator = " ") { tag ->
|
||||||
|
"tag:\"${tag.key}\""
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue