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
@@ -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)
}
}
@@ -539,9 +539,9 @@ interface JsExtensions : JsEncodeUtils {
/** /**
* 删除本地文件 * 删除本地文件
*/ */
fun deleteFile(path: String) { fun deleteFile(path: String): Boolean {
val file = getFile(path) val file = getFile(path)
FileUtils.delete(file, true) return FileUtils.delete(file, true)
} }
/** /**
@@ -825,6 +825,15 @@ interface JsExtensions : JsEncodeUtils {
return s return s
} }
fun toURL(urlStr: String): JsURL {
return JsURL(urlStr)
}
fun toURL(url: String, baseUrl: String? = null): JsURL {
return JsURL(url, baseUrl)
}
/** /**
* 弹窗提示 * 弹窗提示
*/ */
@@ -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)
}
}
@@ -10,18 +10,23 @@ import android.view.*
import android.webkit.* import android.webkit.*
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.core.view.size import androidx.core.view.size
import com.script.rhino.RhinoScriptEngine
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.imagePathKey import io.legado.app.constant.AppConst.imagePathKey
import io.legado.app.data.entities.BaseSource
import io.legado.app.databinding.ActivityRssReadBinding import io.legado.app.databinding.ActivityRssReadBinding
import io.legado.app.help.JsExtensions
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.lib.dialogs.SelectItem import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.lib.dialogs.selector import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.accentColor
import io.legado.app.lib.theme.primaryTextColor import io.legado.app.lib.theme.primaryTextColor
import io.legado.app.model.Download 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.association.OnLineImportActivity
import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.file.HandleFileContract import io.legado.app.ui.file.HandleFileContract
import io.legado.app.ui.login.SourceLoginActivity import io.legado.app.ui.login.SourceLoginActivity
import io.legado.app.utils.* import io.legado.app.utils.*
@@ -39,6 +44,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
override val binding by viewBinding(ActivityRssReadBinding::inflate) override val binding by viewBinding(ActivityRssReadBinding::inflate)
override val viewModel by viewModels<ReadRssViewModel>() override val viewModel by viewModels<ReadRssViewModel>()
private var starMenuItem: MenuItem? = null private var starMenuItem: MenuItem? = null
private var ttsMenuItem: MenuItem? = null private var ttsMenuItem: MenuItem? = null
private var customWebViewCallback: WebChromeClient.CustomViewCallback? = null private var customWebViewCallback: WebChromeClient.CustomViewCallback? = null
@@ -48,6 +54,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
viewModel.saveImage(it.value, uri) viewModel.saveImage(it.value, uri)
} }
} }
private val rssJsExtensions by lazy { RssJsExtensions() }
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
viewModel.upStarMenuData.observe(this) { upStarMenu() } viewModel.upStarMenuData.observe(this) { upStarMenu() }
@@ -401,9 +408,14 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
val source = viewModel.rssSource val source = viewModel.rssSource
val js = source?.shouldOverrideUrlLoading val js = source?.shouldOverrideUrlLoading
if (!js.isNullOrBlank()) { if (!js.isNullOrBlank()) {
val result = source.evalJS(js) { val result = RhinoScriptEngine.runCatching {
put("url", url.toString()) eval(js) {
}.toString() put("java", rssJsExtensions)
put("url", url.toString())
}.toString()
}.onFailure {
it.printOnDebug()
}.getOrNull()
if (result.isTrue()) { if (result.isTrue()) {
return true 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))
}
}
} }
@@ -10,10 +10,12 @@ import androidx.lifecycle.viewModelScope
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst
import io.legado.app.data.appDb 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.RssArticle
import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssSource
import io.legado.app.data.entities.RssStar import io.legado.app.data.entities.RssStar
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.JsExtensions
import io.legado.app.help.TTS import io.legado.app.help.TTS
import io.legado.app.help.http.newCallResponseBody import io.legado.app.help.http.newCallResponseBody
import io.legado.app.help.http.okHttpClient import io.legado.app.help.http.okHttpClient
@@ -26,7 +28,7 @@ import splitties.init.appCtx
import java.util.Date import java.util.Date
class ReadRssViewModel(application: Application) : BaseViewModel(application) { class ReadRssViewModel(application: Application) : BaseViewModel(application), JsExtensions {
var rssSource: RssSource? = null var rssSource: RssSource? = null
var rssArticle: RssArticle? = null var rssArticle: RssArticle? = null
var tts: TTS? = null var tts: TTS? = null
@@ -36,6 +38,10 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) {
val upTtsMenuData = MutableLiveData<Boolean>() val upTtsMenuData = MutableLiveData<Boolean>()
val upStarMenuData = MutableLiveData<Boolean>() val upStarMenuData = MutableLiveData<Boolean>()
override fun getSource(): BaseSource? {
return rssSource
}
fun initData(intent: Intent) { fun initData(intent: Intent) {
execute { execute {
val origin = intent.getStringExtra("origin") ?: return@execute val origin = intent.getStringExtra("origin") ?: return@execute
@@ -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
}
}
}
@@ -48,6 +48,12 @@ object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
private val indexedProps: MutableMap<Any, Any?> private val indexedProps: MutableMap<Any, Any?>
private val implementor: InterfaceImplementor 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) @Throws(ScriptException::class)
override fun eval(reader: Reader, scope: Scriptable): Any? { override fun eval(reader: Reader, scope: Scriptable): Any? {
val cx = Context.enter() val cx = Context.enter()