Просмотр исходного кода

Merge pull request #4193 from NihilityT/master

验证流程问题修复
Horis 2 лет назад
Родитель
Сommit
9385e01ecd

+ 2 - 1
app/src/main/assets/web/help/md/jsHelp.md

@@ -20,7 +20,8 @@
 |变量名|调用类|
 |------|-----|
 |java|当前类|
-|baseUrl|当前url,String  |
+|baseUrl|String,当前 url,如 `https://example.com/page/1`|
+|baseUrlWithOptions|String,带参数的当前 url,如 `https://example.com/page/1,{"webView": true}`|
 |result|上一步的结果|
 |book|[书籍类](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)|
 |chapter|[章节类](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookChapter.kt)|

+ 2 - 2
app/src/main/java/io/legado/app/help/JsExtensions.kt

@@ -226,10 +226,10 @@ interface JsExtensions : JsEncodeUtils {
     /**
      * 使用内置浏览器打开链接,并等待网页结果
      */
-    fun startBrowserAwait(url: String, title: String): StrResponse {
+    fun startBrowserAwait(url: String, title: String, refetchAfterSuccess: Boolean = true): StrResponse {
         return StrResponse(
             url,
-            SourceVerificationHelp.getVerificationResult(getSource(), url, title, true)
+            SourceVerificationHelp.getVerificationResult(getSource(), url, title, true, refetchAfterSuccess)
         )
     }
 

+ 28 - 15
app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt

@@ -19,8 +19,8 @@ object SourceVerificationHelp {
 
     private val waitTime = 1.minutes.inWholeNanoseconds
 
-    private fun getKey(source: BaseSource) = getKey(source.getKey())
-    fun getKey(sourceKey: String) = "${sourceKey}_verificationResult"
+    private fun getVerificationResultKey(source: BaseSource) = getVerificationResultKey(source.getKey())
+    private fun getVerificationResultKey(sourceKey: String) = "${sourceKey}_verificationResult"
 
     /**
      * 获取书源验证结果
@@ -30,27 +30,27 @@ object SourceVerificationHelp {
         source: BaseSource?,
         url: String,
         title: String,
-        useBrowser: Boolean
+        useBrowser: Boolean,
+        refetchAfterSuccess: Boolean = true
     ): String {
         source
             ?: throw NoStackTraceException("getVerificationResult parameter source cannot be null")
 
-        val key = getKey(source)
-        CacheManager.delete(key)
+        clearResult(source.getKey())
 
         if (!useBrowser) {
             appCtx.startActivity<VerificationCodeActivity> {
                 putExtra("imageUrl", url)
                 putExtra("sourceOrigin", source.getKey())
                 putExtra("sourceName", source.getTag())
-                IntentData.put(key, Thread.currentThread())
+                IntentData.put(getVerificationResultKey(source), Thread.currentThread())
             }
         } else {
-            startBrowser(source, url, title, true)
+            startBrowser(source, url, title, true, refetchAfterSuccess)
         }
 
         var waitUserInput = false
-        while (CacheManager.get(key) == null) {
+        while (getResult(source.getKey()) == null) {
             if (!waitUserInput) {
                 AppLog.putDebug("等待返回验证结果...")
                 waitUserInput = true
@@ -58,7 +58,7 @@ object SourceVerificationHelp {
             LockSupport.parkNanos(this, waitTime)
         }
 
-        return CacheManager.get(key)!!.let {
+        return getResult(source.getKey())!!.let {
             it.ifBlank {
                 throw NoStackTraceException("验证结果为空")
             }
@@ -73,25 +73,38 @@ object SourceVerificationHelp {
         source: BaseSource?,
         url: String,
         title: String,
-        saveResult: Boolean? = false
+        saveResult: Boolean? = false,
+        refetchAfterSuccess: Boolean? = true
     ) {
         source ?: throw NoStackTraceException("startBrowser parameter source cannot be null")
-        val key = getKey(source)
         appCtx.startActivity<WebViewActivity> {
             putExtra("title", title)
             putExtra("url", url)
             putExtra("sourceOrigin", source.getKey())
             putExtra("sourceName", source.getTag())
             putExtra("sourceVerificationEnable", saveResult)
+            putExtra("refetchAfterSuccess", refetchAfterSuccess)
             IntentData.put(url, source.getHeaderMap(true))
-            IntentData.put(key, Thread.currentThread())
+            IntentData.put(getVerificationResultKey(source), Thread.currentThread())
         }
     }
 
 
-    fun checkResult(key: String) {
-        CacheManager.get(key) ?: CacheManager.putMemory(key, "")
-        val thread = IntentData.get<Thread>(key)
+    fun checkResult(sourceKey: String) {
+        getResult(sourceKey) ?: setResult(sourceKey, "")
+        val thread = IntentData.get<Thread>(getVerificationResultKey(sourceKey))
         LockSupport.unpark(thread)
     }
+
+    fun setResult(sourceKey: String, result: String?) {
+        CacheManager.putMemory(getVerificationResultKey(sourceKey), result ?: "")
+    }
+
+    fun getResult(sourceKey: String): String? {
+        return CacheManager.get(getVerificationResultKey(sourceKey))
+    }
+
+    fun clearResult(sourceKey: String) {
+        CacheManager.delete(getVerificationResultKey(sourceKey))
+    }
 }

+ 14 - 13
app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt

@@ -54,6 +54,8 @@ class AnalyzeRule(
         private set
     var baseUrl: String? = null
         private set
+    var optionStr: String = "{}"
+        private set
     var redirectUrl: URL? = null
         private set
     private var isJSON: Boolean = false
@@ -63,10 +65,6 @@ class AnalyzeRule(
     private var analyzeByJSoup: AnalyzeByJSoup? = null
     private var analyzeByJSonPath: AnalyzeByJSonPath? = null
 
-    private var objectChangedXP = false
-    private var objectChangedJS = false
-    private var objectChangedJP = false
-
     private val stringRuleCache = hashMapOf<String, List<SourceRule>>()
 
     private var coroutineContext: CoroutineContext = EmptyCoroutineContext
@@ -80,9 +78,9 @@ class AnalyzeRule(
             else -> content.toString().isJson()
         }
         setBaseUrl(baseUrl)
-        objectChangedXP = true
-        objectChangedJS = true
-        objectChangedJP = true
+        analyzeByXPath = null
+        analyzeByJSoup = null
+        analyzeByJSonPath = null
         return this
     }
 
@@ -98,6 +96,11 @@ class AnalyzeRule(
         return this
     }
 
+    fun setOption(option: String): AnalyzeRule {
+        optionStr = option
+        return this
+    }
+
     fun setRedirectUrl(url: String): URL? {
         try {
             redirectUrl = URL(url)
@@ -114,9 +117,8 @@ class AnalyzeRule(
         return if (o != content) {
             AnalyzeByXPath(o)
         } else {
-            if (analyzeByXPath == null || objectChangedXP) {
+            if (analyzeByXPath == null) {
                 analyzeByXPath = AnalyzeByXPath(content!!)
-                objectChangedXP = false
             }
             analyzeByXPath!!
         }
@@ -129,9 +131,8 @@ class AnalyzeRule(
         return if (o != content) {
             AnalyzeByJSoup(o)
         } else {
-            if (analyzeByJSoup == null || objectChangedJS) {
+            if (analyzeByJSoup == null) {
                 analyzeByJSoup = AnalyzeByJSoup(content!!)
-                objectChangedJS = false
             }
             analyzeByJSoup!!
         }
@@ -144,9 +145,8 @@ class AnalyzeRule(
         return if (o != content) {
             AnalyzeByJSonPath(o)
         } else {
-            if (analyzeByJSonPath == null || objectChangedJP) {
+            if (analyzeByJSonPath == null) {
                 analyzeByJSonPath = AnalyzeByJSonPath(content!!)
-                objectChangedJP = false
             }
             analyzeByJSonPath!!
         }
@@ -754,6 +754,7 @@ class AnalyzeRule(
             bindings["book"] = book
             bindings["result"] = result
             bindings["baseUrl"] = baseUrl
+            bindings["baseUrlWithOptions"] = "$baseUrl,$optionStr"
             bindings["chapter"] = chapter
             bindings["title"] = chapter?.title
             bindings["src"] = content

+ 4 - 1
app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt

@@ -76,6 +76,7 @@ class AnalyzeUrl(
     var type: String? = null
         private set
     val headerMap = HashMap<String, String>()
+    var optionStr: String = ""
     private var urlNoQuery: String = ""
     private var queryStr: String? = null
     private val fieldMap = LinkedHashMap<String, String>()
@@ -193,8 +194,10 @@ class AnalyzeUrl(
             baseUrl = it
         }
         if (urlNoOption.length != ruleUrl.length) {
-            GSON.fromJsonObject<UrlOption>(ruleUrl.substring(urlMatcher.end())).getOrNull()
+            val optionStr = ruleUrl.substring(urlMatcher.end())
+            GSON.fromJsonObject<UrlOption>(optionStr).getOrNull()
                 ?.let { option ->
+                    this.optionStr = optionStr
                     option.getMethod()?.let {
                         if (it.equals("POST", true)) method = RequestMethod.POST
                     }

+ 1 - 1
app/src/main/java/io/legado/app/model/webBook/BookList.kt

@@ -43,7 +43,7 @@ object BookList {
         Debug.log(bookSource.bookSourceUrl, "≡获取成功:${analyzeUrl.ruleUrl}")
         Debug.log(bookSource.bookSourceUrl, body, state = 10)
         val analyzeRule = AnalyzeRule(ruleData, bookSource)
-        analyzeRule.setContent(body).setBaseUrl(baseUrl)
+        analyzeRule.setContent(body).setBaseUrl(baseUrl).setOption(analyzeUrl.optionStr)
         analyzeRule.setRedirectUrl(baseUrl)
         analyzeRule.setCoroutineContext(coroutineContext)
         if (isSearch) bookSource.bookUrlPattern?.let {

+ 2 - 4
app/src/main/java/io/legado/app/ui/association/VerificationCodeDialog.kt

@@ -57,7 +57,6 @@ class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification
     }
 
     private var sourceOrigin: String? = null
-    private var key = ""
 
     override fun onFragmentCreated(view: View, savedInstanceState: Bundle?): Unit = binding.run {
         initMenu()
@@ -65,7 +64,6 @@ class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification
         toolBar.setBackgroundColor(primaryColor)
         toolBar.subtitle = arguments.getString("sourceName")
         sourceOrigin = arguments.getString("sourceOrigin")
-        key = SourceVerificationHelp.getKey(sourceOrigin!!)
         val imageUrl = arguments.getString("imageUrl") ?: return@run
         loadImage(imageUrl, sourceOrigin)
         verificationCodeImageView.setOnClickListener {
@@ -119,7 +117,7 @@ class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification
         when (item.itemId) {
             R.id.menu_ok -> {
                 val verificationCode = binding.verificationCode.text.toString()
-                CacheManager.putMemory(key, verificationCode)
+                SourceVerificationHelp.setResult(sourceOrigin!!, verificationCode)
                 dismiss()
             }
         }
@@ -127,7 +125,7 @@ class VerificationCodeDialog() : BaseDialogFragment(R.layout.dialog_verification
     }
 
     override fun onDestroy() {
-        SourceVerificationHelp.checkResult(key)
+        SourceVerificationHelp.checkResult(sourceOrigin!!)
         super.onDestroy()
         activity?.finish()
     }

+ 3 - 3
app/src/main/java/io/legado/app/ui/browser/WebViewActivity.kt

@@ -82,7 +82,7 @@ class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
             R.id.menu_copy_url -> sendToClip(viewModel.baseUrl)
             R.id.menu_ok -> {
                 if (viewModel.sourceVerificationEnable) {
-                    viewModel.saveVerificationResult(intent) {
+                    viewModel.saveVerificationResult(binding.webView) {
                         finish()
                     }
                 } else {
@@ -158,7 +158,7 @@ class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
     }
 
     override fun finish() {
-        SourceVerificationHelp.checkResult(viewModel.key)
+        SourceVerificationHelp.checkResult(viewModel.sourceOrigin)
         super.finish()
     }
 
@@ -224,7 +224,7 @@ class WebViewActivity : VMBaseActivity<ActivityWebViewBinding, WebViewModel>() {
                     if (it == "true") {
                         isCloudflareChallenge = true
                     } else if (isCloudflareChallenge && viewModel.sourceVerificationEnable) {
-                        viewModel.saveVerificationResult(intent) {
+                        viewModel.saveVerificationResult(binding.webView) {
                             finish()
                         }
                     }

+ 23 - 10
app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt

@@ -5,6 +5,7 @@ import android.content.Intent
 import android.net.Uri
 import android.util.Base64
 import android.webkit.URLUtil
+import android.webkit.WebView
 import androidx.documentfile.provider.DocumentFile
 import io.legado.app.base.BaseViewModel
 import io.legado.app.constant.AppConst
@@ -22,27 +23,30 @@ import io.legado.app.utils.isContentScheme
 import io.legado.app.utils.printOnDebug
 import io.legado.app.utils.toastOnUi
 import io.legado.app.utils.writeBytes
+import org.apache.commons.text.StringEscapeUtils
 import java.io.File
 import java.util.Date
 
 class WebViewModel(application: Application) : BaseViewModel(application) {
+    var intent: Intent? = null
     var baseUrl: String = ""
     var html: String? = null
     val headerMap: HashMap<String, String> = hashMapOf()
     var sourceVerificationEnable: Boolean = false
+    var refetchAfterSuccess: Boolean = true
     var sourceOrigin: String = ""
-    var key = ""
 
     fun initData(
         intent: Intent,
         success: () -> Unit
     ) {
         execute {
+            this@WebViewModel.intent = intent
             val url = intent.getStringExtra("url")
                 ?: throw NoStackTraceException("url不能为空")
             sourceOrigin = intent.getStringExtra("sourceOrigin") ?: ""
-            key = SourceVerificationHelp.getKey(sourceOrigin)
             sourceVerificationEnable = intent.getBooleanExtra("sourceVerificationEnable", false)
+            refetchAfterSuccess = intent.getBooleanExtra("refetchAfterSuccess", true)
             val headerMapF = IntentData.get<Map<String, String>>(url)
             val analyzeUrl = AnalyzeUrl(url, headerMapF = headerMapF)
             baseUrl = analyzeUrl.url
@@ -91,21 +95,30 @@ class WebViewModel(application: Application) : BaseViewModel(application) {
         }
     }
 
-    fun saveVerificationResult(intent: Intent, success: () -> Unit) {
-        execute {
-            if (sourceVerificationEnable) {
-                val url = intent.getStringExtra("url")!!
+    fun saveVerificationResult(webView: WebView, success: () -> Unit) {
+        if (!sourceVerificationEnable) {
+            execute { success.invoke() }
+        }
+        if (refetchAfterSuccess) {
+            execute {
+                val url = intent!!.getStringExtra("url")!!
                 val source = appDb.bookSourceDao.getBookSource(sourceOrigin)
-                val key = "${sourceOrigin}_verificationResult"
                 html = AnalyzeUrl(
                     url,
                     headerMapF = headerMap,
                     source = source
                 ).getStrResponseAwait(useWebView = false).body
-                CacheManager.putMemory(key, html ?: "")
+                SourceVerificationHelp.setResult(sourceOrigin, html ?: "")
+                success.invoke()
+            }
+        } else {
+            webView.evaluateJavascript("document.documentElement.outerHTML") {
+                execute {
+                    html = StringEscapeUtils.unescapeJson(it).trim('"')
+                    SourceVerificationHelp.setResult(sourceOrigin, html ?: "")
+                    success.invoke()
+                }
             }
-        }.onSuccess {
-            success.invoke()
         }
     }