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 9382490f7..826c9aaba 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 @@ -5,8 +5,10 @@ import android.text.TextUtils import androidx.annotation.Keep import io.legado.app.constant.AppConst.SCRIPT_ENGINE import io.legado.app.constant.Pattern.EXP_PATTERN -import io.legado.app.constant.Pattern.JS_PATTERN +import io.legado.app.utils.GSON import io.legado.app.utils.NetworkUtils +import io.legado.app.utils.fromJsonObject +import okhttp3.RequestBody import java.net.URLEncoder import java.util.* import java.util.regex.Pattern @@ -18,11 +20,19 @@ import javax.script.SimpleBindings * 搜索URL规则解析 */ @Keep -class AnalyzeUrl @SuppressLint("DefaultLocale") -@Throws(Exception::class) -constructor(ruleUrl: String, key: String?, page: Int?, headerMapF: Map?, baseUrl: String?) { - private var baseUrl: String? = null - var url: String? = null +@SuppressLint("DefaultLocale") +class AnalyzeUrl( + private var ruleUrl: String, + key: String? = null, + page: Int? = null, + headerMapF: Map? = null, + var baseUrl: String? = null +) { + companion object { + private val pagePattern = Pattern.compile("<(.*?)>") + } + + lateinit var url: String private set var host: String? = null private set @@ -32,8 +42,10 @@ constructor(ruleUrl: String, key: String?, page: Int?, headerMapF: Map() private val headerMap = HashMap() - private var charCode: String? = null - var urlMode = UrlMode.DEFAULT + private var charset: String? = null + var body: RequestBody? = null + private set + var method = Method.GET private set val postData: ByteArray @@ -47,142 +59,42 @@ constructor(ruleUrl: String, key: String?, page: Int?, headerMapF: Map, baseUrl: String) : this( - urlRule, - null, - null, - headerMapF, - baseUrl - ) - init { - var ruleUrl = ruleUrl - if (!TextUtils.isEmpty(baseUrl)) { -// this.baseUrl = headerPattern.matcher(baseUrl).replaceAll("") - } - //解析Header - ruleUrl = analyzeHeader(ruleUrl, headerMapF) - //替换关键字 - key?.let { - if (it.isNotBlank()) { - ruleUrl = ruleUrl.replace("searchKey", it) - } - } - //分离编码规则 - ruleUrl = splitCharCode(ruleUrl) - //判断是否有下一页 - if (page != null && page > 1 && !ruleUrl.contains("searchPage")) - throw Exception("没有下一页") - //替换js - ruleUrl = replaceJs(ruleUrl, baseUrl, page, key) - //设置页数 - ruleUrl = analyzePage(ruleUrl, page) - //执行规则列表 - val ruleList = splitRule(ruleUrl) - for (rule in ruleList) { - ruleUrl = if (rule.startsWith("")) { - evalJS(rule.substring(4, rule.lastIndexOf("<")), ruleUrl) as String - } else { - rule.replace("@result", ruleUrl) - } - } - //分离post参数 - var ruleUrlS = ruleUrl.split("@".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (ruleUrlS.size > 1) { - urlMode = UrlMode.POST - } else { - //分离get参数 - ruleUrlS = ruleUrlS[0].split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (ruleUrlS.size > 1) { - urlMode = UrlMode.GET - } - } - generateUrlPath(ruleUrlS[0]) - if (urlMode != UrlMode.DEFAULT) { - analyzeQuery(ruleUrlS[1]) - } - } - - /** - * 解析Header - */ - private fun analyzeHeader(ruleUrl: String, headerMapF: Map?): String { -// var ruleUrl = ruleUrl -// if (headerMapF != null) { -// headerMap.putAll(headerMapF) -// } -// val matcher = headerPattern.matcher(ruleUrl) -// if (matcher.find()) { -// var find = matcher.group(0) -// ruleUrl = ruleUrl.replace(find, "") -// find = find.substring(8) -// try { -// val map = Gson().fromJsonObject>(find) -// headerMap.putAll(map) -// } catch (ignored: Exception) { -// } -// } - return ruleUrl + baseUrl = baseUrl?.split(",\n*".toRegex(), 1)?.get(0) + headerMapF?.let { headerMap.putAll(it) } + //替换参数 + replaceKeyPageJs(key, page) + //处理URL + initUrl() } /** - * 分离编码规则 + * 替换关键字,页数,JS */ - private fun splitCharCode(rule: String): String { - val ruleUrlS = rule.split("\\|".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (ruleUrlS.size > 1) { - if (!TextUtils.isEmpty(ruleUrlS[1])) { - val qtS = ruleUrlS[1].split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - for (qt in qtS) { - val gz = qt.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (gz[0] == "char") { - charCode = gz[1] - } + private fun replaceKeyPageJs(key: String?, page: Int?) { + //page + page?.let { + val matcher = pagePattern.matcher(ruleUrl) + while (matcher.find()) { + val pages = + matcher.group(1).split(",".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray() + ruleUrl = if (page <= pages.size) { + ruleUrl.replace(matcher.group(), pages[page - 1].trim { it <= ' ' }) + } else { + ruleUrl.replace(matcher.group(), pages[pages.size - 1].trim { it <= ' ' }) } } } - return ruleUrlS[0] - } - - /** - * 解析页数 - */ - private fun analyzePage(ruleUrl: String, searchPage: Int?): String { - var ruleUrl = ruleUrl - if (searchPage == null) return ruleUrl - val matcher = pagePattern.matcher(ruleUrl) - while (matcher.find()) { - val pages = matcher.group(1).split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - if (searchPage <= pages.size) { - ruleUrl = ruleUrl.replace(matcher.group(), pages[searchPage - 1].trim { it <= ' ' }) - } else { - ruleUrl = ruleUrl.replace(matcher.group(), pages[pages.size - 1].trim { it <= ' ' }) - } - } - return ruleUrl.replace("searchPage-1", (searchPage - 1).toString()) - .replace("searchPage+1", (searchPage + 1).toString()) - .replace("searchPage", searchPage.toString()) - } - - /** - * 替换js - */ - @SuppressLint("DefaultLocale") - @Throws(Exception::class) - private fun replaceJs(ruleUrl: String, baseUrl: String?, searchPage: Int?, searchKey: String?): String { - var ruleUrl = ruleUrl + //js if (ruleUrl.contains("{{") && ruleUrl.contains("}}")) { var jsEval: Any val sb = StringBuffer(ruleUrl.length) val simpleBindings = object : SimpleBindings() { init { this["baseUrl"] = baseUrl - this["searchPage"] = searchPage - this["searchKey"] = searchKey + this["page"] = page + this["key"] = key } } val expMatcher = EXP_PATTERN.matcher(ruleUrl) @@ -199,7 +111,27 @@ constructor(ruleUrl: String, key: String?, page: Int?, headerMapF: Map 1) { + val options = GSON.fromJsonObject>(urlArray[1]) + options?.let { + options["method"]?.let { if (it.equals("POST", true)) method = Method.POST } + options["headers"]?.let { headers -> + GSON.fromJsonObject>( + headers + )?.let { headerMap.putAll(it) } + } + options["body"]?.let { } + options["charset"]?.let { charset = it } + } + } } /** @@ -212,47 +144,20 @@ constructor(ruleUrl: String, key: String?, page: Int?, headerMapF: Map 1) queryM[1] else "" - if (TextUtils.isEmpty(charCode)) { + if (TextUtils.isEmpty(charset)) { if (NetworkUtils.hasUrlEncoded(value)) { queryMap[queryM[0]] = value } else { queryMap[queryM[0]] = URLEncoder.encode(value, "UTF-8") } - } else if (charCode == "escape") { + } else if (charset == "escape") { // queryMap[queryM[0]] = StringUtils.escape(value) } else { - queryMap[queryM[0]] = URLEncoder.encode(value, charCode) + queryMap[queryM[0]] = URLEncoder.encode(value, charset) } } } - /** - * 拆分规则 - */ - private fun splitRule(ruleStr: String): List { - val ruleList = ArrayList() - val jsMatcher = JS_PATTERN.matcher(ruleStr) - var start = 0 - var tmp: String - while (jsMatcher.find()) { - if (jsMatcher.start() > start) { - tmp = ruleStr.substring(start, jsMatcher.start()).replace("\n".toRegex(), "").trim { it <= ' ' } - if (!TextUtils.isEmpty(tmp)) { - ruleList.add(tmp) - } - } - ruleList.add(jsMatcher.group()) - start = jsMatcher.end() - } - if (ruleStr.length > start) { - tmp = ruleStr.substring(start).replace("\n".toRegex(), "").trim { it <= ' ' } - if (!TextUtils.isEmpty(tmp)) { - ruleList.add(tmp) - } - } - return ruleList - } - /** * 分解URL */ @@ -280,11 +185,7 @@ constructor(ruleUrl: String, key: String?, page: Int?, headerMapF: Map