diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt index a1b24d44..89622b8b 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/NineMangaParser.kt @@ -1,5 +1,8 @@ package org.koitharu.kotatsu.parsers.site.all +import androidx.collection.ArrayMap +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Interceptor import okhttp3.Response @@ -105,14 +108,11 @@ internal abstract class NineMangaParser( ).parseHtml() val root = doc.body().selectFirstOrThrow("div.manga") val infoRoot = root.selectFirstOrThrow("div.bookintro") + val tagMap = getOrCreateTagMap() + val selectTag = infoRoot.getElementsByAttributeValue("itemprop", "genre").first()?.select("a") + val tags = selectTag?.mapNotNullToSet { tagMap[it.text()] } return manga.copy( - tags = infoRoot.getElementsByAttributeValue("itemprop", "genre").first()?.select("a")?.mapToSet { a -> - MangaTag( - title = a.text().toTitleCase(), - key = a.attr("href").substringBetween("/", "."), - source = source, - ) - }.orEmpty(), + tags = tags.orEmpty(), author = infoRoot.getElementsByAttributeValue("itemprop", "author").first()?.text(), state = parseStatus(infoRoot.select("li a.red").text()), description = infoRoot.getElementsByAttributeValue("itemprop", "description").first()?.html() @@ -155,18 +155,29 @@ internal abstract class NineMangaParser( return root.selectFirst("a.pic_download")?.absUrl("href") ?: doc.parseFailed("Page image not found") } + private var tagCache: ArrayMap? = null + private val mutex = Mutex() + override suspend fun getTags(): Set { - val doc = webClient.httpGet("https://${domain}/search/?type=high").parseHtml() - val root = doc.body().getElementById("search_form") - return root?.select("li.cate_list")?.mapNotNullToSet { li -> - val cateId = li.attr("cate_id") ?: return@mapNotNullToSet null - val a = li.selectFirst("a") ?: return@mapNotNullToSet null - MangaTag( + return getOrCreateTagMap().values.toSet() + } + + protected suspend fun getOrCreateTagMap(): Map = mutex.withLock { + tagCache?.let { return@withLock it } + val tagMap = ArrayMap() + val tagElements = webClient.httpGet("https://${domain}/search/?type=high").parseHtml().select("li.cate_list") + for (el in tagElements) { + if (el.text().isEmpty()) continue + val cateId = el.attr("cate_id") + val a = el.selectFirstOrThrow("a") + tagMap[el.text()] = MangaTag( title = a.text().toTitleCase(), key = cateId, source = source, ) - } ?: doc.parseFailed("Root not found") + } + tagCache = tagMap + return@withLock tagMap } private fun parseStatus(status: String) = when { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/Neoxscans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/Neoxscans.kt index 7cc8acf5..2b14ae74 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/Neoxscans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madara/pt/Neoxscans.kt @@ -1,12 +1,49 @@ package org.koitharu.kotatsu.parsers.site.madara.pt +import org.jsoup.nodes.Document import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser +import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.site.madara.MadaraParser +import org.koitharu.kotatsu.parsers.util.* +import java.text.SimpleDateFormat @MangaSourceParser("NEOX_SCANS", "NeoxScans", "pt") -internal class Neoxscans(context: MangaLoaderContext) : +internal open class Neoxscans(context: MangaLoaderContext) : MadaraParser(context, MangaSource.NEOX_SCANS, "neoxscan.net", 18) { override val datePattern = "dd/MM/yyyy" + + override suspend fun loadChapters(mangaUrl: String, document: Document): List { + val doc = if (postReq) { + val mangaId = document.select("div#manga-chapters-holder").attr("data-id") + val url = "https://$domain/wp-admin/admin-ajax.php" + val postdata = "action=manga_get_chapters&manga=$mangaId" + webClient.httpPost(url, postdata).parseHtml() + } else { + val url = mangaUrl.toAbsoluteUrl(domain).removeSuffix('/') + "/ajax/chapters/" + webClient.httpPost(url, emptyMap()).parseHtml() + } + val dateFormat = SimpleDateFormat(datePattern, sourceLocale) + return doc.select(selectChapter).mapChapters(reversed = true) { i, li -> + val a = li.selectFirst("a") + val href = a?.attrAsRelativeUrlOrNull("href") ?: li.parseFailed("Link is missing") + val link = href + stylePage + val dateText = li.selectFirst("a.c-new-tag")?.attr("title") ?: li.selectFirst(selectDate)?.text() + val name = li.selectFirst("a:contains(Cap)")?.text() ?: a.ownText() + MangaChapter( + id = generateUid(href), + url = link, + name = name, + number = i + 1, + branch = null, + uploadDate = parseChapterDate( + dateFormat, + dateText, + ), + scanlator = null, + source = source, + ) + } + } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madtheme/en/MangaJinx.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madtheme/en/MangaJinx.kt new file mode 100644 index 00000000..0ebbcb33 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/madtheme/en/MangaJinx.kt @@ -0,0 +1,34 @@ +package org.koitharu.kotatsu.parsers.site.madtheme.en + +import org.koitharu.kotatsu.parsers.MangaLoaderContext +import org.koitharu.kotatsu.parsers.MangaSourceParser +import org.koitharu.kotatsu.parsers.model.MangaChapter +import org.koitharu.kotatsu.parsers.model.MangaPage +import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.parsers.site.madtheme.MadthemeParser +import org.koitharu.kotatsu.parsers.util.domain +import org.koitharu.kotatsu.parsers.util.generateUid +import org.koitharu.kotatsu.parsers.util.parseHtml +import org.koitharu.kotatsu.parsers.util.selectFirstOrThrow +import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl + +@MangaSourceParser("MANGAJINX", "MangaJinx", "en") +internal class MangaJinx(context: MangaLoaderContext) : + MadthemeParser(context, MangaSource.MANGAJINX, "mangajinx.com") { + override val listUrl = "search" + + override suspend fun getPages(chapter: MangaChapter): List { + val chapterUrl = chapter.url.toAbsoluteUrl(domain) + val docs = webClient.httpGet(chapterUrl).parseHtml() + val script = docs.selectFirstOrThrow("script:containsData(var chapImages)") + val images = script.data().substringAfter("= \"").substringBefore("\";").split(",") + return images.map { + MangaPage( + id = generateUid(it), + url = it, + preview = null, + source = source, + ) + } + } +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt index f8ee646b..89e94ec6 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/nepnep/NepnepParser.kt @@ -51,7 +51,9 @@ internal abstract class NepnepParser( val imgUrl = "https://temp.compsci88.com/cover/" + m.getString("i") + ".jpg" when { !query.isNullOrEmpty() -> { - if (m.getString("i").contains(query.urlEncoded(), ignoreCase = true)) { + if (m.getString("s").contains(query, ignoreCase = true) || m.getString("al") + .contains(query, ignoreCase = true) + ) { manga.add( addManga(href, imgUrl, m), )