mirror of
https://github.com/Aminark/legado-ios.git
synced 2026-10-24 21:01:22 +08:00
feat: 支持 EPUB 阅读并改善规则兼容与阅读稳定性
支持 EPUB 2/3 导入、目录、封面和章节插图,保留本地书管理与阅读进度。 修复 JSON 模板、动态替换与请求参数兼容,以及 RSS 翻页和连续滚动定位。 更新编辑器工具栏和回归测试,发布版本为 0.1.12(build 18)。
This commit is contained in:
@@ -17,6 +17,48 @@ public struct JSONPathEvaluator: Sendable {
|
||||
|
||||
public init() {}
|
||||
|
||||
// Legado's JSON rules also allow literal templates such as /book/{$.id}.
|
||||
// Balance braces and quoted strings instead of stopping at the first }.
|
||||
func evaluateRule(_ rule: String, in root: JSONValue) throws -> [JSONValue] {
|
||||
var cursor = rule.startIndex
|
||||
var output = ""
|
||||
var foundTemplate = false
|
||||
while let opening = rule.range(of: "{$.", range: cursor..<rule.endIndex) {
|
||||
foundTemplate = true
|
||||
output += rule[cursor..<opening.lowerBound]
|
||||
let start = rule.index(after: opening.lowerBound)
|
||||
var end = start
|
||||
var depth = 1
|
||||
var quote: Character?
|
||||
var escaped = false
|
||||
while end < rule.endIndex {
|
||||
let character = rule[end]
|
||||
if escaped { escaped = false }
|
||||
else if character == "\\" { escaped = true }
|
||||
else if let activeQuote = quote {
|
||||
if character == activeQuote { quote = nil }
|
||||
} else if character == "\"" || character == "'" { quote = character }
|
||||
else if character == "{" { depth += 1 }
|
||||
else if character == "}" {
|
||||
depth -= 1
|
||||
if depth == 0 { break }
|
||||
}
|
||||
end = rule.index(after: end)
|
||||
}
|
||||
guard end < rule.endIndex else {
|
||||
throw RuleEngineError.malformedRule(rule: rule, detail: "JSONPath 模板大括号未闭合")
|
||||
}
|
||||
let values = try evaluate(path: String(rule[start..<end]), in: root)
|
||||
output += RuleEvaluation(values: values).strings.joined(separator: "\n")
|
||||
cursor = rule.index(after: end)
|
||||
}
|
||||
if foundTemplate {
|
||||
output += rule[cursor...]
|
||||
return [.string(output)]
|
||||
}
|
||||
return try evaluate(path: rule.hasPrefix("$") ? rule : "$." + rule, in: root)
|
||||
}
|
||||
|
||||
public func evaluate(path: String, in root: JSONValue) throws -> [JSONValue] {
|
||||
let segments = try parse(path)
|
||||
var current = [root]
|
||||
@@ -59,7 +101,10 @@ public struct JSONPathEvaluator: Sendable {
|
||||
guard next < rule.endIndex else {
|
||||
throw RuleEngineError.malformedRule(rule: path, detail: "JSONPath 不能以点结尾")
|
||||
}
|
||||
if rule[next] == "." {
|
||||
if rule[next] == "[" {
|
||||
// Legacy sources use $.[*] as well as $[*].
|
||||
index = next
|
||||
} else if rule[next] == "." {
|
||||
index = rule.index(after: next)
|
||||
let parsed = try parseDotSelector(rule, from: index, original: path)
|
||||
segments.append(.recursive(parsed.selector))
|
||||
|
||||
Reference in New Issue
Block a user