This commit is contained in:
kunfei 2023-04-21 14:04:59 +08:00
parent 1dbe4b4ec0
commit a4a4de8ef1
13 changed files with 95 additions and 92 deletions

View File

@ -37,7 +37,7 @@ class AndroidJsTest {
queryStringWithSign
""".trimIndent()
Rhino.use {
evaluateString(initStandardObjects(), js, "yy", 1, null)
evaluateString(it, js, "yy", 1, null)
}
@Language("js")
val js1 = """
@ -45,7 +45,7 @@ class AndroidJsTest {
returnData.getErrorMsg()
""".trimIndent()
val result1 = Rhino.use {
evaluateString(initStandardObjects(), js1, "xx", 1, null)
evaluateString(it, js1, "xx", 1, null)
}
Assert.assertEquals(result1, "未知错误,请联系开发者!").let {
@ -59,17 +59,15 @@ class AndroidJsTest {
@Language("js")
val jsMap = "$=result;id=$.id;id"
val result = Rhino.use {
val scope = initStandardObjects()
scope.putBinding("result", map)
evaluateString(scope, jsMap, "xxx", 1, null)
it.putBinding("result", map)
evaluateString(it, jsMap, "xxx", 1, null)
}
Assert.assertEquals("3242532321", result)
@Language("js")
val jsMap1 = """result.get("id")"""
val result1 = Rhino.use {
val scope = initStandardObjects()
scope.putBinding("result", map)
evaluateString(scope, jsMap1, "xxx", 1, null)
it.putBinding("result", map)
evaluateString(it, jsMap1, "xxx", 1, null)
}
Assert.assertEquals("3242532321", result1)
}

View File

@ -10,7 +10,6 @@ import android.os.Build
import com.github.liuyueyi.quick.transfer.ChineseUtils
import com.github.liuyueyi.quick.transfer.constants.TransType
import com.jeremyliao.liveeventbus.LiveEventBus
import com.script.rhino.RhinoScriptEngine
import io.legado.app.base.AppContextWrapper
import io.legado.app.constant.AppConst.channelIdDownload
import io.legado.app.constant.AppConst.channelIdReadAloud
@ -41,7 +40,6 @@ class App : Application() {
override fun onCreate() {
super.onCreate()
RhinoScriptEngine
oldConfig = Configuration(resources.configuration)
CrashHandler(this)
//预下载Cronet so

View File

@ -236,15 +236,19 @@ interface BaseSource : JsExtensions {
bindings["baseUrl"] = getKey()
bindings["cookie"] = CookieStore
bindings["cache"] = CacheManager
// return Rhino.use {
// val scope = initStandardObjects()
// return Rhino.use { scope ->
// scope.putBindings(bindings)
// getShareScope()?.let {
// scope.prototype = it
// }
// evaluate(scope, jsStr)
// eval(scope, jsStr)
// }
return RhinoScriptEngine.eval(jsStr, SimpleBindings(bindings))
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
val scope = RhinoScriptEngine.getRuntimeScope(context)
getShareScope()?.let {
scope.prototype = it
}
return RhinoScriptEngine.eval(jsStr, scope)
}
fun getShareScope(): Scriptable? {

View File

@ -241,9 +241,8 @@ fun Book.getExportFileName(suffix: String): String {
bindings["author"] = getRealAuthor()
return kotlin.runCatching {
Rhino.use {
val scope = initStandardObjects()
scope.putBindings(bindings)
evaluateString(scope, jsStr, "name&author", 1, null)
it.putBindings(bindings)
evaluateString(it, jsStr, "name&author", 1, null)
}.toString() + "." + suffix
}.onFailure {
AppLog.put("导出书名规则错误,使用默认规则\n${it.localizedMessage}", it)

View File

@ -32,7 +32,7 @@ object SharedJsScope {
var scope = scopeMap[key]?.get()
if (scope == null) {
Rhino.use {
scope = initStandardObjects()
scope = it
if (jsLib.isJsonObject()) {
val jsMap: Map<String, String> = GSON.fromJson(
jsLib,

View File

@ -258,6 +258,7 @@ class AnalyzeRule(
} else {
getAnalyzeByJSoup(it).getString(sourceRule.rule)
}
else -> sourceRule.rule
}
}
@ -307,6 +308,7 @@ class AnalyzeRule(
result.toString(),
sourceRule.rule.splitNotBlank("&&")
)
Mode.Js -> evalJS(sourceRule.rule, it)
Mode.Json -> getAnalyzeByJSonPath(it).getObject(sourceRule.rule)
Mode.XPath -> getAnalyzeByXPath(it).getElements(sourceRule.rule)
@ -339,6 +341,7 @@ class AnalyzeRule(
result.toString(),
sourceRule.rule.splitNotBlank("&&")
)
Mode.Js -> evalJS(sourceRule.rule, result)
Mode.Json -> getAnalyzeByJSonPath(it).getList(sourceRule.rule)
Mode.XPath -> getAnalyzeByXPath(it).getElements(sourceRule.rule)
@ -389,7 +392,7 @@ class AnalyzeRule(
if (rule.replaceRegex.isEmpty()) return result
var vResult = result
vResult = if (rule.replaceFirst) {
/* ##match##replace### 获取第一个匹配到的结果并进行替换 */
/* ##match##replace### 获取第一个匹配到的结果并进行替换 */
kotlin.runCatching {
val pattern = Pattern.compile(rule.replaceRegex)
val matcher = pattern.matcher(vResult)
@ -402,7 +405,7 @@ class AnalyzeRule(
rule.replacement
}
} else {
/* ##match##replace 替换*/
/* ##match##replace 替换*/
kotlin.runCatching {
vResult.replace(rule.replaceRegex.toRegex(), rule.replacement)
}.getOrElse {
@ -476,26 +479,32 @@ class AnalyzeRule(
mode = Mode.Default
ruleStr
}
ruleStr.startsWith("@@") -> {
mode = Mode.Default
ruleStr.substring(2)
}
ruleStr.startsWith("@XPath:", true) -> {
mode = Mode.XPath
ruleStr.substring(7)
}
ruleStr.startsWith("@Json:", true) -> {
mode = Mode.Json
ruleStr.substring(6)
}
isJSON || ruleStr.startsWith("$.") || ruleStr.startsWith("$[") -> {
mode = Mode.Json
ruleStr
}
ruleStr.startsWith("/") -> {//XPath特征很明显,无需配置单独的识别标头
mode = Mode.XPath
ruleStr
}
else -> ruleStr
}
//分离put
@ -523,10 +532,12 @@ class AnalyzeRule(
ruleType.add(getRuleType)
ruleParam.add(tmp.substring(6, tmp.lastIndex))
}
tmp.startsWith("{{") -> {
ruleType.add(jsRuleType)
ruleParam.add(tmp.substring(2, tmp.length - 2))
}
else -> {
splitRegex(tmp)
}
@ -592,6 +603,7 @@ class AnalyzeRule(
}
} ?: infoVal.insert(0, ruleParam[index])
}
regType == jsRuleType -> {
if (isRule(ruleParam[index])) {
getString(arrayListOf(SourceRule(ruleParam[index]))).let {
@ -606,13 +618,16 @@ class AnalyzeRule(
0,
String.format("%.0f", jsEval)
)
else -> infoVal.insert(0, jsEval.toString())
}
}
}
regType == getRuleType -> {
infoVal.insert(0, get(ruleParam[index]))
}
else -> infoVal.insert(0, ruleParam[index])
}
}
@ -667,6 +682,7 @@ class AnalyzeRule(
"bookName" -> book?.let {
return it.name
}
"title" -> chapter?.let {
return it.title
}
@ -694,15 +710,19 @@ class AnalyzeRule(
bindings["title"] = chapter?.title
bindings["src"] = content
bindings["nextChapterUrl"] = nextChapterUrl
// return Rhino.use {
// val scope = initStandardObjects()
// return Rhino.use { scope ->
// scope.putBindings(bindings)
// source?.getShareScope()?.let {
// scope.prototype = it
// }
// evaluate(scope, jsStr)
// eval(scope, jsStr)
// }
return RhinoScriptEngine.eval(jsStr, SimpleBindings(bindings))
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
val scope = RhinoScriptEngine.getRuntimeScope(context)
source?.getShareScope()?.let {
scope.prototype = it
}
return RhinoScriptEngine.eval(jsStr, scope)
}
override fun getSource(): BaseSource? {

View File

@ -215,6 +215,7 @@ class AnalyzeUrl(
urlNoQuery = url.substring(0, pos)
}
}
RequestMethod.POST -> body?.let {
if (!it.isJson() && !it.isXml() && headerMap["Content-Type"].isNullOrEmpty()) {
analyzeFields(it)
@ -266,15 +267,19 @@ class AnalyzeUrl(
bindings["book"] = ruleData as? Book
bindings["source"] = source
bindings["result"] = result
// return Rhino.use {
// val scope = initStandardObjects()
// return Rhino.use { scope ->
// scope.putBindings(bindings)
// source?.getShareScope()?.let {
// scope.prototype = it
// }
// evaluate(scope, jsStr)
// eval(scope, jsStr)
// }
return RhinoScriptEngine.eval(jsStr, SimpleBindings(bindings))
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
val scope = RhinoScriptEngine.getRuntimeScope(context)
source?.getShareScope()?.let {
scope.prototype = it
}
return RhinoScriptEngine.eval(jsStr, scope)
}
fun put(key: String, value: String): String {
@ -288,6 +293,7 @@ class AnalyzeUrl(
"bookName" -> (ruleData as? Book)?.let {
return it.name
}
"title" -> chapter?.let {
return it.title
}
@ -353,7 +359,10 @@ class AnalyzeUrl(
}
}
if (waitTime > 0) {
throw ConcurrentException("根据并发率还需等待${waitTime}毫秒才可以访问", waitTime = waitTime)
throw ConcurrentException(
"根据并发率还需等待${waitTime}毫秒才可以访问",
waitTime = waitTime
)
}
return fetchRecord
}
@ -414,6 +423,7 @@ class AnalyzeUrl(
headerMap = headerMap
).getStrResponse()
}
else -> BackstageWebView(
url = url,
tag = source?.getKey(),
@ -439,6 +449,7 @@ class AnalyzeUrl(
postJson(body)
}
}
else -> get(urlNoQuery, fieldMap, true)
}
}.let {
@ -500,6 +511,7 @@ class AnalyzeUrl(
postJson(body)
}
}
else -> get(urlNoQuery, fieldMap, true)
}
}

View File

@ -20,7 +20,7 @@ import io.legado.app.lib.webdav.WebDav
import io.legado.app.lib.webdav.WebDavException
import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.evaluate
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBinding
import io.legado.app.utils.*
import kotlinx.coroutines.runBlocking
@ -272,9 +272,8 @@ object LocalBook {
AppConfig.bookImportFileName + "\nJSON.stringify({author:author,name:name})"
//在脚本中定义如何分解文件名成书名、作者名
val jsonStr = Rhino.use {
val scope = initStandardObjects()
scope.putBinding("src", tempFileName)
evaluate(scope, js)
it.putBinding("src", tempFileName)
eval(it, js)
}.toString()
val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr)
.getOrThrow()

View File

@ -1,15 +1,18 @@
package io.legado.app.rhino
import org.mozilla.javascript.Context
import org.mozilla.javascript.ImporterTopLevel
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.Undefined
import org.mozilla.javascript.Wrapper
object Rhino {
inline fun <T> use(block: Context.() -> T): T {
inline fun <T> use(block: Context.(Scriptable) -> T): T {
return try {
val cx = Context.enter()
block.invoke(cx)
val scope = cx.initStandardObjects(ImporterTopLevel(cx))
block.invoke(cx, scope)
} finally {
Context.exit()
}

View File

@ -7,7 +7,7 @@ import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.ScriptableObject
import java.io.Reader
fun Context.evaluate(
fun Context.eval(
scope: Scriptable,
source: String,
sourceName: String = "<Unknown source>",
@ -19,21 +19,7 @@ fun Context.evaluate(
)
}
fun Context.evaluate(
bindings: Bindings,
source: String,
sourceName: String = "<Unknown source>",
lineno: Int = 1,
securityDomain: Any? = null
): Any? {
val scope = initStandardObjects()
scope.putBindings(bindings)
return Rhino.unwrapReturnValue(
evaluateString(scope, source, sourceName, lineno, securityDomain)
)
}
fun Context.evaluate(
fun Context.eval(
scope: Scriptable,
reader: Reader,
sourceName: String = "<Unknown source>",
@ -45,20 +31,6 @@ fun Context.evaluate(
)
}
fun Context.evaluate(
bindings: Bindings,
reader: Reader,
sourceName: String = "<Unknown source>",
lineno: Int = 1,
securityDomain: Any? = null
): Any? {
val scope = initStandardObjects()
scope.putBindings(bindings)
return Rhino.unwrapReturnValue(
evaluateReader(scope, reader, sourceName, lineno, securityDomain)
)
}
fun Scriptable.putBinding(key: String, value: Any?) {
val wrappedOut = Context.javaToJS(value, this)
ScriptableObject.putProperty(this, key, wrappedOut)

View File

@ -3,7 +3,8 @@ package io.legado.app.utils
import io.legado.app.constant.AppPattern.EXP_PATTERN
import io.legado.app.rhino.Bindings
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.evaluate
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBindings
object JsUtils {
@ -14,9 +15,10 @@ object JsUtils {
val sb = StringBuffer()
val expMatcher = EXP_PATTERN.matcher(js)
while (expMatcher.find()) {
val result = expMatcher.group(1)?.let {
val result = expMatcher.group(1)?.let { js1 ->
Rhino.use {
evaluate(bindings, it)
it.putBindings(bindings)
eval(it, js1)
}
} ?: ""
if (result is String) {
@ -31,7 +33,8 @@ object JsUtils {
return sb.toString()
}
return Rhino.use {
evaluate(bindings, js)
it.putBindings(bindings)
eval(it, js)
}.toString()
}

View File

@ -4,9 +4,9 @@ import androidx.core.os.postDelayed
import io.legado.app.exception.RegexTimeoutException
import io.legado.app.help.CrashHandler
import io.legado.app.help.coroutine.Coroutine
import io.legado.app.rhino.Bindings
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.evaluate
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBinding
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.suspendCancellableCoroutine
import splitties.init.appCtx
@ -31,10 +31,9 @@ fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): Stri
val stringBuffer = StringBuffer()
while (matcher.find()) {
if (isJs) {
val bindings = Bindings()
bindings["result"] = matcher.group()
val jsResult = Rhino.use {
evaluate(bindings, replacement1)
it.putBinding("result", matcher.group())
eval(it, replacement1)
}.toString()
matcher.appendReplacement(stringBuffer, jsResult)
} else {

View File

@ -3,7 +3,7 @@ package io.legado.app
import com.script.SimpleBindings
import io.legado.app.data.entities.BookChapter
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.evaluate
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBinding
import org.intellij.lang.annotations.Language
import org.junit.Assert
@ -42,9 +42,8 @@ class JsTest {
@Language("js")
val jsMap1 = """result.get("id")"""
val result1 = Rhino.use {
val scope = initStandardObjects()
scope.putBinding("result", map)
evaluateString(scope, jsMap1, "xxx", 1, null)
it.putBinding("result", map)
evaluateString(it, jsMap1, "xxx", 1, null)
}
Assert.assertEquals("3242532321", result1)
}
@ -52,9 +51,8 @@ class JsTest {
@Test
fun testFor() {
val scope = Rhino.use {
val scope = initStandardObjects()
evaluateString(scope, printJs, "print", 1, null)
scope
evaluateString(it, printJs, "print", 1, null)
it
}
@Language("js")
@ -77,7 +75,8 @@ class JsTest {
result
""".trimIndent()
val result = Rhino.use {
evaluateString(scope, jsFor, "jsFor", 1, null)
it.prototype = scope
evaluateString(it, jsFor, "jsFor", 1, null)
}
Assert.assertEquals("12012", result)
}
@ -85,7 +84,7 @@ class JsTest {
@Test
fun testReturnNull() {
val result = Rhino.use {
evaluate(initStandardObjects(), "null")
eval(it, "null")
}
Assert.assertEquals(null, result)
}
@ -103,9 +102,8 @@ class JsTest {
.replace(/\:/g,"")
""".trimIndent()
val result = Rhino.use {
val scope = initStandardObjects()
scope.putBinding("result", ",.!?…;:")
evaluate(scope, js)
it.putBinding("result", ",.!?…;:")
eval(it, js)
}
Assert.assertEquals(result, ",。!?……;:")
}
@ -119,9 +117,8 @@ class JsTest {
@Language("js")
val js = "chapter.title"
val result = Rhino.use {
val scope = initStandardObjects()
scope.putBinding("chapter", chapter)
evaluate(scope, js)
it.putBinding("chapter", chapter)
eval(it, js)
}
Assert.assertEquals(result, "xxxyyy")
}
@ -137,9 +134,8 @@ class JsTest {
result
""".trimIndent()
val result = Rhino.use {
val scope = initStandardObjects()
scope.putBinding("list", list)
evaluate(scope, js)
it.putBinding("list", list)
eval(it, js)
}
Assert.assertEquals(result, 6.0)
}