跳到正文
VK-Sight
/archives/booklib-evolution.html

三台墨水屏一个月后:booklib 从"帮书排版"到"只修不改"

目录

上一篇《一套书喂三台墨水屏: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 生成之前自动给没找过的书找一次:

  1. 漫画先查 Bangumi;
  2. 豆瓣:搜索建议找不到的(漫画),再去书籍搜索页找;
  3. QQ 阅读:豆瓣没有的网文;
  4. 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 条,每一条都是在设备上截屏、量像素量出来的。

暂无评论

添加新评论