This commit is contained in:
Horis
2024-07-08 08:48:04 +08:00
parent 5712a606ce
commit dd798012bd
7 changed files with 91 additions and 48 deletions
@@ -5,6 +5,7 @@ import android.webkit.WebSettings
import androidx.annotation.Keep
import cn.hutool.core.codec.Base64
import cn.hutool.core.util.HexUtil
import com.script.rhino.RhinoContext
import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.dateFormat
import io.legado.app.constant.AppLog
@@ -50,6 +51,7 @@ import kotlinx.coroutines.runBlocking
import okio.use
import org.jsoup.Connection
import org.jsoup.Jsoup
import org.mozilla.javascript.Context
import splitties.init.appCtx
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
@@ -65,6 +67,8 @@ import java.util.SimpleTimeZone
import java.util.UUID
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/**
* js扩展类, 在js中通过java变量调用
@@ -78,6 +82,12 @@ interface JsExtensions : JsEncodeUtils {
fun getSource(): BaseSource?
private val context: CoroutineContext
get() {
val rhinoContext = Context.getCurrentContext() as RhinoContext
return rhinoContext.coroutineContext ?: EmptyCoroutineContext
}
/**
* 访问网络,返回String
*/
@@ -87,9 +97,9 @@ interface JsExtensions : JsEncodeUtils {
} else {
url.toString()
}
return runBlocking {
val analyzeUrl = AnalyzeUrl(urlStr, source = getSource(), coroutineContext = context)
return runBlocking(context) {
kotlin.runCatching {
val analyzeUrl = AnalyzeUrl(urlStr, source = getSource())
analyzeUrl.getStrResponseAwait().body
}.onFailure {
AppLog.put("ajax(${urlStr}) error\n${it.localizedMessage}", it)
@@ -103,7 +113,7 @@ interface JsExtensions : JsEncodeUtils {
* 并发访问网络
*/
fun ajaxAll(urlList: Array<String>): Array<StrResponse?> {
return runBlocking {
return runBlocking(context) {
val asyncArray = Array(urlList.size) {
async(IO) {
val url = urlList[it]
@@ -122,7 +132,7 @@ interface JsExtensions : JsEncodeUtils {
* 访问网络,返回Response<String>
*/
fun connect(urlStr: String): StrResponse {
return runBlocking {
return runBlocking(context) {
val analyzeUrl = AnalyzeUrl(urlStr, source = getSource())
kotlin.runCatching {
analyzeUrl.getStrResponseAwait()
@@ -135,7 +145,7 @@ interface JsExtensions : JsEncodeUtils {
}
fun connect(urlStr: String, header: String?): StrResponse {
return runBlocking {
return runBlocking(context) {
val headerMap = GSON.fromJsonObject<Map<String, String>>(header).getOrNull()
val analyzeUrl = AnalyzeUrl(urlStr, headerMapF = headerMap, source = getSource())
kotlin.runCatching {
@@ -156,7 +166,7 @@ interface JsExtensions : JsEncodeUtils {
* @return 返回js获取的内容
*/
fun webView(html: String?, url: String?, js: String?): String? {
return runBlocking {
return runBlocking(context) {
BackstageWebView(
url = url,
html = html,
@@ -171,7 +181,7 @@ interface JsExtensions : JsEncodeUtils {
* 使用webView获取资源url
*/
fun webViewGetSource(html: String?, url: String?, js: String?, sourceRegex: String): String? {
return runBlocking {
return runBlocking(context) {
BackstageWebView(
url = url,
html = html,
@@ -192,7 +202,7 @@ interface JsExtensions : JsEncodeUtils {
js: String?,
overrideUrlRegex: String
): String? {
return runBlocking {
return runBlocking(context) {
BackstageWebView(
url = url,
html = html,
@@ -294,7 +304,7 @@ interface JsExtensions : JsEncodeUtils {
* @return 下载的文件相对路径
*/
fun downloadFile(url: String): String {
val analyzeUrl = AnalyzeUrl(url, source = getSource())
val analyzeUrl = AnalyzeUrl(url, source = getSource(), coroutineContext = context)
val type = UrlUtil.getSuffix(url, analyzeUrl.type)
val path = FileUtils.getPath(
File(FileUtils.getCachePath()),
@@ -321,7 +331,8 @@ interface JsExtensions : JsEncodeUtils {
ReplaceWith("downloadFile(url: String)")
)
fun downloadFile(content: String, url: String): String {
val type = AnalyzeUrl(url, source = getSource()).type ?: return ""
val type = AnalyzeUrl(url, source = getSource(), coroutineContext = context).type
?: return ""
val path = FileUtils.getPath(
FileUtils.createFolderIfNotExist(FileUtils.getCachePath()),
"${MD5Utils.md5Encode16(url)}.${type}"
@@ -689,7 +700,7 @@ interface JsExtensions : JsEncodeUtils {
*/
fun getZipByteArrayContent(url: String, path: String): ByteArray? {
val bytes = if (url.isAbsUrl()) {
AnalyzeUrl(url, source = getSource()).getByteArray()
AnalyzeUrl(url, source = getSource(), coroutineContext = context).getByteArray()
} else {
HexUtil.decodeHex(url)
}
@@ -717,7 +728,7 @@ interface JsExtensions : JsEncodeUtils {
*/
fun getRarByteArrayContent(url: String, path: String): ByteArray? {
val bytes = if (url.isAbsUrl()) {
AnalyzeUrl(url, source = getSource()).getByteArray()
AnalyzeUrl(url, source = getSource(), coroutineContext = context).getByteArray()
} else {
HexUtil.decodeHex(url)
}
@@ -735,7 +746,7 @@ interface JsExtensions : JsEncodeUtils {
*/
fun get7zByteArrayContent(url: String, path: String): ByteArray? {
val bytes = if (url.isAbsUrl()) {
AnalyzeUrl(url, source = getSource()).getByteArray()
AnalyzeUrl(url, source = getSource(), coroutineContext = context).getByteArray()
} else {
HexUtil.decodeHex(url)
}
@@ -769,14 +780,20 @@ interface JsExtensions : JsEncodeUtils {
when (data) {
is String -> {
if (useCache) {
key = MessageDigest.getInstance("SHA-256").digest(data.toByteArray()).toHexString()
key = MessageDigest.getInstance("SHA-256").digest(data.toByteArray())
.toHexString()
qTTF = CacheManager.getQueryTTF(key)
if (qTTF != null) return qTTF
}
val font: ByteArray? = when {
data.isContentScheme() -> Uri.parse(data).readBytes(appCtx)
data.startsWith("/storage") -> File(data).readBytes()
data.isAbsUrl() -> AnalyzeUrl(data, source = getSource()).getByteArray()
data.isAbsUrl() -> AnalyzeUrl(
data,
source = getSource(),
coroutineContext = context
).getByteArray()
else -> base64DecodeToByteArray(data)
}
font ?: return null
@@ -32,7 +32,9 @@ import java.util.regex.Pattern
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/**
* 解析规则获取结果
@@ -67,7 +69,7 @@ class AnalyzeRule(
private val stringRuleCache = hashMapOf<String, List<SourceRule>>()
private var coroutineContext: CoroutineContext? = null
private var coroutineContext: CoroutineContext = EmptyCoroutineContext
@JvmOverloads
fun setContent(content: Any?, baseUrl: String? = null): AnalyzeRule {
@@ -84,8 +86,8 @@ class AnalyzeRule(
return this
}
fun setCoroutineContext(context: CoroutineContext?): AnalyzeRule {
coroutineContext = context
fun setCoroutineContext(context: CoroutineContext): AnalyzeRule {
coroutineContext = context.minusKey(ContinuationInterceptor)
return this
}
@@ -777,9 +779,14 @@ class AnalyzeRule(
} else {
url.toString()
}
return runBlocking {
val analyzeUrl = AnalyzeUrl(
urlStr,
source = source,
ruleData = book,
coroutineContext = coroutineContext
)
return runBlocking(coroutineContext) {
kotlin.runCatching {
val analyzeUrl = AnalyzeUrl(urlStr, source = source, ruleData = book)
analyzeUrl.getStrResponseAwait().body
}.onFailure {
log("ajax(${urlStr}) error\n${it.stackTraceToString()}")
@@ -797,7 +804,7 @@ class AnalyzeRule(
val bookSource = source as? BookSource
val book = book as? Book
if (bookSource == null || book == null) return
runBlocking {
runBlocking(coroutineContext) {
withTimeout(1800000) {
WebBook.preciseSearchAwait(this, bookSource, book.name, book.author)
.getOrThrow().let {
@@ -818,7 +825,7 @@ class AnalyzeRule(
val bookSource = source as? BookSource
val book = book as? Book
if (bookSource == null || book == null) return
runBlocking {
runBlocking(coroutineContext) {
withTimeout(1800000) {
WebBook.getBookInfoAwait(bookSource, book)
}
@@ -832,7 +839,7 @@ class AnalyzeRule(
val bookSource = source as? BookSource
val book = book as? Book
if (bookSource == null || book == null) return
runBlocking {
runBlocking(coroutineContext) {
withTimeout(1800000) {
WebBook.getBookInfoAwait(bookSource, book)
}
@@ -35,6 +35,9 @@ import java.io.InputStream
import java.net.URLEncoder
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.coroutines.ContinuationInterceptor
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.math.max
/**
@@ -55,6 +58,7 @@ class AnalyzeUrl(
private val ruleData: RuleDataInterface? = null,
private val chapter: BookChapter? = null,
private val readTimeout: Long? = null,
private var coroutineContext: CoroutineContext = EmptyCoroutineContext,
headerMapF: Map<String, String>? = null,
) : JsExtensions {
companion object {
@@ -89,6 +93,7 @@ class AnalyzeUrl(
private set
init {
coroutineContext = coroutineContext.minusKey(ContinuationInterceptor)
val urlMatcher = paramPattern.matcher(baseUrl)
if (urlMatcher.find()) baseUrl = baseUrl.substring(0, urlMatcher.start())
(headerMapF ?: source?.getHeaderMap(true))?.let {
@@ -278,7 +283,7 @@ class AnalyzeUrl(
source?.getShareScope()?.let {
scope.prototype = it
}
return RhinoScriptEngine.eval(jsStr, scope)
return RhinoScriptEngine.eval(jsStr, scope, coroutineContext)
}
fun put(key: String, value: String): String {
@@ -476,7 +481,7 @@ class AnalyzeUrl(
sourceRegex: String? = null,
useWebView: Boolean = true,
): StrResponse {
return runBlocking {
return runBlocking(coroutineContext) {
getStrResponseAwait(jsStr, sourceRegex, useWebView)
}
}
@@ -527,7 +532,7 @@ class AnalyzeUrl(
}
fun getResponse(): Response {
return runBlocking {
return runBlocking(coroutineContext) {
getResponseAwait()
}
}
@@ -553,7 +558,7 @@ class AnalyzeUrl(
}
fun getByteArray(): ByteArray {
return runBlocking {
return runBlocking(coroutineContext) {
getByteArrayAwait()
}
}
@@ -569,7 +574,7 @@ class AnalyzeUrl(
}
fun getInputStream(): InputStream {
return runBlocking {
return runBlocking(coroutineContext) {
getInputStreamAwait()
}
}
@@ -63,12 +63,14 @@ object BookChapterList {
var nextUrl = chapterData.second[0]
while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) {
nextUrlList.add(nextUrl)
val res = AnalyzeUrl(
val analyzeUrl = AnalyzeUrl(
mUrl = nextUrl,
source = bookSource,
ruleData = book,
headerMapF = bookSource.getHeaderMap()
).getStrResponseAwait() //控制并发访问
headerMapF = bookSource.getHeaderMap(),
coroutineContext = coroutineContext
)
val res = analyzeUrl.getStrResponseAwait() //控制并发访问
res.body?.let { nextBody ->
chapterData = analyzeChapterList(
book, nextUrl, nextUrl,
@@ -91,12 +93,14 @@ object BookChapterList {
emit(urlStr)
}
}.mapAsync(AppConfig.threadCount) { urlStr ->
val res = AnalyzeUrl(
val analyzeUrl = AnalyzeUrl(
mUrl = urlStr,
source = bookSource,
ruleData = book,
headerMapF = bookSource.getHeaderMap()
).getStrResponseAwait() //控制并发访问
headerMapF = bookSource.getHeaderMap(),
coroutineContext = coroutineContext
)
val res = analyzeUrl.getStrResponseAwait() //控制并发访问
analyzeChapterList(
book, urlStr, res.url,
res.body!!, tocRule, listRule, bookSource, false
@@ -86,12 +86,14 @@ object BookContent {
) break
nextUrlList.add(nextUrl)
coroutineContext.ensureActive()
val res = AnalyzeUrl(
val analyzeUrl = AnalyzeUrl(
mUrl = nextUrl,
source = bookSource,
ruleData = book,
headerMapF = bookSource.getHeaderMap()
).getStrResponseAwait() //控制并发访问
headerMapF = bookSource.getHeaderMap(),
coroutineContext = coroutineContext
)
val res = analyzeUrl.getStrResponseAwait() //控制并发访问
res.body?.let { nextBody ->
contentData = analyzeContent(
book, nextUrl, res.url, nextBody, contentRule,
@@ -112,12 +114,14 @@ object BookContent {
emit(urlStr)
}
}.mapAsync(AppConfig.threadCount) { urlStr ->
val res = AnalyzeUrl(
val analyzeUrl = AnalyzeUrl(
mUrl = urlStr,
source = bookSource,
ruleData = book,
headerMapF = bookSource.getHeaderMap()
).getStrResponseAwait() //控制并发访问
headerMapF = bookSource.getHeaderMap(),
coroutineContext = coroutineContext
)
val res = analyzeUrl.getStrResponseAwait() //控制并发访问
analyzeContent(
book, urlStr, res.url, res.body!!, contentRule,
bookChapter, bookSource, mNextChapterUrl,
@@ -61,6 +61,7 @@ object WebBook {
headerMapF = bookSource.getHeaderMap(true),
source = bookSource,
ruleData = ruleData,
coroutineContext = coroutineContext
)
var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录
@@ -107,7 +108,8 @@ object WebBook {
baseUrl = bookSource.bookSourceUrl,
source = bookSource,
ruleData = ruleData,
headerMapF = bookSource.getHeaderMap(true)
headerMapF = bookSource.getHeaderMap(true),
coroutineContext = coroutineContext
)
var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录
@@ -164,7 +166,8 @@ object WebBook {
baseUrl = bookSource.bookSourceUrl,
source = bookSource,
ruleData = book,
headerMapF = bookSource.getHeaderMap(true)
headerMapF = bookSource.getHeaderMap(true),
coroutineContext = coroutineContext
)
var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录
@@ -244,7 +247,8 @@ object WebBook {
baseUrl = book.bookUrl,
source = bookSource,
ruleData = book,
headerMapF = bookSource.getHeaderMap(true)
headerMapF = bookSource.getHeaderMap(true),
coroutineContext = coroutineContext
)
var res = analyzeUrl.getStrResponseAwait()
//检测书源是否已登录
@@ -317,7 +321,8 @@ object WebBook {
source = bookSource,
ruleData = book,
chapter = bookChapter,
headerMapF = bookSource.getHeaderMap(true)
headerMapF = bookSource.getHeaderMap(true),
coroutineContext = coroutineContext
)
var res = analyzeUrl.getStrResponseAwait(
jsStr = bookSource.getContentRule().webJs,