上一篇《一套书喂三台墨水屏:booklib 能帮你做什么》写于 10 月初。那时 booklib 的样子是:书放在自己的文件夹里,它照每台设备的脾气各生成一份"优化过的版本",放在书目录旁边,我再整个文件夹拷到 Kindle、掌阅、reMarkable Move 上。
三周过去,又提交了两百五十多次。回头再看那篇文章,有一小半已经不对了:有的功能推翻重做,有的删掉了,有的原本"做不到"后来做到了。这篇把这一个月的变化理一遍,重点讲为什么改。
先看一张对照表
| 10 月初 | 现在 | |
|---|---|---|
| 文字书 | 解开字体字号的锁、按中英文习惯排版、章节强制分页、注释搬到章末 | 只修复:修不合规的写法,文字、图片、样式一概不动;三台的显示照 Send to Kindle 统一 |
| Kindle 的格式 | AZW3,自己写的转换器 | KFX,又自己写了一个写出器;AZW3 整个删了 |
| 书怎么到设备上 | 生成到电脑上,自己拷 | sync 直接传,电脑上不留产物 |
| 跟踪范围 | 一个书目录,三台共用 | 每台设备各挑各的,目录和单本混着来 |
| 元数据 | 手动 meta --fetch,漫画跳过 | sync 自动补,漫画也补;书名、文件名改用网站上的书名 |
| 图片像素 | 只缩放,不动像素 | 掌阅、Move 上灰度的漫画、插图加深中间调 |
| 掌阅漫画翻页 | 一律从左往右(换整屏铺满) | 照书自己写的方向翻 |
下面一项项说。
最大的转向:文字书只修不改
上一篇里,文字书那一节写了六条"优化":解锁字号、按语言排版、章标题独立一页、注释搬到章末并缩小一号……这些现在全部默认关掉了。
起因是 10 月 8 日我自己定了一条更严的规矩:书里的任何一个文字、图片、格式、样式都不许动。理由想清楚以后其实很简单:那些"优化"每一条都有道理,但每一条也都在替作者和排版的人做决定。章节强制分页,有的书本来就是连排的;注释缩小一号,有的书注释本身就是正文的一部分;解开字号的锁,书里精心写的标题层级也跟着散了。与其一本本调,不如回到原点:书长什么样,就让它长什么样。
"只修复"不等于什么都不做。下面这些是 EPUB 规范层面的错误,修了看不出区别,但不修有的阅读器就打不开或者显示错:
- 内部文件不是合法 XML 的(标签没关、交叉嵌套),按 HTML5 的解析规则修好写回,字一个不改;
- 指向不存在文件的图片、字体引用去掉,重复的 id 改名,目录文件修正;
- 统一升级到 EPUB 3,目录至少索引到节;
- 书的语言标错了的改正(有本中文书标成英文,Kindle 就按英文排中文);
- Move 不认 WebP 图片,无损转成 PNG,像素一个不变。
代码里那些排版规则都还在,只是在设备配置里关掉了。以后哪天想开,改一个开关就行。
三台统一:以 Send to Kindle 为准
只修不改带来一个新问题:同一本书在三台上看起来不一样。阅读器各有各的怪癖,原书写的样式,有的阅读器认、有的不认。
我选了一个"裁判":亚马逊自己的 Send to Kindle。把原书推给它,它转出来的 KFX 就是亚马逊认为这本书在 Kindle 上该有的样子。我推了二十多本书过去,把 Amazon 转出来的结果一个属性一个属性地对,整理出一张规则表:段落缺省上下各空一行、标题多大、行高怎么算、左右边距怎么折、哪些颜色淡到看不清要加深……然后让三台都照这张表来:
- Kindle:我自己写的 KFX 写出器照这张表排;
- 掌阅、Move:在 EPUB 里只改看得出差别的那几项。这是"样式不动"唯一的例外:只改值、删声明,文字一个不碰。
"一致"要能量化,不能靠感觉。我给自己定了验收线:我们转的 KFX 和 Send to Kindle 转的,一致率 99.8% 以上;掌阅、Move 和 Kindle 的,99.5% 以上;插图页也算在内。比的是阅读器上实际显示出来的样子,不是 CSS 算出来的值。后来又加了一条:字体、字号这些读者可以自己调,最要紧的是版式,该居中的居中,该竖排的竖排,该有横线的有横线,合集的分册封面不多出一页。版式检查一处不一样就列出来,不打总分。
怪癖是一条条量出来的
"照 Kindle 显示"的前提,是先弄清另外两台到底怎么显示。为此我做了一套"怪癖测试书":每页测一种写法,自动在设备上逐页截屏,和 Kindle 对比。目前怪癖表里记了 87 条,都是验证过的。挑几条有意思的:
- 掌阅:不认
rem单位;写了!important的声明反而输给前面的普通声明;字号的pt当成px算;颜色的rgba()写法整条作废。 - Move:有两套 CSS 解析,外链样式表里的照标准来,行内样式里的
em却按另一个基准算;标题字号只认small到xx-large五个关键字,写1.75em它不理,最后只好把这种标题换成<div>;边框不画,内边距不认,上下边框只能插一张横线图来模拟。 - Kindle:竖直方向的距离按行距算,不按字号;显示出来的行高有下限,写得再小也不会低于正常的 0.744 倍。
每条怪癖都写成设备配置里的一个字段,代码里不写"如果是掌阅就怎样"。
Kindle:从 AZW3 换成 KFX
上一篇说我自己写了一个 EPUB → AZW3 转换器。它在 10 月 9 日被整个删掉了,换成了 KFX。
KFX 是 Kindle 现在主推的格式,Send to Kindle 推下来的就是它。比起 AZW3,它在 Kindle 自带阅读器里有注释弹窗、更好的排版,漫画也能写成固定版式整屏显示。问题是 KFX 没有官方文档。我只照 Amazon 公开的 Ion 数据格式规范,加上对样本文件的黑盒分析来写,没看任何现成转换工具的代码,连别人讲那些代码的文章也不看。
摸索的过程踩了不少坑,几条典型的:
- 书的唯一编号在文件里出现四处,必须一起改,只改一处封面就不显示;
- 图片资源的编号必须正好等于图片数据的编号加 9,差一点图片和书架缩略图就不显示,6 本样本无一例外;
- 中文书的语言起初照别人的经验写成英文(为了能调段间距),结果 Kindle 按英文规则排中文,上标会把整行往下推 20 像素;改回中文以后,测试页和 Amazon 转的逐像素一样。
写出器现在是第 24 版。几个后来补上的功能:有字的段落里嵌小图(生僻字图、图标不再单独占一行)、原书没有封面页的照 Amazon 补一页、透明 PNG 合成白底(Kindle 会把透明处显示成黑色)、动图 WebP 显示第一帧。
不用再拷文件夹了
上一篇的第三步是"自己拷到设备上"。现在没有这一步了:sync 发现哪台设备接着,就直接传上去,电脑上不留产物。

- Kindle、掌阅:USB 接上后,电脑自动把它们挂成普通文件夹,书放进
documents/<子目录>/。这里顺手修了挂载工具 jmtpfs 的两个毛病:在存储根目录建文件夹报错(它把根目录的父对象填成 0,安卓只认 0xFFFFFFFF);改名是整份下载再上传(作者把真改名注释掉了)。打了补丁以后,改名、挪目录成了设备上的真操作,一个 30MB 的文件只要几十毫秒。 - Move:经 SSH 调 Move 上书架服务的导入接口,书直接加入系统书库,多级子目录按层建成文件夹。Move 排一本大漫画要几分钟,所以导入改成异步任务,不挡别的设备。
- 增量:每本书每台设备记一个指纹,没变就不生成;规则升级后重新生成出来和设备上那份字节一样的,也不再传。
- 跟着删:原书删了、不再跟踪了,设备上传过去的那本跟着删(Move 上进回收站)。设备上你自己放的文件一概不碰。
最担心的是阅读进度。实测下来:Kindle、掌阅覆盖同名文件,进度都还在;Move 原地替换同一本书时会回到开头,书架服务后来加了"替换前记下位置、重开时跳回去"。原书换了目录,Kindle 上的进度文件夹也会跟着挪。
每台设备读不同的书
三台的用法其实不一样:漫画在彩屏的 Move 上看,大部头小说在 Kindle 上看。10 月 19 日起,每台设备可以有自己的跟踪范围,目录和单本混着来:
booklib track --device=xochitl --top 优秀漫画/哆啦A夢 侦探悬疑/欧美侦探/罗杰疑案
booklib track --device=ireader,kindle --top 科幻神话
booklib sync--top 的意思是"从这一层开始放":优秀漫画/哆啦A夢 在 Move 上就是根目录下一个「哆啦A夢」文件夹,不用先点进「优秀漫画」。路径不用写全,相对路径会到书根目录里找,扩展名也能省;fish 里按 Tab 能补全目录和书名。
元数据:书名也照网站的改
上一篇的封面和简介要手动 meta --fetch,漫画还跳过不找。现在的顺序是跟踪 → 补元数据 → 传设备,sync 生成之前自动给没找过的书找一次:
- 漫画先查 Bangumi;
- 豆瓣:搜索建议找不到的(漫画),再去书籍搜索页找;
- QQ 阅读:豆瓣没有的网文;
- Wikidata:找原作,再到 Open Library 找原版封面;都没有就生成一张。
找到以后,除了封面、简介、标签,还会补作者国籍、译者,以及出版社、出版日期、ISBN。后面三项只在豆瓣那个版本就是手上这本时才写:书名一致、译者也对得上。好读的台湾译本对上大陆版的条目,就不写。
书名和设备上的文件名也改用网站上的书名,卷次照书里的补上。哆啦A夢全彩版 - 卷01 变成 哆啦A梦 第01卷,波洛系列04:罗杰疑案 变成 罗杰疑案。这条规则昨天刚修过一个坑:《伊藤潤二愛藏版》书里的卷次写成「卷08 呻吟的排水管」,卷号后面还跟着卷名,规则认不出来,十本书都成了「伊藤潤二」,重名的只好加上 [4aed32] 这种后缀。现在卷名一起留着:伊藤潤二 第08卷 呻吟的排水管。
漫画:还是贴边,翻页照书
漫画的目标没变:不拉伸、居中、离屏幕边缘 1~2 像素。变了的有三处:
- 翻页方向照书:上一篇说掌阅上日漫一旦声明从右往左翻就铺不满,只好改成从左往右。后来查清楚,留边是掌阅「排版」设置给的,选「漫画」排版就铺满了,和书本身无关。所以现在三台都照书自己写的方向翻,代价是掌阅上每本要手动选一次排版。
- Move 的页边距不用手工登记:书架服务导入时看到书里的标记,自动把这本的页边距设成 1。
- 中间调加深:这是"图片只为适配屏幕缩放"这条底线唯一的例外。在 Move、掌阅上比了好几轮:彩页提对比度、锐化、加饱和度,都"没有明显区别";黑白页把中间调加深,"明显更好"。最后定下灰度漫画页按伽马 1.45 加深,文字书里的灰度插图按 1.3,纯黑、纯白两端不动。Kindle 当时没插上,还没比。
删掉和不做的
一个月里删的东西不比加的少:
- AZW3 写出器:被 KFX 取代,整个删了。
- KOReader:中间有几天 Kindle、掌阅开机直接进 KOReader,还搭了进度同步服务。最后还是回到三台都用自带阅读器,"原生简洁"。
- MOBI 词典转换:掌阅自带阅读器直接认 MOBI 词典,用不上了。
- 解 DRM:从"暂停"改成"不做",识别出 DRM 照旧拒收。
- 漫画章节目录:手上的漫画自带目录是一页一条,章名只印在图上,要做得手录或者认图,不做。
还有几件试过、做不到的:
- Kindle 上的书架文件夹:书在
documents/下照样分子目录,但 Kindle 书架不显示文件夹。它的"收藏夹"不越狱写不进去:真机上把能经 USB 看到的数据库翻了一遍,里面没有收藏夹。 - 掌阅书架多套一层「documents」:掌阅导入时把新文件夹挂在一个叫「documents」的分组下。改它的书架数据库能解决,但我最后决定不动。
- 三台同步阅读进度、英文自动断字:和上一篇一样,还是做不到。
一些数字
- 代码全是 Rust,约 5.4 万行,分成 6 个模块,674 个测试;
- 书库里 185 本:30 本文字书,155 卷漫画;
- 每改一条影响正文的规则,都拿全部真书回归一遍:新旧版本的可见文字逐字一致,目录不变,XHTML 合法。
最后
这一个月最大的体会是:规则会被推翻,所以每条都要记下来为什么。项目里有一份决定记录,按日期记着每个决定和当时的理由,被推翻的标"已改"、指向新的那条。"章节强制分页"是第一天定的,第十天推翻;"掌阅漫画一律往左翻"活了半个月;"KFX 不考虑"一周后就开始写 KFX 写出器了。有这份记录,推翻的时候知道推翻的是什么、当初为什么那样做,不会改着改着又绕回原地。
另一条没变:没在真机上看过,就不算完成。怪癖表里的 87 条,每一条都是在设备上截屏、量像素量出来的。
暂无评论