手里有个掌阅的阅读器(Smart XS,已停产停售),可以在阅读时划线,并将这部分内容封装成 EPUB 格式的笔记,本文主要关注如何拆解这种笔记文件,以及重新用 markdown 格式输出这些笔记。
Updated 20250804: 从目录读取笔记列表,避免乱序。
拆解 EPUB 文件
EPUB(Electronic Publication) 是常见的电子书格式1,完整的标准可以查阅EPUB 3.2 規格文件中文版。从“最小可用系统”的角度来讲,EPUB 文件是一个用 zip 方式压缩的文件夹,里面包含的是必要的元信息和 html 格式存储的文本内容,以及其他可选的多媒体内容(例如插图等)。
以这次要解析的笔记为例,手动解压后的目录结构是:
.
├── META-INF
│ └── container.xml
├── mimetype
└── OEBPS
├── chapter_0.html
├── chapter_1.html
├── chapter_2.html
├── chapter_3.html
├── chapter_4.html
├── chapter_5.html
├── chapter_6.html
├── chapter_7.html
├── chapter_8.html
├── content.opf
├── cover_2.png
├── cover.png
├── cover_thumbnail.png
├── item_1.xhtml
├── toc.ncx
├── zybooknote.css
└── zybooknote_icon_locate.png
目前需要关注的是这些文件:
OEBPS/toc.ncx
,包含了目录信息;OEBPS/chapter_*.html
,这就是阅读时划线的所有笔记,每章对应一个文件。
提取笔记
既然笔记都在 html 文件里,只要按顺序读取这些文件的内容,然后根据标签的提取对应信息即可:
- 章节标题在唯一一个
<h2>
标签内; - 每条笔记对应一个
class="zybooknote_summary"
的<p
标签。
功能实现
有一些细节需要关注:
- 既然 epub 本质是一个压缩文件,需要解压到一个临时的文件夹中,这里选择了在系统临时文件夹下建立一个随机名称的文件夹,当然在结束后也要记得清理这个文件夹。
- 以 linux 为例,临时文件夹就是
/tmp
目录; - 以 golang 为例,可以通过
os.TempDir()
方法获取系统的临时文件夹位置。
- 以 linux 为例,临时文件夹就是
- 为了让整体结构更清晰,引入笔记和笔记本两个结构体,其中:
- 笔记本对应整个掌阅生成的笔记文件,这个结构负责解压、获取文件列表、输出到目标文件、清理临时目录;
- 笔记对应一个具体的 html 文件,负责从文件读取笔记信息、按照 markdown 格式化输出。
- 用
demo -o <DEST_PATH> <EPUB_FILE>
这样的形式来指定输出的 markdown 文件和输入的笔记文件路径。
代码就不贴在这里了,有兴趣的朋友可以移步 notex-multi Review 代码(欢迎提 issue)。
总结
“So, what we learned from taday?”2
-
代码本身不复杂,更值得训练的是从框架层面设计流程,避免用 “面条式” 代码来实现,良好的结构有助于扩展(新功能)、迁移(到其他语言或者场景);
-
// TODO20250804 Done
目前没有用toc.ncx
中的内容来读取章节列表,而仅仅是通过获取文件列表的顺序,在目前使用中尚且算可用,但后续最好已经
修改为根据目录来查找文件; -
促使我写下上述文字的动力是 當代學生生存手冊 中的这段话,同时也强烈推荐这本书作者的博客 螺莉莉的数据中心。
“道理誰都懂,但是道理不能說服任何人。因為道理是空洞的結果,探索這些道理的過程才是智慧。我們需要的不是道理,我們需要的是智慧。 智慧是最重要的,所以最後我想用這句話,為今天的分享做一個結尾:不要停止思考。”