Fixes batch

master
Koitharu 2 years ago
parent 2f5441ef20
commit 789e39b6cb
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -71,4 +71,15 @@ class MangaChapter(
override fun toString(): String {
return "MangaChapter($id - #$number [$url] - $source)"
}
internal fun copy(number: Int) = MangaChapter(
id = id,
name = name,
number = number,
url = url,
scanlator = scanlator,
uploadDate = uploadDate,
branch = branch,
source = source,
)
}

@ -417,6 +417,4 @@ internal class ExHentaiParser(
}
return joiner.complete().takeUnless { it.isEmpty() }
}
private fun String.isNumeric() = all { c -> c.isDigit() }
}

@ -155,28 +155,13 @@ internal abstract class GroupleParser(
val scripts = doc.select("script")
for (script in scripts) {
val data = script.html()
val pos = data.indexOf("rm_h.readerInit( 0,")
if (pos == -1) {
continue
var pos = data.indexOf("rm_h.readerDoInit(")
if (pos != -1) {
parsePagesNew(data, pos)?.let { return it } ?: continue
}
val json = data.substring(pos).substringAfter('(').substringBefore('\n').substringBeforeLast(')')
if (json.isEmpty()) {
continue
}
val ja = JSONArray("[$json]")
val pages = ja.getJSONArray(1)
val servers = ja.getJSONArray(3).mapJSON { it.getString("path") }
val serversStr = servers.joinToString("|")
return (0 until pages.length()).map { i ->
val page = pages.getJSONArray(i)
val primaryServer = page.getString(0)
val url = page.getString(2)
MangaPage(
id = generateUid(url),
url = "$primaryServer|$serversStr|$url",
preview = null,
source = source,
)
pos = data.indexOf("rm_h.readerInit( 0,")
if (pos != -1) {
parsePagesOld(data, pos)?.let { return it } ?: continue
}
}
doc.parseFailed("Pages list not found at ${chapter.url}")
@ -373,4 +358,48 @@ internal abstract class GroupleParser(
source = source,
)
}
private fun parsePagesNew(data: String, pos: Int): List<MangaPage>? {
val json = data.substring(pos).substringAfter('(').substringBefore('\n').substringBeforeLast(')')
if (json.isEmpty()) {
return null
}
val ja = JSONArray("[$json]")
val pages = ja.getJSONArray(0)
val servers = ja.getJSONArray(2).mapJSON { it.getString("path") }
val serversStr = servers.joinToString("|")
return (0 until pages.length()).map { i ->
val page = pages.getJSONArray(i)
val primaryServer = page.getString(2)
val url = page.getString(1)
MangaPage(
id = generateUid(url),
url = "$primaryServer|$serversStr|$url",
preview = null,
source = source,
)
}
}
private fun parsePagesOld(data: String, pos: Int): List<MangaPage>? {
val json = data.substring(pos).substringAfter('(').substringBefore('\n').substringBeforeLast(')')
if (json.isEmpty()) {
return null
}
val ja = JSONArray("[$json]")
val pages = ja.getJSONArray(1)
val servers = ja.getJSONArray(3).mapJSON { it.getString("path") }
val serversStr = servers.joinToString("|")
return (0 until pages.length()).map { i ->
val page = pages.getJSONArray(i)
val primaryServer = page.getString(0)
val url = page.getString(2)
MangaPage(
id = generateUid(url),
url = "$primaryServer|$serversStr|$url",
preview = null,
source = source,
)
}
}
}

@ -11,9 +11,8 @@ internal class MintMangaParser(
) : GroupleParser(context, MangaSource.MINTMANGA, 2) {
override val configKeyDomain = ConfigKey.Domain(
"23.mintmanga.live",
"24.mintmanga.one",
"mintmanga.live",
"mintmanga.com",
"m.mintmanga.live",
)
}

@ -1,6 +1,7 @@
package org.koitharu.kotatsu.parsers.site.ru.multichan
import okhttp3.HttpUrl
import org.jsoup.internal.StringUtil
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
@ -22,21 +23,17 @@ internal abstract class ChanParser(
SortOrder.RATING,
)
override val isTagsExclusionSupported: Boolean = true
override val authUrl: String
get() = "https://${domain}"
override val isAuthorized: Boolean
get() = context.cookieJar.getCookies(domain).any { it.name == "dle_user_id" }
override suspend fun getList(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
tagsExclude: Set<MangaTag>?,
sortOrder: SortOrder,
): List<Manga> {
override suspend fun getList(offset: Int, filter: MangaListFilter?): List<Manga> {
val domain = domain
val doc = webClient.httpGet(buildUrl(offset, query, tags, sortOrder)).parseHtml()
val doc = webClient.httpGet(buildUrl(offset, filter)).parseHtml()
val root = doc.body().selectFirst("div.main_fon")?.getElementById("content")
?: doc.parseFailed("Cannot find root")
return root.select("div.content_row").mapNotNull { row ->
@ -180,48 +177,56 @@ internal abstract class ChanParser(
protected open fun buildUrl(
offset: Int,
query: String?,
tags: Set<MangaTag>?,
sortOrder: SortOrder,
filter: MangaListFilter?,
): HttpUrl {
val builder = urlBuilder()
builder.addQueryParameter("offset", offset.toString())
when {
!query.isNullOrEmpty() -> {
when (filter) {
is MangaListFilter.Search -> {
builder.addQueryParameter("do", "search")
builder.addQueryParameter("subaction", "search")
builder.addQueryParameter("search_start", ((offset / 40) + 1).toString())
builder.addQueryParameter("full_search", "0")
builder.addQueryParameter("result_from", (offset + 1).toString())
builder.addQueryParameter("result_num", "40")
builder.addQueryParameter("story", query)
builder.addQueryParameter("story", filter.query)
builder.addQueryParameter("need_sort_date", "false")
}
!tags.isNullOrEmpty() -> {
builder.addPathSegment("tags")
builder.addPathSegment(tags.joinToString("+") { it.key })
builder.addQueryParameter(
"n",
when (sortOrder) {
SortOrder.RATING,
SortOrder.POPULARITY,
-> "favdesc"
SortOrder.ALPHABETICAL -> "abcasc"
else -> "" // SortOrder.NEWEST
},
)
is MangaListFilter.Advanced -> {
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty()) {
builder.addPathSegment("tags")
val joiner = StringUtil.StringJoiner("+")
filter.tags.forEach { joiner.add(it.key) }
filter.tagsExclude.forEach { joiner.add("-"); joiner.append(it.key) }
builder.addPathSegment(joiner.complete())
builder.addQueryParameter(
"n",
when (filter.sortOrder) {
SortOrder.RATING,
SortOrder.POPULARITY,
-> "favdesc"
SortOrder.ALPHABETICAL -> "abcasc"
else -> "" // SortOrder.NEWEST
},
)
} else {
when (filter.sortOrder) {
SortOrder.POPULARITY -> builder.addPathSegment("mostviews")
SortOrder.ALPHABETICAL -> builder.addPathSegment("catalog")
SortOrder.RATING -> builder.addPathSegment("mostfavorites")
else -> { // SortOrder.NEWEST
builder.addPathSegment("manga")
builder.addPathSegment("new")
}
}
}
}
else -> when (sortOrder) {
SortOrder.POPULARITY -> builder.addPathSegment("mostviews")
SortOrder.ALPHABETICAL -> builder.addPathSegment("catalog")
SortOrder.RATING -> builder.addPathSegment("mostfavorites")
else -> { // SortOrder.NEWEST
builder.addPathSegment("manga")
builder.addPathSegment("new")
}
null -> {
builder.addPathSegment("manga")
builder.addPathSegment("new")
}
}
return builder.build()

@ -58,10 +58,10 @@ internal class HenChanParser(context: MangaLoaderContext) : ChanParser(context,
)
}
override fun buildUrl(offset: Int, query: String?, tags: Set<MangaTag>?, sortOrder: SortOrder): HttpUrl {
if (query.isNullOrEmpty() && tags.isNullOrEmpty()) {
override fun buildUrl(offset: Int, filter: MangaListFilter?): HttpUrl = when {
filter is MangaListFilter.Advanced && filter.tags.isEmpty() && filter.tagsExclude.isEmpty() -> {
val builder = urlBuilder().addQueryParameter("offset", offset.toString())
when (sortOrder) {
when (filter.sortOrder) {
SortOrder.POPULARITY -> {
builder.addPathSegment("mostviews")
builder.addQueryParameter("sort", "manga")
@ -77,8 +77,18 @@ internal class HenChanParser(context: MangaLoaderContext) : ChanParser(context,
builder.addPathSegment("newest")
}
}
return builder.build()
builder.build()
}
filter == null -> {
val builder = urlBuilder().addQueryParameter("offset", offset.toString())
builder.addPathSegment("manga")
builder.addPathSegment("newest")
builder.build()
}
else -> {
super.buildUrl(offset, filter)
}
return super.buildUrl(offset, query, tags, sortOrder)
}
}

@ -178,9 +178,11 @@ internal abstract class WpComicsParser(
val tagItems = doc.select("div.genre-item")
val result = ArrayMap<String, MangaTag>(tagItems.size)
for (item in tagItems) {
val title = item.text().trim()
val title = item.text()
val key = item.select("span[data-id]").attr("data-id")
result[title] = MangaTag(title = title, key = key, source = source)
if (key.isNotEmpty() && title.isNotEmpty()) {
result[title] = MangaTag(title = title, key = key, source = source)
}
}
tagCache = result
result
@ -216,7 +218,7 @@ internal abstract class WpComicsParser(
protected open val selectDate = "div.col-xs-4"
protected open val selectChapter = "div#nt_listchapter li:not(.heading)"
protected open val selectChapter = "div#nt_listchapter li .chapter"
protected open suspend fun getChapters(doc: Document): List<MangaChapter> {
return doc.body().select(selectChapter).mapChapters(reversed = true) { i, li ->

@ -1,13 +1,15 @@
package org.koitharu.kotatsu.parsers.site.wpcomics.en
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
import org.koitharu.kotatsu.parsers.util.*
import java.util.EnumSet
import java.util.*
@MangaSourceParser("XOXOCOMICS", "XoxoComics", "en", ContentType.COMICS)
internal class XoxoComics(context: MangaLoaderContext) :
@ -146,6 +148,29 @@ internal class XoxoComics(context: MangaLoaderContext) :
)
}
override suspend fun getChapters(doc: Document): List<MangaChapter> {
val pages = doc.select("ul.pagination > li:not(.active)")
return if (pages.size <= 1) {
super.getChapters(doc)
} else {
val list = coroutineScope {
pages.mapNotNull { page ->
val a = page.selectFirst("a") ?: return@mapNotNull null
if (a.text().isNumeric()) {
val href = a.attrAsAbsoluteUrl("href")
async {
super.getChapters(webClient.httpGet(href).parseHtml()).asReversed()
}
} else {
null // TODO support pagination with overflow
}
}.awaitAll().flattenTo(ArrayList())
}
list.addAll(super.getChapters(doc).asReversed())
list.reverse()
list.mapIndexed { i, x -> x.copy(number = i + 1) }
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain) + "/all"

@ -10,6 +10,7 @@ import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
internal class NetTruyen(context: MangaLoaderContext) :
WpComicsParser(context, MangaSource.NETTRUYEN, "www.nettruyenlive.com", 36) {
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain(
"www.nettruyenaz.com",
"www.nettruyenlive.com",
"www.nettruyenio.com",
"www.nettruyento.com",

@ -7,4 +7,4 @@ import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
@MangaSourceParser("NHATTRUYENMIN", "NhattruyenPlus", "vi")
internal class Nhattruyenmin(context: MangaLoaderContext) :
WpComicsParser(context, MangaSource.NHATTRUYENMIN, "nhattruyenplus.com")
WpComicsParser(context, MangaSource.NHATTRUYENMIN, "nhattruyenmax.com")

@ -240,3 +240,5 @@ inline fun <T> Appendable.appendAll(
append(transform(item))
}
}
fun String.isNumeric() = all { c -> c.isDigit() }

Loading…
Cancel
Save