Firefox 能抓、能存,就是交不出一个文件夹
#11 上那句「Firefox 的存储接口不太一样,不好移植」对了一半,而且指的是错的那一半:存储那一格原样可用,卡住的是把字节交到磁盘上那一步。
#11 要的是上架 Firefox。 仓库主人在 issue 上的判断是:「Firefox 系浏览器的数据存储接口不太一样, 没办法很容易地移植过去。」
查了浏览器兼容性数据之后,这个判断对了一半,而且指的是错的那一半。
最神圣的那条路,一行都不用改
| 用到的能力 | Chrome | Firefox |
|---|---|---|
| 浏览器内的私有文件系统(档案就存在这儿) | 86 | 111 |
| 在专用线程里原地读写它(写档案靠这个) | 102 | 111 |
| 改请求头的两条规则(没有它一张封面都抓不到) | 84–92 | 113 |
| 闹钟、下载、选文件夹导入 | — | 全有 |
| 后台的 service worker | 88 | ❌ 没有 |
| 离屏文档 | 109 | ❌ 没有 |
| 「选一个文件夹」那个接口 | 86 | ❌ 完全没实现 |
Firefox 能抓、能存,就是交不出一个文件夹。 存储那一格——也就是被点名的那一格——原样可用;卡住的是把字节交到用户磁盘上那一步。
这不是挑毛病。一个凭印象下的判断,指对了「有问题」而指错了「问题在哪」, 代价是这个功能被搁置了。而查清它只花了半天,办法是去读兼容性数据, 再在真的 Firefox 上把答不了的那几格量一遍。
Firefox 那边少一层,不是多一层
Chrome 的后台是个 service worker:那里没有网页环境,也起不了专用线程, 而写档案偏偏只能在专用线程里做——所以 Chrome 要先开一个「离屏文档」, 抓取跑在它里面。
Firefox 的后台本来就是一个页面,直接就能起专用线程。 所以那一层根本不需要:
| 后台是什么 | 抓取跑在哪 | |
|---|---|---|
| Chrome / Edge | service worker | 先开一个离屏文档 |
| Firefox | 事件页 | 就在后台自己身上 |
挑哪一条按能力挑,不按浏览器名字挑——「有没有离屏文档这个接口」。 按名字挑的话,某天谁改个名就静默走错分支,而走错的症状是「抓取根本起不来」。
导出交出一个 zip,而它是壳子,不是格式
没有「选文件夹」这个接口,Firefox 上的导出只能打成一个包下载。 而这件事有一句话必须说准:
这是一个 zip 壳子。解开之后里面就是标准的档案目录, 与 Chrome 导出的完全一样——搬回豆备、喂给解析器,用的都是解开后的那个文件夹。
说它是「Firefox 专用格式」,等于告诉用户你的数据被锁在一个浏览器上, 而这与这个项目的全部主张正好相反。所以那句话在三个地方一字不差地写着, 并且有一条测试钉住它背后的不变量:
Firefox 导出的 zip,解开之后与 Chrome 导出的目录逐字节相同。
它同时保证了两件事:跨浏览器搬得动,以及解开就能直接喂给命令行工具。
同一份实现,也要同一份输入次序
同一批 28 份档案,命令行与 Firefox 各导一次 NeoDB 包。内容逐条相同, 行序完全不同——保持原序逐行比,17420 行里对不上 27636 处。
两份都对。坏掉的是「同样的档案产出同样的字节」,而这个项目正是靠读 diff 确认「这次只改了该改的」。
成因不在解析逻辑(结论与顺序无关,有测试钉着),在喂进去的顺序: 命令行按档案编号升序,扩展按降序——因为档案选择器要把最新的排在最上面, 那是对的。产出的行序跟着插入顺序走,于是两边分了家。
这是「字节是什么意思只能有一份实现」的第三次,而这一次连实现都是同一份 ——整条流水线是逐字节抄过去的。分家的是喂给它的次序。所以那条规矩要再宽一格: 同一份实现,也要同一份输入次序,否则产出仍然会分叉,而且照样不报错。
顺带修掉的几件
- Firefox 上一条通知都发不出来。它对两个可选属性整条拒收, 而那句调用外面包着一个吞掉一切的 try/catch——于是每一条通知都静默失败。
- 导出能按「停下」了。近两万页的解析要跑很久,而在这之前没有出口。
- 自检页在 Chrome 上已经坏了一个月。它是在真浏览器里验存储的唯一量具, 而量具本身是坏的——后面「完整的档案写入与崩溃恢复」那一项从来没跑过。 它在打包名单里,却没有任何测试进去过。
- 上游那个 zip 写入器的两个缺陷:中文文件名在 Linux 上乱码,以及解出来的文件读不了。 后者是三个常用的检查命令都发现不了的——它们都不往磁盘上写。
还剩一件,只有档案主人能做
自检页在真 Firefox 上跑通了,导出、导入、跨浏览器搬运都对着真实档案走过一遍。 Gecko 那一侧只剩一个行为性未知:后台事件页扛不扛得住一场几小时的真实抓取。 那要真跑一次,探针答不了。