|
@@ -2,10 +2,12 @@ package io.legado.app.model.analyzeRule
|
|
|
|
|
|
|
|
import android.text.TextUtils
|
|
import android.text.TextUtils
|
|
|
import androidx.annotation.Keep
|
|
import androidx.annotation.Keep
|
|
|
|
|
+import com.google.gson.internal.LinkedTreeMap
|
|
|
import com.script.CompiledScript
|
|
import com.script.CompiledScript
|
|
|
import com.script.buildScriptBindings
|
|
import com.script.buildScriptBindings
|
|
|
import com.script.rhino.RhinoScriptEngine
|
|
import com.script.rhino.RhinoScriptEngine
|
|
|
import io.legado.app.constant.AppPattern.JS_PATTERN
|
|
import io.legado.app.constant.AppPattern.JS_PATTERN
|
|
|
|
|
+import io.legado.app.constant.AppPattern.WebJS_PATTERN
|
|
|
import io.legado.app.data.entities.BaseBook
|
|
import io.legado.app.data.entities.BaseBook
|
|
|
import io.legado.app.data.entities.BaseSource
|
|
import io.legado.app.data.entities.BaseSource
|
|
|
import io.legado.app.data.entities.Book
|
|
import io.legado.app.data.entities.Book
|
|
@@ -15,6 +17,7 @@ import io.legado.app.data.entities.RssArticle
|
|
|
import io.legado.app.exception.NoStackTraceException
|
|
import io.legado.app.exception.NoStackTraceException
|
|
|
import io.legado.app.help.CacheManager
|
|
import io.legado.app.help.CacheManager
|
|
|
import io.legado.app.help.JsExtensions
|
|
import io.legado.app.help.JsExtensions
|
|
|
|
|
+import io.legado.app.help.http.BackstageWebView
|
|
|
import io.legado.app.help.http.CookieStore
|
|
import io.legado.app.help.http.CookieStore
|
|
|
import io.legado.app.help.source.getShareScope
|
|
import io.legado.app.help.source.getShareScope
|
|
|
import io.legado.app.model.Debug
|
|
import io.legado.app.model.Debug
|
|
@@ -22,10 +25,12 @@ import io.legado.app.model.webBook.WebBook
|
|
|
import io.legado.app.utils.GSON
|
|
import io.legado.app.utils.GSON
|
|
|
import io.legado.app.utils.GSONStrict
|
|
import io.legado.app.utils.GSONStrict
|
|
|
import io.legado.app.utils.NetworkUtils
|
|
import io.legado.app.utils.NetworkUtils
|
|
|
|
|
+import io.legado.app.utils.fromJsonArray
|
|
|
import io.legado.app.utils.fromJsonObject
|
|
import io.legado.app.utils.fromJsonObject
|
|
|
import io.legado.app.utils.getOrPutLimit
|
|
import io.legado.app.utils.getOrPutLimit
|
|
|
import io.legado.app.utils.isDataUrl
|
|
import io.legado.app.utils.isDataUrl
|
|
|
import io.legado.app.utils.isJson
|
|
import io.legado.app.utils.isJson
|
|
|
|
|
+import io.legado.app.utils.isMainThread
|
|
|
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
|
|
@@ -163,6 +168,23 @@ class AnalyzeRule(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private fun getWebJsResult(jsStr: String, result: Any): String {
|
|
|
|
|
+ check(!isMainThread) { "webJs must be called on a background thread" }
|
|
|
|
|
+ return runBlocking {
|
|
|
|
|
+ BackstageWebView(
|
|
|
|
|
+ url = baseUrl,
|
|
|
|
|
+ html = content.toString(),
|
|
|
|
|
+ javaScript = jsStr,
|
|
|
|
|
+ headerMap = getSource()?.getHeaderMap(true),
|
|
|
|
|
+ tag = getSource()?.getKey(),
|
|
|
|
|
+ cacheFirst = true,
|
|
|
|
|
+ timeout = 10000,
|
|
|
|
|
+ result = GSON.toJson(result),
|
|
|
|
|
+ isRule = true,
|
|
|
|
|
+ ).getStrResponse().body.orEmpty()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 获取文本列表
|
|
* 获取文本列表
|
|
|
*/
|
|
*/
|
|
@@ -203,6 +225,8 @@ class AnalyzeRule(
|
|
|
result = replaceRegex(result.toString(), sourceRule)
|
|
result = replaceRegex(result.toString(), sourceRule)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ } else if (result is LinkedTreeMap<*, *>) {
|
|
|
|
|
+ result = result[ruleList.first().rule]
|
|
|
} else {
|
|
} else {
|
|
|
for (sourceRule in ruleList) {
|
|
for (sourceRule in ruleList) {
|
|
|
putRule(sourceRule.putMap)
|
|
putRule(sourceRule.putMap)
|
|
@@ -211,6 +235,9 @@ class AnalyzeRule(
|
|
|
val rule = sourceRule.rule
|
|
val rule = sourceRule.rule
|
|
|
if (rule.isNotEmpty()) {
|
|
if (rule.isNotEmpty()) {
|
|
|
result = when (sourceRule.mode) {
|
|
result = when (sourceRule.mode) {
|
|
|
|
|
+ Mode.WebJs -> getWebJsResult(rule, result).let {
|
|
|
|
|
+ GSON.fromJsonArray<String>(it).getOrNull() ?: it
|
|
|
|
|
+ }
|
|
|
Mode.Js -> evalJS(rule, result)
|
|
Mode.Js -> evalJS(rule, result)
|
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getStringList(rule)
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getStringList(rule)
|
|
|
Mode.XPath -> getAnalyzeByXPath(result).getStringList(rule)
|
|
Mode.XPath -> getAnalyzeByXPath(result).getStringList(rule)
|
|
@@ -290,6 +317,8 @@ class AnalyzeRule(
|
|
|
}?.let {
|
|
}?.let {
|
|
|
replaceRegex(it, sourceRule)
|
|
replaceRegex(it, sourceRule)
|
|
|
}
|
|
}
|
|
|
|
|
+ } else if (result is LinkedTreeMap<*, *>) {
|
|
|
|
|
+ result = result[ruleList.first().rule]?.toString()
|
|
|
} else {
|
|
} else {
|
|
|
for (sourceRule in ruleList) {
|
|
for (sourceRule in ruleList) {
|
|
|
putRule(sourceRule.putMap)
|
|
putRule(sourceRule.putMap)
|
|
@@ -298,6 +327,7 @@ class AnalyzeRule(
|
|
|
val rule = sourceRule.rule
|
|
val rule = sourceRule.rule
|
|
|
if (rule.isNotBlank() || sourceRule.replaceRegex.isEmpty()) {
|
|
if (rule.isNotBlank() || sourceRule.replaceRegex.isEmpty()) {
|
|
|
result = when (sourceRule.mode) {
|
|
result = when (sourceRule.mode) {
|
|
|
|
|
+ Mode.WebJs -> getWebJsResult(rule, result)
|
|
|
Mode.Js -> evalJS(rule, result)
|
|
Mode.Js -> evalJS(rule, result)
|
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getString(rule)
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getString(rule)
|
|
|
Mode.XPath -> getAnalyzeByXPath(result).getString(rule)
|
|
Mode.XPath -> getAnalyzeByXPath(result).getString(rule)
|
|
@@ -354,6 +384,10 @@ class AnalyzeRule(
|
|
|
rule.splitNotBlank("&&")
|
|
rule.splitNotBlank("&&")
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ Mode.WebJs -> GSON.fromJsonObject<Map<String, Any?>>(
|
|
|
|
|
+ getWebJsResult(rule, result)
|
|
|
|
|
+ ).getOrNull()
|
|
|
|
|
+
|
|
|
Mode.Js -> evalJS(rule, result)
|
|
Mode.Js -> evalJS(rule, result)
|
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getObject(rule)
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getObject(rule)
|
|
|
Mode.XPath -> getAnalyzeByXPath(result).getElements(rule)
|
|
Mode.XPath -> getAnalyzeByXPath(result).getElements(rule)
|
|
@@ -387,6 +421,10 @@ class AnalyzeRule(
|
|
|
rule.splitNotBlank("&&")
|
|
rule.splitNotBlank("&&")
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ Mode.WebJs -> GSON.fromJsonArray<Map<String, Any?>>(
|
|
|
|
|
+ getWebJsResult(rule, result)
|
|
|
|
|
+ ).getOrNull()
|
|
|
|
|
+
|
|
|
Mode.Js -> evalJS(rule, result)
|
|
Mode.Js -> evalJS(rule, result)
|
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getList(rule)
|
|
Mode.Json -> getAnalyzeByJSonPath(result).getList(rule)
|
|
|
Mode.XPath -> getAnalyzeByXPath(result).getElements(rule)
|
|
Mode.XPath -> getAnalyzeByXPath(result).getElements(rule)
|
|
@@ -515,6 +553,18 @@ class AnalyzeRule(
|
|
|
start = jsMatcher.end()
|
|
start = jsMatcher.end()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ val webJsMatcher = WebJS_PATTERN.matcher(ruleStr)
|
|
|
|
|
+ while (webJsMatcher.find()) {
|
|
|
|
|
+ if (webJsMatcher.start() > start) {
|
|
|
|
|
+ tmp = ruleStr.substring(start, webJsMatcher.start()).trim { it <= ' ' }
|
|
|
|
|
+ if (tmp.isNotEmpty()) {
|
|
|
|
|
+ ruleList.add(SourceRule(tmp, mMode))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ruleList.add(SourceRule(webJsMatcher.group(1) ?: "", Mode.WebJs))
|
|
|
|
|
+ start = webJsMatcher.end()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (ruleStr.length > start) {
|
|
if (ruleStr.length > start) {
|
|
|
tmp = ruleStr.substring(start).trim { it <= ' ' }
|
|
tmp = ruleStr.substring(start).trim { it <= ' ' }
|
|
|
if (tmp.isNotEmpty()) {
|
|
if (tmp.isNotEmpty()) {
|
|
@@ -738,7 +788,7 @@ class AnalyzeRule(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
enum class Mode {
|
|
enum class Mode {
|
|
|
- XPath, Json, Default, Js, Regex
|
|
|
|
|
|
|
+ XPath, Json, Default, Js, Regex, WebJs
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -826,6 +876,10 @@ class AnalyzeRule(
|
|
|
* js实现跨域访问,不能删
|
|
* js实现跨域访问,不能删
|
|
|
*/
|
|
*/
|
|
|
override fun ajax(url: Any): String? {
|
|
override fun ajax(url: Any): String? {
|
|
|
|
|
+ return ajax(url, null)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun ajax(url: Any, callTimeout: Long?): String? {
|
|
|
val urlStr = if (url is List<*>) {
|
|
val urlStr = if (url is List<*>) {
|
|
|
url.firstOrNull().toString()
|
|
url.firstOrNull().toString()
|
|
|
} else {
|
|
} else {
|
|
@@ -835,6 +889,7 @@ class AnalyzeRule(
|
|
|
urlStr,
|
|
urlStr,
|
|
|
source = source,
|
|
source = source,
|
|
|
ruleData = book,
|
|
ruleData = book,
|
|
|
|
|
+ callTimeout = callTimeout,
|
|
|
coroutineContext = coroutineContext
|
|
coroutineContext = coroutineContext
|
|
|
)
|
|
)
|
|
|
return kotlin.runCatching {
|
|
return kotlin.runCatching {
|