feat: optimize reader caching and document formats
This commit is contained in:
@@ -73,7 +73,11 @@ public final class RDEpubURLReaderController: UIViewController {
|
||||
}
|
||||
|
||||
public func applyDemoDisplayType(_ displayType: RDEpubReaderView.DisplayType) {
|
||||
readerController?.configuration.displayType = displayType
|
||||
if let readerController {
|
||||
readerController.configuration.displayType = displayType
|
||||
} else {
|
||||
cbzReaderController?.setDisplayType(displayType)
|
||||
}
|
||||
emitDemoState(prefix: "display=\(displayType.demoArgumentValue)")
|
||||
}
|
||||
|
||||
@@ -145,14 +149,16 @@ public final class RDEpubURLReaderController: UIViewController {
|
||||
|
||||
private func embedReaderController() {
|
||||
let controller: UIViewController
|
||||
if bookURL.pathExtension.lowercased() == "epub" {
|
||||
switch RDReaderDocumentFormat(fileURL: bookURL) {
|
||||
case .epub:
|
||||
controller = RDEPUBReaderController(
|
||||
epubURL: bookURL,
|
||||
configuration: epubConfiguration
|
||||
)
|
||||
} else {
|
||||
case .cbz:
|
||||
controller = RDCBZReaderController(bookURL: bookURL, configuration: epubConfiguration)
|
||||
case .mobi, .plainText:
|
||||
let bookIdentifier = bookURL.lastPathComponent
|
||||
let bookTitle = bookURL.deletingPathExtension().lastPathComponent
|
||||
let pageSize = currentTextPageSize()
|
||||
let renderStyle = currentTextRenderStyle()
|
||||
let safeInsets = RDEPUBSafeArea.resolve(view.safeAreaInsets)
|
||||
@@ -176,23 +182,33 @@ public final class RDEpubURLReaderController: UIViewController {
|
||||
imageMaxHeightRatio: 0.85
|
||||
)
|
||||
)
|
||||
if let textBook = try? builder.build(textFileURL: bookURL, pageSize: pageSize, style: renderStyle) {
|
||||
do {
|
||||
let source: (textURL: URL, title: String)
|
||||
if RDReaderDocumentFormat(fileURL: bookURL) == .mobi {
|
||||
let document = try RDMOBIParser().parse(fileURL: bookURL)
|
||||
source = (try cachedMOBITextURL(text: document.text), document.title)
|
||||
} else {
|
||||
source = (bookURL, bookURL.deletingPathExtension().lastPathComponent)
|
||||
}
|
||||
let textBook = try builder.build(textFileURL: source.textURL, pageSize: pageSize, style: renderStyle)
|
||||
controller = RDEPUBReaderController(
|
||||
textBook: textBook,
|
||||
bookIdentifier: bookIdentifier,
|
||||
title: bookTitle,
|
||||
textFileURL: bookURL,
|
||||
title: source.title,
|
||||
textFileURL: source.textURL,
|
||||
configuration: epubConfiguration
|
||||
)
|
||||
} else {
|
||||
|
||||
let fallback = UIViewController()
|
||||
let textView = UITextView()
|
||||
textView.isEditable = false
|
||||
textView.text = rd_decodeTextFile(url: bookURL)
|
||||
fallback.view = textView
|
||||
controller = fallback
|
||||
} catch {
|
||||
controller = makeErrorController(error)
|
||||
}
|
||||
case nil:
|
||||
controller = makeErrorController(
|
||||
NSError(
|
||||
domain: "RDEpubReaderView.UnsupportedFormat",
|
||||
code: 1,
|
||||
userInfo: [NSLocalizedDescriptionKey: "不支持此文件格式"]
|
||||
)
|
||||
)
|
||||
}
|
||||
embeddedController = controller
|
||||
addChild(controller)
|
||||
@@ -213,8 +229,15 @@ public final class RDEpubURLReaderController: UIViewController {
|
||||
embeddedController as? RDEPUBReaderController
|
||||
}
|
||||
|
||||
private var cbzReaderController: RDCBZReaderController? {
|
||||
embeddedController as? RDCBZReaderController
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func performDemoPageNavigation(_ pageNumber: Int, animated: Bool) -> Bool {
|
||||
if let cbzReaderController {
|
||||
return cbzReaderController.goToPage(pageNumber, animated: animated)
|
||||
}
|
||||
guard let readerController else { return false }
|
||||
guard pageNumber > 0 else { return false }
|
||||
|
||||
@@ -451,18 +474,41 @@ public final class RDEpubURLReaderController: UIViewController {
|
||||
)
|
||||
}
|
||||
|
||||
private func rd_decodeTextFile(url: URL) -> String {
|
||||
if let content = try? NSString(contentsOf: url, encoding: String.Encoding.utf8.rawValue) as String {
|
||||
return content
|
||||
}
|
||||
if let content = try? NSString(contentsOf: url, encoding: 0x80000632) as String {
|
||||
return content
|
||||
}
|
||||
if let content = try? NSString(contentsOf: url, encoding: 0x80000631) as String {
|
||||
return content
|
||||
}
|
||||
return ""
|
||||
private func cachedMOBITextURL(text: String) throws -> URL {
|
||||
let attributes = try? FileManager.default.attributesOfItem(atPath: bookURL.path)
|
||||
let size = (attributes?[.size] as? NSNumber)?.uint64Value ?? 0
|
||||
let modified = (attributes?[.modificationDate] as? Date)?.timeIntervalSince1970 ?? 0
|
||||
let safeName = bookURL.deletingPathExtension().lastPathComponent
|
||||
.replacingOccurrences(of: #"[^A-Za-z0-9._-]"#, with: "_", options: .regularExpression)
|
||||
let base = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first
|
||||
?? FileManager.default.temporaryDirectory
|
||||
let directory = base.appendingPathComponent("ssreaderview-mobi", isDirectory: true)
|
||||
.appendingPathComponent("\(safeName)-\(size)-\(Int64(modified))", isDirectory: true)
|
||||
let textURL = directory.appendingPathComponent("content.txt")
|
||||
if FileManager.default.fileExists(atPath: textURL.path) { return textURL }
|
||||
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
|
||||
try Data(text.utf8).write(to: textURL, options: .atomic)
|
||||
return textURL
|
||||
}
|
||||
|
||||
private func makeErrorController(_ error: Error) -> UIViewController {
|
||||
let fallback = UIViewController()
|
||||
fallback.view.backgroundColor = .systemBackground
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
label.textColor = .secondaryLabel
|
||||
label.text = error.localizedDescription
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
fallback.view.addSubview(label)
|
||||
NSLayoutConstraint.activate([
|
||||
label.leadingAnchor.constraint(equalTo: fallback.view.leadingAnchor, constant: 24),
|
||||
label.trailingAnchor.constraint(equalTo: fallback.view.trailingAnchor, constant: -24),
|
||||
label.centerYAnchor.constraint(equalTo: fallback.view.centerYAnchor)
|
||||
])
|
||||
return fallback
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension RDEpubURLReaderController: RDEPUBReaderDelegate {
|
||||
|
||||
Reference in New Issue
Block a user