Merge pull request #4193 from NihilityT/master

验证流程问题修复
This commit is contained in:
Horis
2024-09-09 19:21:41 +08:00
committed by GitHub
9 changed files with 79 additions and 50 deletions

View File

@@ -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)|

View File

@@ -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)
)
}

View File

@@ -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))
}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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()
}

View File

@@ -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()
}
}

View File

@@ -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()
}
}