diff --git a/build.gradle b/build.gradle index 54baa889..4a2e05ce 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,7 @@ kotlin { dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1' implementation 'com.squareup.okhttp3:okhttp:4.9.3' - implementation 'com.squareup.okio:okio:3.0.0' + implementation 'com.squareup.okio:okio:3.1.0' implementation 'org.jsoup:jsoup:1.14.3' implementation 'org.json:json:20220320' implementation 'androidx.collection:collection-ktx:1.2.0' diff --git a/kotatsu-parsers-ksp/build.gradle b/kotatsu-parsers-ksp/build.gradle index 9ae06d1d..e6317098 100644 --- a/kotatsu-parsers-ksp/build.gradle +++ b/kotatsu-parsers-ksp/build.gradle @@ -3,5 +3,5 @@ plugins { } dependencies { - implementation 'com.google.devtools.ksp:symbol-processing-api:1.6.20-1.0.5' + implementation 'com.google.devtools.ksp:symbol-processing-api:1.6.21-1.0.5' } \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt index 25fd49db..ed7f8498 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaLoaderContext.kt @@ -41,6 +41,7 @@ abstract class MangaLoaderContext { suspend fun httpPost( url: String, form: Map, + headers: Headers? = null, ): Response { val body = FormBody.Builder() form.forEach { (k, v) -> @@ -49,12 +50,16 @@ abstract class MangaLoaderContext { val request = Request.Builder() .post(body.build()) .url(url) + if (headers != null) { + request.headers(headers) + } return httpClient.newCall(request.build()).await().ensureSuccess() } suspend fun httpPost( url: String, payload: String, + headers: Headers?, ): Response { val body = FormBody.Builder() payload.split('&').forEach { @@ -68,6 +73,9 @@ abstract class MangaLoaderContext { val request = Request.Builder() .post(body.build()) .url(url) + if (headers != null) { + request.headers(headers) + } return httpClient.newCall(request.build()).await().ensureSuccess() } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt index 05ed85bc..0f9e1b53 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/GroupleParser.kt @@ -16,10 +16,10 @@ private const val PAGE_SIZE = 70 private const val PAGE_SIZE_SEARCH = 50 private const val NSFW_ALERT = "сексуальные сцены" -internal abstract class GroupleParser(source: MangaSource) : MangaParser(source) { +internal abstract class GroupleParser(source: MangaSource, userAgent: String) : MangaParser(source) { private val headers = Headers.Builder() - .add("User-Agent", "readmangafun") + .add("User-Agent", userAgent) .build() override val sortOrders: Set = EnumSet.of( @@ -43,6 +43,7 @@ internal abstract class GroupleParser(source: MangaSource) : MangaParser(source) "q" to query.urlEncoded(), "offset" to (offset upBy PAGE_SIZE_SEARCH).toString(), ), + headers, ) tags.isNullOrEmpty() -> context.httpGet( "https://$domain/list?sortType=${ @@ -166,12 +167,17 @@ internal abstract class GroupleParser(source: MangaSource) : MangaParser(source) val scripts = doc.select("script") for (script in scripts) { val data = script.html() - val pos = data.indexOf("rm_h.init") + val pos = data.indexOf("rm_h.initReader(") if (pos == -1) { continue } - val json = data.substring(pos).substringAfter('(').substringBefore('\n') + 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(4).mapJSON { it.getString("path") } @@ -199,11 +205,12 @@ internal abstract class GroupleParser(source: MangaSource) : MangaParser(source) val headers = Headers.headersOf("Referer", page.referer) for (server in servers) { val url = server + path - if (context.httpHead(url, headers).isSuccessful) { + if (tryHead(url, headers)) { return url } } - throw IllegalArgumentException("Cannot find any page url") + val fallbackServer = servers.firstOrNull() ?: parseFailed("Cannot find any page url") + return fallbackServer + path } override suspend fun getTags(): Set { @@ -263,6 +270,10 @@ internal abstract class GroupleParser(source: MangaSource) : MangaParser(source) payload["s_sale"] = "" payload["years"] = "1900,2099" payload["+"] = "Искать".urlEncoded() - return context.httpPost(url, payload) + return context.httpPost(url, payload, headers) } + + private suspend fun tryHead(url: String, headers: Headers): Boolean = runCatching { + context.httpHead(url, headers).isSuccessful + }.getOrDefault(false) } \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MintMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MintMangaParser.kt index 8e198469..f30cdadc 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MintMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/MintMangaParser.kt @@ -6,7 +6,9 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.MangaSource @MangaSourceParser("MINTMANGA", "MintManga", "ru") -internal class MintMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.MINTMANGA) { +internal class MintMangaParser( + override val context: MangaLoaderContext, +) : GroupleParser(MangaSource.MINTMANGA, "mintmangafun") { override val configKeyDomain = ConfigKey.Domain( "mintmanga.live", diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ReadmangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ReadmangaParser.kt index 5cd27116..31d98a7d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ReadmangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ReadmangaParser.kt @@ -6,7 +6,9 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.MangaSource @MangaSourceParser("READMANGA_RU", "ReadManga", "ru") -internal class ReadmangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.READMANGA_RU) { +internal class ReadmangaParser( + override val context: MangaLoaderContext, +) : GroupleParser(MangaSource.READMANGA_RU, "readmangafun") { override val configKeyDomain = ConfigKey.Domain( "readmanga.io", diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/SelfMangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/SelfMangaParser.kt index e00889e5..6a6280f8 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/SelfMangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/SelfMangaParser.kt @@ -6,7 +6,9 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.MangaSource @MangaSourceParser("SELFMANGA", "SelfManga", "ru") -internal class SelfMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.SELFMANGA) { +internal class SelfMangaParser( + override val context: MangaLoaderContext, +) : GroupleParser(MangaSource.SELFMANGA, "selfmangafun") { override val configKeyDomain = ConfigKey.Domain("selfmanga.live", null) } \ No newline at end of file