parent
22ba4be2b6
commit
1393a25fbb
47
src/en/readcomiconline/assets/script.js
Normal file
47
src/en/readcomiconline/assets/script.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
(() => {
|
||||||
|
const isValidUrl = (str) => {
|
||||||
|
try {
|
||||||
|
new URL(str);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const arrays = [];
|
||||||
|
const functions = [];
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
const builtInKeys = new Set(Object.getOwnPropertyNames(iframe.contentWindow));
|
||||||
|
document.body.removeChild(iframe);
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(window)) {
|
||||||
|
if (builtInKeys.has(key)) continue;
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
arrays.push(value);
|
||||||
|
} else if (typeof value === 'function' && value.length >= 1) {
|
||||||
|
functions.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arrays.forEach(arrayValue => {
|
||||||
|
functions.forEach(funcValue => {
|
||||||
|
try {
|
||||||
|
const mapped = arrayValue.map(x => funcValue(x));
|
||||||
|
|
||||||
|
if (
|
||||||
|
Array.isArray(mapped) &&
|
||||||
|
mapped.length != 0 &&
|
||||||
|
mapped.every(item => typeof item === 'string' && isValidUrl(item))
|
||||||
|
) {
|
||||||
|
results.push(mapped);
|
||||||
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return results
|
||||||
|
})();
|
@ -1,7 +1,7 @@
|
|||||||
ext {
|
ext {
|
||||||
extName = 'ReadComicOnline'
|
extName = 'ReadComicOnline'
|
||||||
extClass = '.Readcomiconline'
|
extClass = '.Readcomiconline'
|
||||||
extVersionCode = 31
|
extVersionCode = 32
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -9,12 +9,15 @@ import android.util.Log
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.webkit.ConsoleMessage
|
import android.webkit.ConsoleMessage
|
||||||
import android.webkit.WebChromeClient
|
import android.webkit.WebChromeClient
|
||||||
|
import android.webkit.WebResourceRequest
|
||||||
|
import android.webkit.WebResourceResponse
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
import eu.kanade.tachiyomi.lib.randomua.UserAgentType
|
import eu.kanade.tachiyomi.lib.randomua.UserAgentType
|
||||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
@ -23,8 +26,11 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
import keiyoushi.utils.getPreferencesLazy
|
import keiyoushi.utils.getPreferencesLazy
|
||||||
import kotlinx.serialization.decodeFromString
|
import keiyoushi.utils.parseAs
|
||||||
import kotlinx.serialization.json.Json
|
import keiyoushi.utils.tryParse
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -35,7 +41,6 @@ import org.jsoup.nodes.Element
|
|||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
@ -51,7 +56,8 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
override fun headersBuilder() = super.headersBuilder()
|
||||||
|
.set("Referer", "$baseUrl/")
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
.setRandomUserAgent(
|
.setRandomUserAgent(
|
||||||
@ -173,6 +179,7 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
val infoElement = document.select("div.barContent").first()!!
|
val infoElement = document.select("div.barContent").first()!!
|
||||||
|
|
||||||
val manga = SManga.create()
|
val manga = SManga.create()
|
||||||
|
manga.title = infoElement.selectFirst("a.bigChar")!!.text()
|
||||||
manga.artist = infoElement.select("p:has(span:contains(Artist:)) > a").first()?.text()
|
manga.artist = infoElement.select("p:has(span:contains(Artist:)) > a").first()?.text()
|
||||||
manga.author = infoElement.select("p:has(span:contains(Writer:)) > a").first()?.text()
|
manga.author = infoElement.select("p:has(span:contains(Writer:)) > a").first()?.text()
|
||||||
manga.genre = infoElement.select("p:has(span:contains(Genres:)) > *:gt(0)").text()
|
manga.genre = infoElement.select("p:has(span:contains(Genres:)) > *:gt(0)").text()
|
||||||
@ -211,12 +218,12 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||||
chapter.name = urlElement.text()
|
chapter.name = urlElement.text()
|
||||||
chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
|
chapter.date_upload = dateFormat.tryParse(element.selectFirst("td:eq(1)")?.text())
|
||||||
SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()).parse(it)?.time ?: 0L
|
|
||||||
} ?: 0
|
|
||||||
return chapter
|
return chapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val dateFormat = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault())
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
val qualitySuffix = if ((qualitypref() != "lq" && serverpref() != "s2") || (qualitypref() == "lq" && serverpref() == "s2")) {
|
val qualitySuffix = if ((qualitypref() != "lq" && serverpref() != "s2") || (qualitypref() == "lq" && serverpref() == "s2")) {
|
||||||
"&s=${serverpref()}&quality=${qualitypref()}&readType=1"
|
"&s=${serverpref()}&quality=${qualitypref()}&readType=1"
|
||||||
@ -232,12 +239,8 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
val latch = CountDownLatch(1)
|
val latch = CountDownLatch(1)
|
||||||
var webView: WebView? = null
|
var webView: WebView? = null
|
||||||
var images: List<String> = emptyList()
|
var urls: List<List<String>> = emptyList()
|
||||||
|
|
||||||
val html = document.outerHtml()
|
|
||||||
val match = KEY_REGEX.find(html)
|
|
||||||
val key1 = match?.groups?.get(1)?.value ?: throw Exception("Fail to get image links. Logging in via WebView may fix this issue.")
|
|
||||||
val key2 = match?.groups?.get(2)?.value ?: throw Exception("Fail to get image links. Logging in via WebView may fix this issue.")
|
|
||||||
handler.post {
|
handler.post {
|
||||||
val innerWv = WebView(Injekt.get<Application>())
|
val innerWv = WebView(Injekt.get<Application>())
|
||||||
|
|
||||||
@ -249,14 +252,32 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
innerWv.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
|
innerWv.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
|
||||||
|
|
||||||
innerWv.webViewClient = object : WebViewClient() {
|
innerWv.webViewClient = object : WebViewClient() {
|
||||||
override fun onLoadResource(view: WebView?, url: String?) {
|
private val emptyResponse = WebResourceResponse("text/plain", "utf-8", 200, "OK", mapOf(), "".byteInputStream())
|
||||||
|
|
||||||
|
override fun shouldInterceptRequest(
|
||||||
|
view: WebView?,
|
||||||
|
request: WebResourceRequest?,
|
||||||
|
): WebResourceResponse? {
|
||||||
|
val url = request?.url?.toString()
|
||||||
|
|
||||||
|
url ?: return emptyResponse
|
||||||
|
|
||||||
|
if (!url.contains("rguard")) {
|
||||||
|
return emptyResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.shouldInterceptRequest(view, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPageFinished(view: WebView?, url: String?) {
|
||||||
view?.evaluateJavascript(
|
view?.evaluateJavascript(
|
||||||
"""
|
Readcomiconline::class.java
|
||||||
window['$key2'].map(i => $key1(i));
|
.getResourceAsStream("/assets/script.js")!!
|
||||||
""".trimIndent(),
|
.bufferedReader()
|
||||||
|
.use { it.readText() },
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
images = json.decodeFromString<List<String>>(it)
|
urls = it.parseAs()
|
||||||
latch.countDown()
|
latch.countDown()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e("RCO", e.stackTraceToString())
|
Log.e("RCO", e.stackTraceToString())
|
||||||
@ -286,7 +307,7 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
|
|
||||||
innerWv.loadDataWithBaseURL(
|
innerWv.loadDataWithBaseURL(
|
||||||
document.location(),
|
document.location(),
|
||||||
html,
|
document.outerHtml(),
|
||||||
"text/html",
|
"text/html",
|
||||||
"UTF-8",
|
"UTF-8",
|
||||||
null,
|
null,
|
||||||
@ -300,6 +321,30 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
throw Exception("Timeout getting image links")
|
throw Exception("Timeout getting image links")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val images = runBlocking {
|
||||||
|
val valid = urls.map { urlList ->
|
||||||
|
async {
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(urlList.random())
|
||||||
|
.method("HEAD", null)
|
||||||
|
.headers(headers)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val response = client.newCall(request).await()
|
||||||
|
val contentType = response.headers["content-type"] ?: ""
|
||||||
|
val size = response.headers["content-length"]?.toLongOrNull() ?: 0L
|
||||||
|
|
||||||
|
response.isSuccessful && contentType.startsWith("image") && size > 100
|
||||||
|
}
|
||||||
|
}.awaitAll()
|
||||||
|
|
||||||
|
val index = valid.indexOf(true)
|
||||||
|
if (index == -1) {
|
||||||
|
throw Exception("No valid image links found")
|
||||||
|
}
|
||||||
|
urls[index]
|
||||||
|
}
|
||||||
|
|
||||||
return images.mapIndexed { idx, img ->
|
return images.mapIndexed { idx, img ->
|
||||||
Page(idx, imageUrl = img)
|
Page(idx, imageUrl = img)
|
||||||
}
|
}
|
||||||
@ -444,6 +489,5 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
private const val QUALITY_PREF = "qualitypref"
|
private const val QUALITY_PREF = "qualitypref"
|
||||||
private const val SERVER_PREF_TITLE = "Server Preference"
|
private const val SERVER_PREF_TITLE = "Server Preference"
|
||||||
private const val SERVER_PREF = "serverpref"
|
private const val SERVER_PREF = "serverpref"
|
||||||
private val KEY_REGEX = """\.attr\(\s*['"]src['"]\s*,\s*([\w]+)\(\s*([\w]+)\[\s*\w+""".toRegex()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user