mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
优化
This commit is contained in:
parent
2cda94547e
commit
f3be1c36b8
@ -21,6 +21,7 @@ import io.legado.app.utils.isJson
|
|||||||
import io.legado.app.utils.printOnDebug
|
import io.legado.app.utils.printOnDebug
|
||||||
import io.legado.app.utils.splitNotBlank
|
import io.legado.app.utils.splitNotBlank
|
||||||
import io.legado.app.utils.stackTraceStr
|
import io.legado.app.utils.stackTraceStr
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import org.apache.commons.text.StringEscapeUtils
|
import org.apache.commons.text.StringEscapeUtils
|
||||||
@ -31,6 +32,7 @@ import java.util.regex.Pattern
|
|||||||
import kotlin.collections.component1
|
import kotlin.collections.component1
|
||||||
import kotlin.collections.component2
|
import kotlin.collections.component2
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析规则获取结果
|
* 解析规则获取结果
|
||||||
@ -65,6 +67,8 @@ class AnalyzeRule(
|
|||||||
|
|
||||||
private val stringRuleCache = hashMapOf<String, List<SourceRule>>()
|
private val stringRuleCache = hashMapOf<String, List<SourceRule>>()
|
||||||
|
|
||||||
|
private var coroutineContext: CoroutineContext? = null
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun setContent(content: Any?, baseUrl: String? = null): AnalyzeRule {
|
fun setContent(content: Any?, baseUrl: String? = null): AnalyzeRule {
|
||||||
if (content == null) throw AssertionError("内容不可空(Content cannot be null)")
|
if (content == null) throw AssertionError("内容不可空(Content cannot be null)")
|
||||||
@ -80,6 +84,11 @@ class AnalyzeRule(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setCoroutineContext(context: CoroutineContext?): AnalyzeRule {
|
||||||
|
coroutineContext = context
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun setBaseUrl(baseUrl: String?): AnalyzeRule {
|
fun setBaseUrl(baseUrl: String?): AnalyzeRule {
|
||||||
baseUrl?.let {
|
baseUrl?.let {
|
||||||
this.baseUrl = baseUrl
|
this.baseUrl = baseUrl
|
||||||
@ -752,7 +761,7 @@ class AnalyzeRule(
|
|||||||
source?.getShareScope()?.let {
|
source?.getShareScope()?.let {
|
||||||
scope.prototype = it
|
scope.prototype = it
|
||||||
}
|
}
|
||||||
return RhinoScriptEngine.eval(jsStr, scope)
|
return RhinoScriptEngine.eval(jsStr, scope, coroutineContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSource(): BaseSource? {
|
override fun getSource(): BaseSource? {
|
||||||
|
@ -168,6 +168,7 @@ object BookChapterList {
|
|||||||
val analyzeRule = AnalyzeRule(book, bookSource)
|
val analyzeRule = AnalyzeRule(book, bookSource)
|
||||||
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
||||||
analyzeRule.setRedirectUrl(redirectUrl)
|
analyzeRule.setRedirectUrl(redirectUrl)
|
||||||
|
analyzeRule.setCoroutineContext(coroutineContext)
|
||||||
//获取目录列表
|
//获取目录列表
|
||||||
val chapterList = arrayListOf<BookChapter>()
|
val chapterList = arrayListOf<BookChapter>()
|
||||||
Debug.log(bookSource.bookSourceUrl, "┌获取目录列表", log)
|
Debug.log(bookSource.bookSourceUrl, "┌获取目录列表", log)
|
||||||
|
@ -57,6 +57,7 @@ object BookContent {
|
|||||||
val analyzeRule = AnalyzeRule(book, bookSource)
|
val analyzeRule = AnalyzeRule(book, bookSource)
|
||||||
analyzeRule.setContent(body, baseUrl)
|
analyzeRule.setContent(body, baseUrl)
|
||||||
analyzeRule.setRedirectUrl(redirectUrl)
|
analyzeRule.setRedirectUrl(redirectUrl)
|
||||||
|
analyzeRule.setCoroutineContext(coroutineContext)
|
||||||
analyzeRule.chapter = bookChapter
|
analyzeRule.chapter = bookChapter
|
||||||
analyzeRule.nextChapterUrl = mNextChapterUrl
|
analyzeRule.nextChapterUrl = mNextChapterUrl
|
||||||
coroutineContext.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
@ -150,7 +151,7 @@ object BookContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
private fun analyzeContent(
|
private suspend fun analyzeContent(
|
||||||
book: Book,
|
book: Book,
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
redirectUrl: String,
|
redirectUrl: String,
|
||||||
@ -164,6 +165,7 @@ object BookContent {
|
|||||||
): Pair<String, List<String>> {
|
): Pair<String, List<String>> {
|
||||||
val analyzeRule = AnalyzeRule(book, bookSource)
|
val analyzeRule = AnalyzeRule(book, bookSource)
|
||||||
analyzeRule.setContent(body, baseUrl)
|
analyzeRule.setContent(body, baseUrl)
|
||||||
|
analyzeRule.setCoroutineContext(coroutineContext)
|
||||||
val rUrl = analyzeRule.setRedirectUrl(redirectUrl)
|
val rUrl = analyzeRule.setRedirectUrl(redirectUrl)
|
||||||
analyzeRule.nextChapterUrl = nextChapterUrl
|
analyzeRule.nextChapterUrl = nextChapterUrl
|
||||||
val nextUrlList = arrayListOf<String>()
|
val nextUrlList = arrayListOf<String>()
|
||||||
|
@ -40,6 +40,7 @@ object BookInfo {
|
|||||||
val analyzeRule = AnalyzeRule(book, bookSource)
|
val analyzeRule = AnalyzeRule(book, bookSource)
|
||||||
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
||||||
analyzeRule.setRedirectUrl(redirectUrl)
|
analyzeRule.setRedirectUrl(redirectUrl)
|
||||||
|
analyzeRule.setCoroutineContext(coroutineContext)
|
||||||
analyzeBookInfo(book, body, analyzeRule, bookSource, baseUrl, redirectUrl, canReName)
|
analyzeBookInfo(book, body, analyzeRule, bookSource, baseUrl, redirectUrl, canReName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ object BookList {
|
|||||||
val analyzeRule = AnalyzeRule(ruleData, bookSource)
|
val analyzeRule = AnalyzeRule(ruleData, bookSource)
|
||||||
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
analyzeRule.setContent(body).setBaseUrl(baseUrl)
|
||||||
analyzeRule.setRedirectUrl(baseUrl)
|
analyzeRule.setRedirectUrl(baseUrl)
|
||||||
|
analyzeRule.setCoroutineContext(coroutineContext)
|
||||||
if (isSearch) bookSource.bookUrlPattern?.let {
|
if (isSearch) bookSource.bookUrlPattern?.let {
|
||||||
coroutineContext.ensureActive()
|
coroutineContext.ensureActive()
|
||||||
if (baseUrl.matches(it.toRegex())) {
|
if (baseUrl.matches(it.toRegex())) {
|
||||||
|
@ -18,6 +18,7 @@ import kotlinx.coroutines.CoroutineStart
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
object WebBook {
|
object WebBook {
|
||||||
@ -196,12 +197,14 @@ object WebBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun runPreUpdateJs(bookSource: BookSource, book: Book): Result<Boolean> {
|
suspend fun runPreUpdateJs(bookSource: BookSource, book: Book): Result<Boolean> {
|
||||||
return kotlin.runCatching {
|
return kotlin.runCatching {
|
||||||
val preUpdateJs = bookSource.ruleToc?.preUpdateJs
|
val preUpdateJs = bookSource.ruleToc?.preUpdateJs
|
||||||
if (!preUpdateJs.isNullOrBlank()) {
|
if (!preUpdateJs.isNullOrBlank()) {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
AnalyzeRule(book, bookSource).evalJS(preUpdateJs)
|
AnalyzeRule(book, bookSource)
|
||||||
|
.setCoroutineContext(coroutineContext)
|
||||||
|
.evalJS(preUpdateJs)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
AppLog.put("执行preUpdateJs规则失败 书源:${bookSource.bookSourceName}", it)
|
AppLog.put("执行preUpdateJs规则失败 书源:${bookSource.bookSourceName}", it)
|
||||||
throw it
|
throw it
|
||||||
|
@ -6,6 +6,7 @@ package com.script
|
|||||||
import org.mozilla.javascript.Scriptable
|
import org.mozilla.javascript.Scriptable
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
import java.io.StringReader
|
import java.io.StringReader
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
abstract class AbstractScriptEngine(val bindings: Bindings? = null) : ScriptEngine {
|
abstract class AbstractScriptEngine(val bindings: Bindings? = null) : ScriptEngine {
|
||||||
|
|
||||||
@ -64,6 +65,10 @@ abstract class AbstractScriptEngine(val bindings: Bindings? = null) : ScriptEngi
|
|||||||
return this.eval(reader, getRuntimeScope(context))
|
return this.eval(reader, getRuntimeScope(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun eval(script: String, scope: Scriptable, coroutineContext: CoroutineContext?): Any? {
|
||||||
|
return this.eval(StringReader(script), scope, coroutineContext)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
override fun eval(reader: Reader, bindings: Bindings): Any? {
|
override fun eval(reader: Reader, bindings: Bindings): Any? {
|
||||||
return this.eval(reader, getScriptContext(bindings))
|
return this.eval(reader, getScriptContext(bindings))
|
||||||
|
@ -5,6 +5,7 @@ package com.script
|
|||||||
|
|
||||||
import org.mozilla.javascript.Scriptable
|
import org.mozilla.javascript.Scriptable
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
interface ScriptEngine {
|
interface ScriptEngine {
|
||||||
var context: ScriptContext
|
var context: ScriptContext
|
||||||
@ -14,14 +15,20 @@ interface ScriptEngine {
|
|||||||
@Throws(ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
fun eval(reader: Reader, scope: Scriptable): Any?
|
fun eval(reader: Reader, scope: Scriptable): Any?
|
||||||
|
|
||||||
|
@Throws(ScriptException::class)
|
||||||
|
fun eval(reader: Reader, scope: Scriptable, coroutineContext: CoroutineContext?): Any?
|
||||||
|
|
||||||
@Throws(ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
suspend fun evalSuspend(reader: Reader, scope: Scriptable): Any?
|
suspend fun evalSuspend(reader: Reader, scope: Scriptable): Any?
|
||||||
|
|
||||||
|
@Throws(ScriptException::class)
|
||||||
|
fun eval(script: String, scope: Scriptable): Any?
|
||||||
|
|
||||||
@Throws(ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
suspend fun evalSuspend(script: String, scope: Scriptable): Any?
|
suspend fun evalSuspend(script: String, scope: Scriptable): Any?
|
||||||
|
|
||||||
@Throws(ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
fun eval(script: String, scope: Scriptable): Any?
|
fun eval(script: String, scope: Scriptable, coroutineContext: CoroutineContext?): Any?
|
||||||
|
|
||||||
@Throws(ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
fun eval(reader: Reader): Any?
|
fun eval(reader: Reader): Any?
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.script.rhino
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.coroutines.ensureActive
|
||||||
|
import org.mozilla.javascript.Context
|
||||||
|
import org.mozilla.javascript.ContextFactory
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class RhinoContext(factory: ContextFactory) : Context(factory) {
|
||||||
|
|
||||||
|
var coroutineContext: CoroutineContext? = null
|
||||||
|
|
||||||
|
@Throws(RhinoInterruptError::class)
|
||||||
|
fun ensureActive() {
|
||||||
|
try {
|
||||||
|
coroutineContext?.ensureActive()
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw RhinoInterruptError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
package com.script.rhino
|
||||||
|
|
||||||
|
class RhinoInterruptError(override val cause: Throwable) : Error()
|
@ -35,6 +35,7 @@ import java.io.StringReader
|
|||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.security.*
|
import java.security.*
|
||||||
import kotlin.coroutines.Continuation
|
import kotlin.coroutines.Continuation
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,6 +85,38 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
|
|||||||
return unwrapReturnValue(ret)
|
return unwrapReturnValue(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun eval(
|
||||||
|
reader: Reader,
|
||||||
|
scope: Scriptable,
|
||||||
|
coroutineContext: CoroutineContext?
|
||||||
|
): Any? {
|
||||||
|
val cx = Context.enter()
|
||||||
|
if (cx is RhinoContext) {
|
||||||
|
cx.coroutineContext = coroutineContext
|
||||||
|
}
|
||||||
|
val ret: Any?
|
||||||
|
try {
|
||||||
|
var filename = this["javax.script.filename"] as? String
|
||||||
|
filename = filename ?: "<Unknown source>"
|
||||||
|
ret = cx.evaluateReader(scope, reader, filename, 1, null)
|
||||||
|
} catch (re: RhinoException) {
|
||||||
|
val line = if (re.lineNumber() == 0) -1 else re.lineNumber()
|
||||||
|
val msg: String = if (re is JavaScriptException) {
|
||||||
|
re.value.toString()
|
||||||
|
} else {
|
||||||
|
re.toString()
|
||||||
|
}
|
||||||
|
val se = ScriptException(msg, re.sourceName(), line)
|
||||||
|
se.initCause(re)
|
||||||
|
throw se
|
||||||
|
} catch (var14: IOException) {
|
||||||
|
throw ScriptException(var14)
|
||||||
|
} finally {
|
||||||
|
Context.exit()
|
||||||
|
}
|
||||||
|
return unwrapReturnValue(ret)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(ContinuationPending::class)
|
@Throws(ContinuationPending::class)
|
||||||
override suspend fun evalSuspend(reader: Reader, scope: Scriptable): Any? {
|
override suspend fun evalSuspend(reader: Reader, scope: Scriptable): Any? {
|
||||||
val cx = Context.enter()
|
val cx = Context.enter()
|
||||||
@ -259,11 +292,12 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
|
|||||||
ContextFactory.initGlobal(object : ContextFactory() {
|
ContextFactory.initGlobal(object : ContextFactory() {
|
||||||
|
|
||||||
override fun makeContext(): Context {
|
override fun makeContext(): Context {
|
||||||
val cx = super.makeContext()
|
val cx = RhinoContext(this)
|
||||||
cx.languageVersion = 200
|
cx.languageVersion = 200
|
||||||
cx.optimizationLevel = -1
|
cx.optimizationLevel = -1
|
||||||
cx.setClassShutter(RhinoClassShutter)
|
cx.setClassShutter(RhinoClassShutter)
|
||||||
cx.wrapFactory = RhinoWrapFactory
|
cx.wrapFactory = RhinoWrapFactory
|
||||||
|
cx.instructionObserverThreshold = 10000
|
||||||
return cx
|
return cx
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +309,12 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun observeInstructionCount(cx: Context, instructionCount: Int) {
|
||||||
|
if (cx is RhinoContext) {
|
||||||
|
cx.ensureActive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun doTopCall(
|
override fun doTopCall(
|
||||||
callable: Callable,
|
callable: Callable,
|
||||||
cx: Context,
|
cx: Context,
|
||||||
@ -308,7 +348,11 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
|
|||||||
thisObj: Scriptable?,
|
thisObj: Scriptable?,
|
||||||
args: Array<Any>
|
args: Array<Any>
|
||||||
): Any? {
|
): Any? {
|
||||||
return super.doTopCall(callable, cx, scope, thisObj, args)
|
try {
|
||||||
|
return super.doTopCall(callable, cx, scope, thisObj, args)
|
||||||
|
} catch (e: RhinoInterruptError) {
|
||||||
|
throw e.cause
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user