HapeLee 2 месяцев назад
Родитель
Сommit
dbca69821b

+ 5 - 1
app/src/main/java/io/legado/app/help/CacheManager.kt

@@ -153,7 +153,10 @@ object CacheManager {
     }
 }
 
+@Keep
+@Suppress("unused")
 object WebCacheManager {
+    @JvmOverloads
     @JavascriptInterface
     fun put(key: String, value: String, saveTime: Int = 0) {
         CacheManager.put(key, value, saveTime)
@@ -184,6 +187,7 @@ object WebCacheManager {
         return CacheManager.get(key, onlyDisk)
     }
 
+    @JvmOverloads
     @JavascriptInterface
     fun putFile(key: String, value: String, saveTime: Int = 0) {
         CacheManager.putFile(key, value, saveTime)
@@ -198,4 +202,4 @@ object WebCacheManager {
     fun delete(key: String) {
         CacheManager.delete(key)
     }
-}
+}

+ 37 - 5
app/src/main/java/io/legado/app/help/webView/WebJsExtensions.kt

@@ -9,10 +9,12 @@ import io.legado.app.data.appDb
 import io.legado.app.data.entities.BaseSource
 import io.legado.app.data.entities.Book
 import io.legado.app.data.entities.BookChapter
+import io.legado.app.data.entities.RssSource
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.help.CacheManager
 import io.legado.app.help.coroutine.Coroutine
 import io.legado.app.model.AudioPlay
+import io.legado.app.model.Debug
 import io.legado.app.model.ReadBook
 import io.legado.app.model.analyzeRule.AnalyzeRule
 import io.legado.app.model.analyzeRule.AnalyzeRule.Companion.setChapter
@@ -21,6 +23,8 @@ import io.legado.app.ui.rss.read.RssJsExtensions
 import io.legado.app.utils.GSON
 import io.legado.app.utils.fromJsonObject
 import io.legado.app.utils.isJsonObject
+import io.legado.app.utils.toastOnUi
+import org.json.JSONObject
 import java.lang.ref.WeakReference
 import kotlin.uuid.Uuid
 
@@ -37,7 +41,7 @@ class WebJsExtensions(
 
     interface Callback {
         fun upConfig(config: String)
-        fun onNavigateToArticles(sortUrl: String? = null)
+        fun onNavigateToArticles(sortUrl: String? = null, origin: String? = null)
     }
 
     @JavascriptInterface
@@ -218,10 +222,38 @@ class WebJsExtensions(
     override fun open(name: String, url: String?, title: String?, origin: String?) {
         when (name) {
             "sort" -> {
-                val sortUrl = if (!url.isNullOrBlank()) {
-                    if (url.isJsonObject()) url else title?.let { "{\"$it\":\"$url\"}" } ?: url
-                } else null
-                callbackRef.get()?.onNavigateToArticles(sortUrl)
+                val sortUrl = if (url.isJsonObject()) {
+                    url
+                } else {
+                    title?.let { JSONObject().put(title, url).toString() } ?: url
+                }
+                val originKey = origin?.takeIf { it.isNotBlank() }
+                val targetSourceUrl = if (originKey != null) {
+                    appDb.rssSourceDao.getByKey(originKey)?.sourceUrl
+                } else {
+                    (getSource() as? RssSource)?.sourceUrl
+                }
+                if (targetSourceUrl == null) {
+                    // origin 指定的订阅源未安装时不能回退到当前源, 否则会用当前源的规则解析跨站 HTML
+                    if (originKey != null) {
+                        val missing = if (title.isNullOrBlank()) {
+                            originKey
+                        } else {
+                            "$title($originKey)"
+                        }
+                        Debug.log(
+                            getSource()?.getKey(),
+                            "WebView open(sort): 未找到订阅源 $missing url=$url"
+                        )
+                        activityRef.get()?.toastOnUi("未找到订阅源:$missing")
+                    }
+                    return
+                }
+                Debug.log(
+                    getSource()?.getKey(),
+                    "WebView open(sort): url=$url, title=$title, origin=$origin, target=$targetSourceUrl"
+                )
+                callbackRef.get()?.onNavigateToArticles(sortUrl, targetSourceUrl)
             }
             else -> super.open(name, url, title, origin)
         }

+ 20 - 1
app/src/main/java/io/legado/app/model/SharedJsScope.kt

@@ -69,7 +69,10 @@ object SharedJsScope {
                 RhinoScriptEngine.eval(jsLib, scope, coroutineContext)
             }
             if (scope is ScriptableObject) {
-                scope.sealObject()
+                /**
+                 * 阻止新全局增加(即函数内未用var的隐性全局变量创建),会直接隐性创建失败,提示变量未定义
+                 */
+                scope.preventExtensions()
             }
             scopeMap.put(key, WeakReference(scope))
         }
@@ -80,6 +83,22 @@ object SharedJsScope {
         if (jsLib.isNullOrBlank()) {
             return
         }
+        if (jsLib.isJsonObject()) {
+            val jsMap: Map<String, String> = GSON.fromJson(
+                jsLib,
+                TypeToken.getParameterized(
+                    Map::class.java,
+                    String::class.java,
+                    String::class.java
+                ).type
+            )
+            jsMap.values.forEach { value ->
+                if (value.isAbsUrl()) {
+                    val fileName = MD5Utils.md5Encode(value)
+                    aCache.remove(fileName)
+                }
+            }
+        }
         val key = MD5Utils.md5Encode(jsLib)
         scopeMap.remove(key)
     }

+ 1 - 1
app/src/main/java/io/legado/app/ui/login/SourceLoginSheets.kt

@@ -245,7 +245,7 @@ private fun SourceLoginRow(
 
 private fun LoginRowLayoutUi.textAlign(): TextAlign = when (justify) {
     "flex_start" -> TextAlign.Start
-    "flex_end", "right" -> TextAlign.End
+    "flex_end" -> TextAlign.End
     else -> TextAlign.Center
 }
 

+ 13 - 2
app/src/main/java/io/legado/app/ui/login/SourceLoginViewModel.kt

@@ -136,7 +136,7 @@ class SourceLoginViewModel(
                     _effects.tryEmit(SourceLoginEffect.Finish)
                     return@onSuccess
                 }
-                loginInfo = loaded.getLoginInfoMap()
+                loginInfo = withContext(Dispatchers.IO) { loaded.getLoginInfoMap() }
                 val headers = withContext(Dispatchers.IO) {
                     runScriptWithContext {
                         loaded.getHeaderMap(
@@ -291,7 +291,18 @@ class SourceLoginViewModel(
             runCatching {
                 if (loginInfo.isEmpty()) currentSource.removeLoginInfo()
                 else if (currentSource.putLoginInfo(GSON.toJson(loginInfo))) {
-                    runScriptWithContext { currentSource.login() }
+                    val loginJs = currentSource.getLoginJs() ?: return@launch
+                    val buttonFunctionJS =
+                        "if (typeof login=='function'){ login.apply(this); } else { throw('Function login not implements!!!') }"
+                    runScriptWithContext {
+                        currentSource.evalJS("$loginJs\n$buttonFunctionJS") {
+                            put("java", jsExtensions)
+                            put("result", loginInfo.toMutableMap())
+                            put("book", book)
+                            put("chapter", chapter)
+                            put("isLongClick", false)
+                        }
+                    }
                 }
             }.onSuccess {
                 submitted = true

+ 3 - 3
app/src/main/java/io/legado/app/ui/widget/dialog/BottomWebViewDialog.kt

@@ -66,12 +66,12 @@ import io.legado.app.ui.association.OnLineImportActivity
 import io.legado.app.ui.file.HandleFileContract
 import io.legado.app.utils.ACache
 import io.legado.app.utils.GSON
+import io.legado.app.utils.applyDayNight
 import io.legado.app.utils.fromJsonObject
 import io.legado.app.utils.invisible
 import io.legado.app.utils.longSnackbar
 import io.legado.app.utils.openUrl
 import io.legado.app.utils.setLayout
-import io.legado.app.utils.applyDayNight
 import io.legado.app.utils.startActivity
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.viewbindingdelegate.viewBinding
@@ -83,10 +83,10 @@ import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import org.koin.android.ext.android.inject
 import java.io.ByteArrayInputStream
 import java.lang.ref.WeakReference
 import java.util.Date
-import org.koin.android.ext.android.inject
 
 class BottomWebViewDialog() : BottomSheetDialogFragment(R.layout.dialog_web_view),
     WebJsExtensions.Callback {
@@ -631,7 +631,7 @@ class BottomWebViewDialog() : BottomSheetDialogFragment(R.layout.dialog_web_view
         }
     }
 
-    override fun onNavigateToArticles(sortUrl: String?) {
+    override fun onNavigateToArticles(sortUrl: String?, origin: String?) {
     }
 
     @Suppress("unused")