- 给全部 78 个 Swift 源文件添加详细的中文注释(文件级、类级、方法级) - 删除 LegacyRDReaderController/ 死代码目录(16 文件 4592 行) - 根目录翻页容器文件移入 ReaderView/ 目录 - Resources/ 移入 EPUBCore/Resources/(与使用者归属一致) - RDEPUBTextIndexTable.swift 移入 EPUBTextRendering/(消除反向依赖) - RDURLReaderController.swift 移入 EPUBUI/(入口控制器归入 UI 层) - 更新 podspec 资源路径
46 lines
1.9 KiB
Swift
46 lines
1.9 KiB
Swift
// RDEPUBParser+ReadingProfile.swift
|
||
// EPUB 阅读配置文件判断
|
||
// 根据 metadata 的 layout 属性和 manifest/spine 内容,
|
||
// 将出版物分类为 webFixedLayout(固定版式)、webInteractive(含脚本/多媒体)或 textReflowable(纯文本重排)。
|
||
|
||
import Foundation
|
||
|
||
extension RDEPUBParser {
|
||
/// 判断出版物的阅读配置文件
|
||
/// 优先判断固定版式,其次检测交互内容(脚本/iframe/视频等),默认为文本重排
|
||
public func readingProfile() -> RDEPUBReadingProfile {
|
||
if metadata.layout == .fixed {
|
||
return .webFixedLayout
|
||
}
|
||
return hasInteractiveContent() ? .webInteractive : .textReflowable
|
||
}
|
||
|
||
/// 检测出版物是否包含交互内容
|
||
/// 通过 manifest 中的脚本媒体类型和 "scripted" 属性,
|
||
/// 以及扫描 HTML 中的 script/iframe/video/audio/canvas/svg/form 等标签
|
||
public func hasInteractiveContent() -> Bool {
|
||
let interactiveMediaTypes = [
|
||
"application/javascript",
|
||
"text/javascript",
|
||
"application/ecmascript"
|
||
]
|
||
if manifest.values.contains(where: { item in
|
||
interactiveMediaTypes.contains(item.mediaType.lowercased()) || item.properties.contains("scripted")
|
||
}) {
|
||
return true
|
||
}
|
||
|
||
let interactivePattern = #"<(script|iframe|video|audio|canvas|svg|form)\b|\bon(load|click|touchstart|touchend|mouseover)=|hype_generated_script|swiper|webview"#
|
||
for item in spine where item.linear && (item.mediaType.contains("html") || item.mediaType.contains("xhtml")) {
|
||
guard let html = htmlString(forRelativePath: item.href) else {
|
||
continue
|
||
}
|
||
if html.range(of: interactivePattern, options: [.regularExpression, .caseInsensitive]) != nil {
|
||
return true
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
}
|