Moth 书就在文件夹里,我只想打开它
最近我新完成并开源了一个新的自托管阅读器:Moth
项目地址:https://github.com/pzweuj/moth
它支持 EPUB、TXT、CBZ 和经典 MOBI,可以保存阅读进度,手机端可以直接作为 PWA 安装使用。
如果只看这段介绍,Moth 似乎并没有什么特别的。
毕竟现在已经有很多成熟的自托管阅读方案,例如 Kavita、Komga、TaleBook。它们拥有更丰富的功能、更完善的元数据管理、更复杂的书库系统,有些还支持 OPDS、多用户、在线书源、自动刮削、Kobo、Kindle 等能力。
所以问题来了:
为什么还要再做一个阅读器?
答案恰恰是:
因为它们做得太多了。
我只是想打开一本书
我最开始的需求其实非常简单。
我的NAS 上已经有整理好的书了:
books/
├── 小说/
│ ├── 三体/
│ │ ├── 01.epub
│ │ ├── 02.epub
│ │ └── 03.epub
│ └── 基地/
│ ├── 01.txt
│ └── 02.txt
└── 漫画/
└── 漩涡/
└── 01.cbz
我已经知道这些是什么书。
文件名是我自己起的。
目录也是我自己整理的。
我不需要软件告诉我:
- 作者是谁;
- 出版社是什么;
- 豆瓣评分多少;
- 应该配哪张封面;
- 这本书属于什么标签;
- 它应该被归到哪个 Collection;
- 这一卷到底是不是某个 Series 的 Volume 3。
我甚至不希望它移动、复制或者修改这些文件。
我只需要:
打开浏览器,找到这本书,然后继续昨天没看完的地方。
这最终成为了 Moth 最核心的一句话:
书放在文件夹里,Moth 负责打开它。
Moth 不是 Library Server
这是 Moth 最核心的设计。
我把 Moth 定义为:
Filesystem Reader,而不是 Library Server。
传统的自托管阅读软件通常会在你的文件系统之上重新建立一个“图书馆”。
大致是:
文件
↓
扫描
↓
识别
↓
Metadata
↓
Series / Author / Volume / Tag
↓
Library
↓
阅读
而 Moth 的流程更接近:
文件系统
↓
索引
↓
打开
↓
阅读
↓
保存进度
Moth 不试图重新解释你的书库。
你的文件系统,本身就是书库。
Kavita、Komga、TaleBook 和 Moth 到底有什么区别?
这几款软件其实并不存在简单的“谁比谁好”。
它们解决的是不同的问题。
我更愿意把它们理解成四种不同的产品哲学。
| 项目 | 核心定位 | 它想解决的问题 |
|---|---|---|
| Komga | 漫画/图书媒体服务器 | 如何管理好我的漫画收藏 |
| Kavita | 数字图书馆 | 如何建立一个功能完整的私人阅读平台 |
| TaleBook | 电子书管理系统 | 如何获取、整理、管理电子书 |
| Moth | 文件阅读器 | 我已经有书了,怎么简单地读它 |
差别看似只是功能多少,实际上是:
软件到底应该替用户管理多少东西。
Komga:我想管理我的漫画收藏
Komga 很像漫画世界里的 Plex。
它非常适合拥有大量 CBZ、CBR、EPUB 或漫画资源的用户。
对于这样的用户:
500 GB 漫画
几百个 Series
几千本单行本
Series、Volume、阅读顺序、左右翻页、双页、Webtoon、OPDS、KOReader、Kobo 等能力都有实际意义。
他们的需求是:
我的收藏本来就很复杂,所以我需要一个强大的媒体服务器来管理它。
这种情况下,Komga 的复杂度是有价值的。
Kavita:我想建立自己的数字图书馆
Kavita 更进一步。
它并不仅仅是一个 Reader,而是一个完整的 Library System。
你可以拥有:
用户 A
├── 阅读进度
├── 权限
└── 阅读偏好
用户 B
├── 阅读进度
├── 权限
└── 阅读偏好
再加上:
- Collections
- Reading Lists
- Tags
- Filters
- Metadata
- 多用户
- 权限控制
- OPDS
- 各种第三方客户端
如果你的目标是:
在家里的 NAS 上建立一个属于全家的私人 Kindle / 漫画站。
Kavita 非常合理。
它解决的是“数字图书馆”问题。
TaleBook:我想管理自己的电子书
TaleBook 又是另外一种思路。
它和 Calibre 的关系非常深。
在这个体系里,一本书不只是一个:
xxx.epub
而是:
书名
作者
出版社
封面
简介
ISBN
格式
标签
……
TaleBook 还可以进一步完成:
下载
↓
导入
↓
获取 Metadata
↓
整理
↓
格式转换
↓
推送
↓
阅读
尤其对于中文电子书用户,它提供了很多很实用的能力。
这非常适合一种我很熟悉的用户:
电子书收藏党。
他们不只喜欢读书,也喜欢:
收书、整理书、补封面、修作者、转格式、分类、维护书库。
对于这种用户来说,这些都不是负担,而是乐趣。
然后是 Moth
Moth 面对的是另外一种人。
他的书早就整理好了:
/books
├── 小说
│ ├── 金庸
│ ├── 刘慈欣
│ └── 阿西莫夫
└── 漫画
├── 伊藤润二
└── 龙珠
他看到 Metadata Scraper 的第一反应不是:
太好了!
而可能是:
我为什么需要这个?
他不需要第二套分类。
不需要第二套 Metadata。
不需要第二套文件管理体系。
因为在他看来:
目录就是分类。
这就是 Moth。
文件系统就是配置
Moth 有一个贯穿整个项目的原则:
Filesystem First
例如:
books/
├── 小说/
│ └── 三体/
└── 漫画/
└── 龙珠/
一级目录就是书架。
二级目录就是系列。
文件就是书。
Moth 不需要你进入后台:
创建书架
→ 填写名称
→ 选择类型
→ 保存
→ 导入
→ 设置 Series
你在文件系统里建立目录,它就已经存在了。
甚至 Moth 的“更多书架”也是类似思路。
如果某个书架不希望长期显示在主页,只需要在对应目录放一个:
hide
文件。
不需要后台设置。
不需要新的数据库表。
不需要“书架显示状态管理系统”。
文件系统本身就是配置文件。
不刮削,是功能
这是 Moth 一个很容易被误解的地方。
Moth:
- 不抓豆瓣;
- 不抓作者;
- 不抓出版社;
- 不获取在线封面;
- 不自动整理;
- 不移动文件;
- 不修改文件名;
- 不建立复杂标签体系。
听起来似乎都是:
“缺少的功能。”
但对 Moth 来说不是。
这是设计目标。
因为每增加一层自动化,就会增加一层状态。
比如 Metadata Scraper 看起来只是一个很普通的功能。
但是一旦开始做,就会自然产生:
Metadata
↓
匹配
↓
匹配错了怎么办?
↓
手动编辑
↓
封面管理
↓
作者管理
↓
标签
↓
冲突解决
↓
重新刮削
↓
Metadata 数据库
一个 Reader 很快就开始变成 Library Manager。
而 Moth 不想成为 Library Manager。
不做离线模式,也是设计选择
PWA 很容易让人联想到另一件事情:
能不能把书下载到手机里,断网继续阅读?
Moth 没有做。
这并不是因为 PWA 无法实现离线缓存,而是因为它和 Moth 的使用模型并不一致。
Moth 的内容来自你的 NAS。
当你完全无法访问 NAS 时,本质上你也已经无法访问 NAS 上的文件。
Moth 只是这个文件系统的一个阅读入口,它没有试图再在手机上维护一份独立的离线书库。
也就是说,Moth 的逻辑始终保持一致:
NAS 在线
↓
文件可访问
↓
Moth 可阅读
如果需要在外网使用,可以通过 VPN、Tailscale、Cloudflare Tunnel、反向代理等方式访问自己的 NAS。
如果真正需要长期离线阅读,那么最直接的方式仍然是:
把那个 EPUB、MOBI、TXT 或 CBZ 文件复制到离线设备上。
Moth 不想在服务器书库之外,再创造一个“PWA 本地书库”,然后开始处理:
- 哪些书已经下载;
- 哪个版本更新了;
- 缓存什么时候失效;
- 阅读进度如何双向合并;
- 本地存储不够怎么办;
- 浏览器清理缓存之后怎么办。
这些当然都可以做。
但它们解决的是另一个问题。
Moth 选择不解决。
单用户,也是功能
Moth 从设计上就是:
Single User
它没有复杂的:
User
Role
Permission
Library ACL
Parental Control
Sharing
因为我对电子书有一个很简单的理解:
书籍可以分享,但阅读路径是个人的。
如果我要把《三体》分享给另外一个人,我真正应该分享的是:
三体.epub
而不是:
“给你一个我的 Moth 账号,你登录以后从我的书架里看。”
文件是可以复制、发送和拥有的。
但下面这些东西:
- 我读到哪一页;
- 哪本书正在读;
- 哪些书已经读完;
- 我喜欢什么字号;
- 我使用什么主题;
- 我习惯单页还是双页;
本质上都是个人状态。
所以 Moth 不试图成为一个“大家登录同一个阅读网站”的平台。
每个人完全可以:
自己的文件
+
自己的 Moth
+
自己的阅读进度
如果真的要分享一本书:
分享文件,而不是分享阅读路径。
这也是为什么 Moth 的单用户并不是“以后再补”的功能缺口,而是一个有意保留的边界。
如果你的目标是给全家或者一群朋友建立公共数字图书馆,那么 Kavita 显然更适合。
PWA,而不是再开发三个客户端
Moth 同样没有:
- Android App;
- iOS App;
- Windows 客户端;
- macOS 客户端。
它只有:
Web。
手机浏览器打开之后,可以直接安装成 PWA。
于是:
桌面
↓
浏览器
手机
↓
PWA
使用的是同一套应用。
阅读进度保存在服务器。
所以我可以:
晚上:
电脑
↓
看到 43%
第二天:
手机
↓
继续 43%
对于一个私人、自托管、单用户的软件来说,我认为已经足够。
四种格式,四条简单的阅读链路
Moth 目前只关心四种格式:
EPUB
直接阅读。
使用 EPUB 本身的章节结构,并保存精确阅读位置。
TXT
这是我比较重视的一种格式。
中文网络小说里仍然存在大量 TXT:
第一章
第二章
第三章
……
Moth 会检测文本编码、识别中文章节,并建立章节索引。
TXT 不需要先手工转换成 EPUB。
直接打开即可。
CBZ
CBZ 本质上就是图片压缩包。
Moth 提供:
- 单页;
- 双页;
- 连续滚动;
- LTR;
- RTL。
对于我自己的漫画阅读需求已经足够。
MOBI
经典无 DRM MOBI 在第一次打开时转换成 EPUB 缓存。
原始 MOBI:
不会被修改。
之后直接复用转换结果。
也就是说 Moth 把 MOBI 当成:
输入格式
而不是再重新实现一套 MOBI Web Reader。
Moth 很小
极简设计带来的一个很直接的结果就是:
资源占用非常低。
目前参考环境下:
| 项目 | 规模 |
|---|---|
| Docker Image | < 30 MB |
| 解包后的运行时 | < 150 MB |
| 静息内存 | 约 5 MB |
| 阅读时内存 | 约 50 MB |
实际数字当然会根据平台、书库和阅读内容变化。
但这基本表达了 Moth 的设计目标:
把它丢进 NAS,然后忘掉它。
对于一台已经跑着:
Jellyfin
Immich
Vaultwarden
FreshRSS
Gitea
Home Assistant
……
的 HomeLab 来说,我并不希望一个“打开小说”的服务再占掉大量资源。
Moth 应该只是安静地待在那里。
/books 甚至可以只读挂载
我很喜欢这一点。
Docker 部署时,书库可以直接:
volumes:
- ./data:/data
- /你的书库:/books:ro
注意最后的:
:ro
Moth 根本没有必要拥有修改书库的权限。
原始文件属于用户。
Moth 只在自己的 /data 中保存:
- SQLite;
- 阅读进度;
- 索引;
- 封面缓存;
- 派生缓存。
于是即使有一天:
rm -rf data/
你的书仍然全部在那里。
因为:
Moth 的数据库不是你的书库。
你的文件系统才是。
哪些人可能会喜欢 Moth?
我觉得至少有三类。
1. NAS 用户
已经有自己的电子书目录,只需要一个浏览器阅读入口。
2. HomeLab 极简主义者
服务器已经跑了很多东西。
看到一个新项目首先关心的是:
占多少 RAM?
镜像多大?
要几个容器?
要不要 Redis?
要不要 PostgreSQL?
Moth 对这类人的答案基本就是:
一个容器,挂两个目录,然后读书。
3. Filesystem Purist
还有一种人可能尤其喜欢 Moth。
他们相信:
文件系统就是最可靠的数据库之一。
他的书库:
小说/
├── 刘慈欣/
├── 金庸/
└── 阿西莫夫/
已经整理得非常漂亮。
他不希望软件重新告诉他:
刘慈欣属于:
科幻 / 中国文学 / 长篇 / 获奖作品……
他只想:
小说
↓
刘慈欣
↓
三体
↓
打开
Moth 非常适合这种人。
哪些人不应该使用 Moth?
这一点同样重要。
如果你需要:
- 多用户;
- OPDS;
- Kobo / KOReader;
- 自动刮削 Metadata;
- 自动整理文件;
- 在线书源;
- 作者管理;
- 标签;
- 推荐;
- 上传;
- 离线书库;
- 强大的漫画收藏管理;
那么:
不要因为 Moth 更轻就选择 Moth。
Komga、Kavita、TaleBook 可能明显更适合你。
Moth 的目标从来不是:
用更少的资源实现 Kavita。
而是:
解决一个更小的问题。
少,不等于简陋
软件很容易走上一条路线:
用户提出需求
↓
添加功能
↓
又出现新的使用场景
↓
再添加功能
↓
配置越来越多
↓
维护成本越来越高
最后我们会得到一个功能非常强大的平台。
这种软件当然有它存在的意义。
但另外一种软件同样应该存在:
它知道什么时候应该停止。
Moth 希望成为后一种。
未来当然还会修 Bug。
会改善兼容性。
会处理更多奇怪的 EPUB、TXT、MOBI 和 CBZ。
会改善不同浏览器和 PWA 的体验。
会继续优化性能。
但是很多 Feature Request 的答案可能仍然会是:
No。
不是因为不会做。
而是因为不应该做。
Moth 和其他软件最大的区别
如果一定要用一句话概括这四个项目:
Komga:我要管理我的漫画收藏。
Kavita:我要建立自己的数字图书馆。
TaleBook:我要获取、整理和管理电子书。
而 Moth 是:
我已经有书了,让我读。
这就是它存在的理由。
最后
我很喜欢现在 Moth 的结构:
目录就是分类
文件就是书
浏览器就是客户端
SQLite 只保存状态
服务器只负责打开
它没有试图解决电子书世界里的所有问题。
也没有准备成为一个“下一代综合数字内容管理平台”。
它只做一件事情:
书放在文件夹里,Moth 负责打开它。
如果这恰好也是你想要的东西,可以试试看。