pull/32/head
kunfei 5 years ago
parent 27f7af2615
commit 1c2df99a67
  1. 46
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt
  2. 147
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt
  3. 3
      app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt
  4. 3
      app/src/main/java/io/legado/app/model/webbook/BookList.kt

@ -70,7 +70,9 @@ object AnalyzeByRegex {
val len = str.length val len = str.length
while (index < len) { while (index < len) {
if (str[index] == '$') { if (str[index] == '$') {
if (str[index + 1] == '{') { if (index + 1 >= len) {
break
} else if (str[index + 1] == '{') {
if (index > start) { if (index > start) {
ruleParam.add(str.substring(start, index)) ruleParam.add(str.substring(start, index))
ruleType.add(0) ruleType.add(0)
@ -106,10 +108,29 @@ object AnalyzeByRegex {
start = index start = index
} }
} else { } else {
++index index++
}
} else if (str[index] == '{') {
if (index + 1 >= len) {
break
} else if (str[index + 1] == '{') {
if (index > start) {
ruleParam.add(str.substring(start, index))
ruleType.add(0)
start = index
}
while (index + 1 < len) {
if (str[index] == '}' && str[index + 1] == '}') {
ruleParam.add(str.substring(start + 2, index))
ruleType.add(-11)
start = index + 2
break
}
index++
}
} }
} else { } else {
++index index++
} }
} }
if (index > start) { if (index > start) {
@ -118,25 +139,6 @@ object AnalyzeByRegex {
} }
} }
// 存取字符串中的put&get参数
fun checkKeys(ruleStr: String, analyzer: AnalyzeRule): String {
var str = ruleStr
if (str.contains("@put:{")) {
val putMatcher = Pattern.compile("@put:\\{([^,]*):([^\\}]*)\\}").matcher(str)
while (putMatcher.find()) {
str = str.replace(putMatcher.group(0), "")
analyzer.put(putMatcher.group(1), putMatcher.group(2))
}
}
if (str.contains("@get:{")) {
val getMatcher = Pattern.compile("@get:\\{([^\\}]*)\\}").matcher(str)
while (getMatcher.find()) {
str = str.replace(getMatcher.group(), analyzer[getMatcher.group(1)] ?: "")
}
}
return str
}
// String数字转int数字的高效方法(利用ASCII值判断) // String数字转int数字的高效方法(利用ASCII值判断)
private fun string2Int(s: String): Int { private fun string2Int(s: String): Int {
var r = 0 var r = 0

@ -1,16 +1,15 @@
package io.legado.app.model.analyzeRule package io.legado.app.model.analyzeRule
import android.annotation.SuppressLint
import android.text.TextUtils import android.text.TextUtils
import androidx.annotation.Keep import androidx.annotation.Keep
import io.legado.app.constant.AppConst.SCRIPT_ENGINE 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.constant.Pattern.JS_PATTERN
import io.legado.app.data.entities.BaseBook import io.legado.app.data.entities.BaseBook
import io.legado.app.utils.* import io.legado.app.utils.*
import java.util.* import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
import javax.script.SimpleBindings import javax.script.SimpleBindings
import kotlin.collections.HashMap
/** /**
@ -18,6 +17,7 @@ import javax.script.SimpleBindings
* 统一解析接口 * 统一解析接口
*/ */
@Keep @Keep
@Suppress("unused")
class AnalyzeRule(private var book: BaseBook? = null) { class AnalyzeRule(private var book: BaseBook? = null) {
private var content: Any? = null private var content: Any? = null
private var baseUrl: String? = null private var baseUrl: String? = null
@ -121,6 +121,8 @@ class AnalyzeRule(private var book: BaseBook? = null) {
if (ruleList.isNotEmpty()) { if (ruleList.isNotEmpty()) {
if (ruleList.isNotEmpty()) result = o if (ruleList.isNotEmpty()) result = o
for (rule in ruleList) { for (rule in ruleList) {
putRule(rule.putMap)
rule.makeUpRule(result)
result?.let { result?.let {
if (rule.rule.isNotEmpty()) { if (rule.rule.isNotEmpty()) {
when (rule.mode) { when (rule.mode) {
@ -129,7 +131,9 @@ class AnalyzeRule(private var book: BaseBook? = null) {
getAnalyzeByJSonPath(it).getStringList(rule.rule) getAnalyzeByJSonPath(it).getStringList(rule.rule)
Mode.XPath -> result = Mode.XPath -> result =
getAnalyzeByXPath(it).getStringList(rule.rule) getAnalyzeByXPath(it).getStringList(rule.rule)
else -> result = getAnalyzeByJSoup(it).getStringList(rule.rule) Mode.Default -> result = getAnalyzeByJSoup(it).getStringList(rule.rule)
else -> {
}
} }
} }
if (rule.replaceRegex.isNotEmpty() && result is List<*>) { if (rule.replaceRegex.isNotEmpty() && result is List<*>) {
@ -189,6 +193,8 @@ class AnalyzeRule(private var book: BaseBook? = null) {
content?.let { o -> content?.let { o ->
if (ruleList.isNotEmpty()) result = o if (ruleList.isNotEmpty()) result = o
for (rule in ruleList) { for (rule in ruleList) {
putRule(rule.putMap)
rule.makeUpRule(result)
result?.let { result?.let {
if (rule.rule.isNotBlank()) { if (rule.rule.isNotBlank()) {
when (rule.mode) { when (rule.mode) {
@ -200,6 +206,8 @@ class AnalyzeRule(private var book: BaseBook? = null) {
} else { } else {
getAnalyzeByJSoup(it).getString(rule.rule) getAnalyzeByJSoup(it).getString(rule.rule)
} }
else -> {
}
} }
} }
if (rule.replaceRegex.isNotEmpty()) { if (rule.replaceRegex.isNotEmpty()) {
@ -228,8 +236,11 @@ class AnalyzeRule(private var book: BaseBook? = null) {
content?.let { o -> content?.let { o ->
if (ruleList.isNotEmpty()) result = o if (ruleList.isNotEmpty()) result = o
for (rule in ruleList) { for (rule in ruleList) {
putRule(rule.putMap)
result?.let { result?.let {
when (rule.mode) { when (rule.mode) {
Mode.Regex -> result =
AnalyzeByRegex.getElement(result.toString(), rule.rule.splitNotBlank("&&"))
Mode.Js -> result = evalJS(rule.rule, it) Mode.Js -> result = evalJS(rule.rule, it)
Mode.Json -> result = getAnalyzeByJSonPath(it).getObject(rule.rule) Mode.Json -> result = getAnalyzeByJSonPath(it).getObject(rule.rule)
Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule) Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule)
@ -255,12 +266,12 @@ class AnalyzeRule(private var book: BaseBook? = null) {
content?.let { o -> content?.let { o ->
if (ruleList.isNotEmpty()) result = o if (ruleList.isNotEmpty()) result = o
for (rule in ruleList) { for (rule in ruleList) {
putRule(rule.putMap)
result?.let { result?.let {
when (rule.mode) { when (rule.mode) {
Mode.Js -> { Mode.Regex -> result =
if (result == null) result = content AnalyzeByRegex.getElements(result.toString(), rule.rule.splitNotBlank("&&"))
result = evalJS(rule.rule, result) Mode.Js -> result = evalJS(rule.rule, result)
}
Mode.Json -> result = getAnalyzeByJSonPath(it).getList(rule.rule) Mode.Json -> result = getAnalyzeByJSonPath(it).getList(rule.rule)
Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule) Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule)
else -> result = getAnalyzeByJSoup(it).getElements(rule.rule) else -> result = getAnalyzeByJSoup(it).getElements(rule.rule)
@ -291,16 +302,16 @@ class AnalyzeRule(private var book: BaseBook? = null) {
} }
/** /**
* 分离并执行put规则 * 分离put规则
*/ */
@Throws(Exception::class) @Throws(Exception::class)
private fun splitPutRule(ruleStr: String): String { private fun splitPutRule(ruleStr: String, putMap: HashMap<String, String>): String {
var vRuleStr = ruleStr var vRuleStr = ruleStr
val putMatcher = putPattern.matcher(vRuleStr) val putMatcher = putPattern.matcher(vRuleStr)
while (putMatcher.find()) { while (putMatcher.find()) {
vRuleStr = vRuleStr.replace(putMatcher.group(), "") vRuleStr = vRuleStr.replace(putMatcher.group(), "")
val map = GSON.fromJsonObject<Map<String, String>>(putMatcher.group(1)) val map = GSON.fromJsonObject<Map<String, String>>(putMatcher.group(1))
map?.let { putRule(map) } map?.let { putMap.putAll(map) }
} }
return vRuleStr return vRuleStr
} }
@ -308,7 +319,7 @@ class AnalyzeRule(private var book: BaseBook? = null) {
/** /**
* 替换@get * 替换@get
*/ */
fun replaceGet(ruleStr: String): String { private fun replaceGet(ruleStr: String): String {
var vRuleStr = ruleStr var vRuleStr = ruleStr
val getMatcher = getPattern.matcher(vRuleStr) val getMatcher = getPattern.matcher(vRuleStr)
while (getMatcher.find()) { while (getMatcher.find()) {
@ -341,33 +352,33 @@ class AnalyzeRule(private var book: BaseBook? = null) {
} }
return vResult return vResult
} }
//
/** // /**
* 替换JS // * 替换JS
*/ // */
@SuppressLint("DefaultLocale") // @SuppressLint("DefaultLocale")
@Throws(Exception::class) // @Throws(Exception::class)
private fun replaceJs(ruleStr: String): String { // private fun replaceJs(ruleStr: String): String {
var vRuleStr = ruleStr // var vRuleStr = ruleStr
if (vRuleStr.contains("{{") && vRuleStr.contains("}}")) { // if (vRuleStr.contains("{{") && vRuleStr.contains("}}")) {
var jsEval: Any // var jsEval: Any
val sb = StringBuffer(vRuleStr.length) // val sb = StringBuffer(vRuleStr.length)
val expMatcher = EXP_PATTERN.matcher(vRuleStr) // val expMatcher = EXP_PATTERN.matcher(vRuleStr)
while (expMatcher.find()) { // while (expMatcher.find()) {
jsEval = evalJS(expMatcher.group(1), content) // jsEval = evalJS(expMatcher.group(1), content)
if (jsEval is String) { // if (jsEval is String) {
expMatcher.appendReplacement(sb, jsEval) // expMatcher.appendReplacement(sb, jsEval)
} else if (jsEval is Double && jsEval % 1.0 == 0.0) { // } else if (jsEval is Double && jsEval % 1.0 == 0.0) {
expMatcher.appendReplacement(sb, String.format("%.0f", jsEval)) // expMatcher.appendReplacement(sb, String.format("%.0f", jsEval))
} else { // } else {
expMatcher.appendReplacement(sb, jsEval.toString()) // expMatcher.appendReplacement(sb, jsEval.toString())
} // }
} // }
expMatcher.appendTail(sb) // expMatcher.appendTail(sb)
vRuleStr = sb.toString() // vRuleStr = sb.toString()
} // }
return vRuleStr // return vRuleStr
} // }
/** /**
* 分解规则生成规则列表 * 分解规则生成规则列表
@ -386,27 +397,27 @@ class AnalyzeRule(private var book: BaseBook? = null) {
} }
vRuleStr.startsWith("@Json:", true) -> { vRuleStr.startsWith("@Json:", true) -> {
mode = Mode.Json mode = Mode.Json
isRegex = true
vRuleStr = vRuleStr.substring(6) vRuleStr = vRuleStr.substring(6)
} }
else -> mode = if (isJSON) { vRuleStr.startsWith(":") -> {
Mode.Json mode = Mode.Regex
} else { vRuleStr = vRuleStr.substring(1)
Mode.Default
} }
else -> mode =
when {
isRegex -> Mode.Regex
isJSON -> Mode.Json
else -> Mode.Default
}
} }
//分离put规则 //拆分为规则列表
vRuleStr = splitPutRule(vRuleStr)
//替换get值
vRuleStr = replaceGet(vRuleStr)
//替换js
vRuleStr = replaceJs(vRuleStr)
//拆分为列表
var start = 0 var start = 0
var tmp: String var tmp: String
val jsMatcher = JS_PATTERN.matcher(vRuleStr) val jsMatcher = JS_PATTERN.matcher(vRuleStr)
while (jsMatcher.find()) { while (jsMatcher.find()) {
if (jsMatcher.start() > start) { if (jsMatcher.start() > start) {
tmp = vRuleStr.substring(start, jsMatcher.start()).replace("\n".toRegex(), "").trim { it <= ' ' } tmp = vRuleStr.substring(start, jsMatcher.start()).replace("\n", "").trim { it <= ' ' }
if (!TextUtils.isEmpty(tmp)) { if (!TextUtils.isEmpty(tmp)) {
ruleList.add(SourceRule(tmp, mode)) ruleList.add(SourceRule(tmp, mode))
} }
@ -415,7 +426,7 @@ class AnalyzeRule(private var book: BaseBook? = null) {
start = jsMatcher.end() start = jsMatcher.end()
} }
if (vRuleStr.length > start) { if (vRuleStr.length > start) {
tmp = vRuleStr.substring(start).replace("\n".toRegex(), "").trim { it <= ' ' } tmp = vRuleStr.substring(start).replace("\n", "").trim { it <= ' ' }
if (!TextUtils.isEmpty(tmp)) { if (!TextUtils.isEmpty(tmp)) {
ruleList.add(SourceRule(tmp, mode)) ruleList.add(SourceRule(tmp, mode))
} }
@ -432,6 +443,9 @@ class AnalyzeRule(private var book: BaseBook? = null) {
internal var replaceRegex = "" internal var replaceRegex = ""
internal var replacement = "" internal var replacement = ""
internal var replaceFirst = false internal var replaceFirst = false
internal val putMap = HashMap<String, String>()
private val ruleParam = ArrayList<String>()
private val ruleType = ArrayList<Int>()
init { init {
this.mode = mainMode this.mode = mainMode
@ -475,12 +489,41 @@ class AnalyzeRule(private var book: BaseBook? = null) {
if (ruleStrS.size > 3) { if (ruleStrS.size > 3) {
replaceFirst = true replaceFirst = true
} }
//分离put
rule = splitPutRule(rule, putMap)
rule = replaceGet(rule)
// 拆分表达式替换规则
AnalyzeByRegex.splitRegexRule(rule, ruleParam, ruleType)
}
fun makeUpRule(result: Any?) {
val infoVal = StringBuilder()
var j = ruleParam.size
while (j-- > 0) {
val regType = ruleType[j]
if (regType > 0) {
@Suppress("UNCHECKED_CAST")
infoVal.insert(0, (result as List<String>)[regType])
} else if (regType < 0) {
val jsEval: Any = evalJS(ruleParam[j], result)
if (jsEval is String) {
infoVal.insert(0, jsEval)
} else if (jsEval is Double && jsEval % 1.0 == 0.0) {
infoVal.insert(0, String.format("%.0f", jsEval))
} else {
infoVal.insert(0, jsEval.toString())
}
} else {
infoVal.insert(0, ruleParam[j])
}
}
rule = infoVal.toString()
} }
} }
enum class Mode { enum class Mode {
XPath, Json, Default, Js XPath, Json, Default, Js, Regex
} }
fun put(key: String, value: String): String { fun put(key: String, value: String): String {

@ -41,6 +41,9 @@ object BookChapterList {
reverse = true reverse = true
listRule = listRule.substring(1) listRule = listRule.substring(1)
} }
if (listRule.startsWith("+")) {
listRule = listRule.substring(1)
}
var chapterData = analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) var chapterData = analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true)
chapterData.chapterList?.let { chapterData.chapterList?.let {
chapterList.addAll(it) chapterList.addAll(it)

@ -48,6 +48,9 @@ object BookList {
reverse = true reverse = true
ruleList = ruleList.substring(1) ruleList = ruleList.substring(1)
} }
if (ruleList.startsWith("+")) {
ruleList = ruleList.substring(1)
}
SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析书籍列表") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析书籍列表")
collections = analyzeRule.getElements(ruleList) collections = analyzeRule.getElements(ruleList)
if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) { if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) {

Loading…
Cancel
Save