diff --git a/app/src/main/assets/web/help/md/jsHelp.md b/app/src/main/assets/web/help/md/jsHelp.md index 5bdff919b..efd6bc6da 100644 --- a/app/src/main/assets/web/help/md/jsHelp.md +++ b/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)| diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index e71d18e8d..a87e1f1c6 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/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) ) } diff --git a/app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt b/app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt index c7b643222..5f28d6a9b 100644 --- a/app/src/main/java/io/legado/app/help/source/SourceVerificationHelp.kt +++ b/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 { 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 { 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(key) + fun checkResult(sourceKey: String) { + getResult(sourceKey) ?: setResult(sourceKey, "") + val thread = IntentData.get(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)) + } } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 9431fe7ef..5bf2725c4 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/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>() 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 diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 7b2f87069..814c3ec5d 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/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() + var optionStr: String = "" private var urlNoQuery: String = "" private var queryStr: String? = null private val fieldMap = LinkedHashMap() @@ -193,8 +194,10 @@ class AnalyzeUrl( baseUrl = it } if (urlNoOption.length != ruleUrl.length) { - GSON.fromJsonObject(ruleUrl.substring(urlMatcher.end())).getOrNull() + val optionStr = ruleUrl.substring(urlMatcher.end()) + GSON.fromJsonObject(optionStr).getOrNull() ?.let { option -> + this.optionStr = optionStr option.getMethod()?.let { if (it.equals("POST", true)) method = RequestMethod.POST } diff --git a/app/src/main/java/io/legado/app/model/webBook/BookList.kt b/app/src/main/java/io/legado/app/model/webBook/BookList.kt index d9f233dcf..f15f8f048 100644 --- a/app/src/main/java/io/legado/app/model/webBook/BookList.kt +++ b/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 { diff --git a/app/src/main/java/io/legado/app/ui/association/VerificationCodeDialog.kt b/app/src/main/java/io/legado/app/ui/association/VerificationCodeDialog.kt index 8190841e9..14953bfd4 100644 --- a/app/src/main/java/io/legado/app/ui/association/VerificationCodeDialog.kt +++ b/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() } diff --git a/app/src/main/java/io/legado/app/ui/browser/WebViewActivity.kt b/app/src/main/java/io/legado/app/ui/browser/WebViewActivity.kt index 57b026fb7..65d6d9ecc 100644 --- a/app/src/main/java/io/legado/app/ui/browser/WebViewActivity.kt +++ b/app/src/main/java/io/legado/app/ui/browser/WebViewActivity.kt @@ -82,7 +82,7 @@ class WebViewActivity : VMBaseActivity() { 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() { } override fun finish() { - SourceVerificationHelp.checkResult(viewModel.key) + SourceVerificationHelp.checkResult(viewModel.sourceOrigin) super.finish() } @@ -224,7 +224,7 @@ class WebViewActivity : VMBaseActivity() { if (it == "true") { isCloudflareChallenge = true } else if (isCloudflareChallenge && viewModel.sourceVerificationEnable) { - viewModel.saveVerificationResult(intent) { + viewModel.saveVerificationResult(binding.webView) { finish() } } diff --git a/app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt b/app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt index 7c8f6f77b..bab12ed97 100644 --- a/app/src/main/java/io/legado/app/ui/browser/WebViewModel.kt +++ b/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 = 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>(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() } }