This commit is contained in:
kunfei
2023-07-29 00:25:04 +08:00
parent 88a6d6d7be
commit c9b96f0fa7
7 changed files with 88 additions and 65 deletions

View File

@@ -1,19 +0,0 @@
package io.legado.app.help
import com.script.SimpleBindings
import com.script.rhino.RhinoScriptEngine
import io.legado.app.data.entities.BaseSource
object JsEngine : JsExtensions {
override fun getSource(): BaseSource? {
return null
}
fun eval(js: String): Any? {
val bindings = SimpleBindings()
bindings["java"] = this
return RhinoScriptEngine.eval(js, bindings)
}
}

View File

@@ -539,9 +539,9 @@ interface JsExtensions : JsEncodeUtils {
/**
* 删除本地文件
*/
fun deleteFile(path: String) {
fun deleteFile(path: String): Boolean {
val file = getFile(path)
FileUtils.delete(file, true)
return FileUtils.delete(file, true)
}
/**
@@ -825,6 +825,15 @@ interface JsExtensions : JsEncodeUtils {
return s
}
fun toURL(urlStr: String): JsURL {
return JsURL(urlStr)
}
fun toURL(url: String, baseUrl: String? = null): JsURL {
return JsURL(url, baseUrl)
}
/**
* 弹窗提示
*/

View File

@@ -1,40 +0,0 @@
@file:Suppress("unused")
package io.legado.app.rhino
import com.script.Bindings
import org.mozilla.javascript.Context
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.ScriptableObject
import java.io.Reader
fun Context.eval(
scope: Scriptable,
source: String,
sourceName: String = "<Unknown source>",
lineno: Int = 1,
securityDomain: Any? = null
): Any? {
return evaluateString(scope, source, sourceName, lineno, securityDomain)
}
fun Context.eval(
scope: Scriptable,
reader: Reader,
sourceName: String = "<Unknown source>",
lineno: Int = 1,
securityDomain: Any? = null
): Any? {
return evaluateReader(scope, reader, sourceName, lineno, securityDomain)
}
fun Scriptable.putBinding(key: String, value: Any?) {
val wrappedOut = Context.javaToJS(value, this)
ScriptableObject.putProperty(this, key, wrappedOut)
}
fun Scriptable.putBindings(bindings: Bindings) {
bindings.forEach { (t, u) ->
putBinding(t, u)
}
}

View File

@@ -10,18 +10,23 @@ import android.view.*
import android.webkit.*
import androidx.activity.viewModels
import androidx.core.view.size
import com.script.rhino.RhinoScriptEngine
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.imagePathKey
import io.legado.app.data.entities.BaseSource
import io.legado.app.databinding.ActivityRssReadBinding
import io.legado.app.help.JsExtensions
import io.legado.app.help.config.AppConfig
import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.theme.accentColor
import io.legado.app.lib.theme.primaryTextColor
import io.legado.app.model.Download
import io.legado.app.ui.association.AddToBookshelfDialog
import io.legado.app.ui.association.OnLineImportActivity
import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.file.HandleFileContract
import io.legado.app.ui.login.SourceLoginActivity
import io.legado.app.utils.*
@@ -39,6 +44,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
override val binding by viewBinding(ActivityRssReadBinding::inflate)
override val viewModel by viewModels<ReadRssViewModel>()
private var starMenuItem: MenuItem? = null
private var ttsMenuItem: MenuItem? = null
private var customWebViewCallback: WebChromeClient.CustomViewCallback? = null
@@ -48,6 +54,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
viewModel.saveImage(it.value, uri)
}
}
private val rssJsExtensions by lazy { RssJsExtensions() }
override fun onActivityCreated(savedInstanceState: Bundle?) {
viewModel.upStarMenuData.observe(this) { upStarMenu() }
@@ -401,9 +408,14 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
val source = viewModel.rssSource
val js = source?.shouldOverrideUrlLoading
if (!js.isNullOrBlank()) {
val result = source.evalJS(js) {
put("url", url.toString())
}.toString()
val result = RhinoScriptEngine.runCatching {
eval(js) {
put("java", rssJsExtensions)
put("url", url.toString())
}.toString()
}.onFailure {
it.printOnDebug()
}.getOrNull()
if (result.isTrue()) {
return true
}
@@ -440,4 +452,23 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
}
@Suppress("unused")
private inner class RssJsExtensions : JsExtensions {
override fun getSource(): BaseSource? {
return viewModel.rssSource
}
fun searchBook(key: String) {
launch {
SearchActivity.start(this@ReadRssActivity, key)
}
}
fun addBook(bookUrl: String) {
showDialogFragment(AddToBookshelfDialog(bookUrl))
}
}
}

View File

@@ -10,10 +10,12 @@ import androidx.lifecycle.viewModelScope
import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppConst
import io.legado.app.data.appDb
import io.legado.app.data.entities.BaseSource
import io.legado.app.data.entities.RssArticle
import io.legado.app.data.entities.RssSource
import io.legado.app.data.entities.RssStar
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.JsExtensions
import io.legado.app.help.TTS
import io.legado.app.help.http.newCallResponseBody
import io.legado.app.help.http.okHttpClient
@@ -26,7 +28,7 @@ import splitties.init.appCtx
import java.util.Date
class ReadRssViewModel(application: Application) : BaseViewModel(application) {
class ReadRssViewModel(application: Application) : BaseViewModel(application), JsExtensions {
var rssSource: RssSource? = null
var rssArticle: RssArticle? = null
var tts: TTS? = null
@@ -36,6 +38,10 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) {
val upTtsMenuData = MutableLiveData<Boolean>()
val upStarMenuData = MutableLiveData<Boolean>()
override fun getSource(): BaseSource? {
return rssSource
}
fun initData(intent: Intent) {
execute {
val origin = intent.getStringExtra("origin") ?: return@execute

View File

@@ -0,0 +1,30 @@
package io.legado.app.utils
import java.net.URL
import java.net.URLDecoder
@Suppress("MemberVisibilityCanBePrivate")
class JsURL(url: String, baseUrl: String? = null) {
val searchParams: Map<String, String>?
init {
val mUrl = if (!baseUrl.isNullOrEmpty()) {
val base = URL(baseUrl)
URL(base, url)
} else {
URL(url)
}
val query = mUrl.query
searchParams = query?.let { query ->
val map = hashMapOf<String, String>()
query.split("&").forEach {
val x = it.split("=")
map[x[0]] = URLDecoder.decode(x[1], "utf-8")
}
map
}
}
}

View File

@@ -48,6 +48,12 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
private val indexedProps: MutableMap<Any, Any?>
private val implementor: InterfaceImplementor
fun eval(js: String, bindingsConfig: SimpleBindings.() -> Unit = {}): Any? {
val bindings = SimpleBindings()
bindings.apply(bindingsConfig)
return eval(js, bindings)
}
@Throws(ScriptException::class)
override fun eval(reader: Reader, scope: Scriptable): Any? {
val cx = Context.enter()