|
|
|
@ -2,14 +2,14 @@ package org.koitharu.kotatsu.parsers.site.all
|
|
|
|
|
|
|
|
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
|
|
import org.json.JSONObject
|
|
|
|
import org.json.JSONObject
|
|
|
|
import org.koitharu.kotatsu.parsers.Broken
|
|
|
|
import org.jsoup.HttpStatusException
|
|
|
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
|
|
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
|
|
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
|
|
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
|
|
|
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
|
|
|
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
|
|
|
import org.koitharu.kotatsu.parsers.core.LegacyPagedMangaParser
|
|
|
|
import org.koitharu.kotatsu.parsers.core.LegacyPagedMangaParser
|
|
|
|
import org.koitharu.kotatsu.parsers.exception.ParseException
|
|
|
|
import org.koitharu.kotatsu.parsers.exception.ParseException
|
|
|
|
import org.koitharu.kotatsu.parsers.model.*
|
|
|
|
|
|
|
|
import org.koitharu.kotatsu.parsers.network.UserAgents
|
|
|
|
import org.koitharu.kotatsu.parsers.network.UserAgents
|
|
|
|
|
|
|
|
import org.koitharu.kotatsu.parsers.model.*
|
|
|
|
import org.koitharu.kotatsu.parsers.util.*
|
|
|
|
import org.koitharu.kotatsu.parsers.util.*
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.getIntOrDefault
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.getIntOrDefault
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.getLongOrDefault
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.getLongOrDefault
|
|
|
|
@ -17,17 +17,18 @@ import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNullToSet
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNullToSet
|
|
|
|
import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrDefault
|
|
|
|
import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrDefault
|
|
|
|
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
|
|
|
|
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
|
|
|
|
|
|
|
|
import java.net.HttpURLConnection
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.util.*
|
|
|
|
import java.util.*
|
|
|
|
|
|
|
|
|
|
|
|
@Broken("Need fix getPages")
|
|
|
|
@MangaSourceParser("KOHARU", "Schale.network", type = ContentType.HENTAI)
|
|
|
|
@MangaSourceParser("KOHARU", "Schale Network", type = ContentType.HENTAI)
|
|
|
|
|
|
|
|
internal class Koharu(context: MangaLoaderContext) :
|
|
|
|
internal class Koharu(context: MangaLoaderContext) :
|
|
|
|
LegacyPagedMangaParser(context, MangaParserSource.KOHARU, 24) {
|
|
|
|
LegacyPagedMangaParser(context, MangaParserSource.KOHARU, 24) {
|
|
|
|
|
|
|
|
|
|
|
|
override val configKeyDomain = ConfigKey.Domain("niyaniya.moe")
|
|
|
|
override val configKeyDomain = ConfigKey.Domain("niyaniya.moe")
|
|
|
|
private val apiSuffix = "api.schale.network"
|
|
|
|
private val apiSuffix = "api.schale.network"
|
|
|
|
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_MOBILE)
|
|
|
|
|
|
|
|
|
|
|
|
override val userAgentKey = ConfigKey.UserAgent(UserAgents.KOHARU)
|
|
|
|
|
|
|
|
|
|
|
|
private val authorsIds = suspendLazy { fetchAuthorsIds() }
|
|
|
|
private val authorsIds = suspendLazy { fetchAuthorsIds() }
|
|
|
|
|
|
|
|
|
|
|
|
@ -320,19 +321,22 @@ internal class Koharu(context: MangaLoaderContext) :
|
|
|
|
val id = parts[0]
|
|
|
|
val id = parts[0]
|
|
|
|
val key = parts[1]
|
|
|
|
val key = parts[1]
|
|
|
|
|
|
|
|
|
|
|
|
val clearance = getClearance(chapter.url)
|
|
|
|
val clearance = getClearance(chapter.publicUrl())
|
|
|
|
|
|
|
|
|
|
|
|
val dataUrl = "https://$apiSuffix/books/detail/$id/$key?crt=$clearance"
|
|
|
|
val dataUrl = "https://$apiSuffix/books/detail/$id/$key?crt=$clearance"
|
|
|
|
val dataResponse = webClient.httpPost(
|
|
|
|
val data = try {
|
|
|
|
|
|
|
|
webClient.httpPost(
|
|
|
|
url = dataUrl.toHttpUrl(),
|
|
|
|
url = dataUrl.toHttpUrl(),
|
|
|
|
form = emptyMap(),
|
|
|
|
form = emptyMap(),
|
|
|
|
extraHeaders = getRequestHeaders(),
|
|
|
|
extraHeaders = getRequestHeaders(),
|
|
|
|
).parseJson()
|
|
|
|
).parseJson().getJSONObject("data")
|
|
|
|
|
|
|
|
} catch (e: HttpStatusException) {
|
|
|
|
val data = try {
|
|
|
|
if (e.statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
|
|
|
|
dataResponse.getJSONObject("data").getJSONObject("data")
|
|
|
|
// Token may be invalid or expired
|
|
|
|
} catch (e: Exception) {
|
|
|
|
// WebView should be closed after receiving Token
|
|
|
|
throw ParseException("Cant parse image data. Token may be invalid or expired: ${e.message}", dataUrl, e)
|
|
|
|
context.requestBrowserAction(this, chapter.publicUrl())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
throw e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
val preferredRes = config[preferredImageResolutionKey] ?: "1280"
|
|
|
|
val preferredRes = config[preferredImageResolutionKey] ?: "1280"
|
|
|
|
@ -406,7 +410,9 @@ internal class Koharu(context: MangaLoaderContext) :
|
|
|
|
private suspend fun fetchAuthorsIds(): Map<String, String> = fetchTags(namespace = 1)
|
|
|
|
private suspend fun fetchAuthorsIds(): Map<String, String> = fetchTags(namespace = 1)
|
|
|
|
.associate { it.title.lowercase() to it.key }
|
|
|
|
.associate { it.title.lowercase() to it.key }
|
|
|
|
|
|
|
|
|
|
|
|
private suspend fun getClearance(mangaId: String): String = WebViewHelper(context)
|
|
|
|
private suspend fun getClearance(chapterUrl: String): String = WebViewHelper(context)
|
|
|
|
.getLocalStorageValue(domain, "clearance")?.removeSurrounding('"')?.nullIfEmpty()
|
|
|
|
.getLocalStorageValue(domain, "clearance")?.removeSurrounding('"')?.nullIfEmpty()
|
|
|
|
?: context.requestBrowserAction(this, "https://$domain/g/$mangaId/read/1")
|
|
|
|
?: context.requestBrowserAction(this, chapterUrl)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun MangaChapter.publicUrl() = "https://$domain/g/$url/read/1"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|