calibre-web使用过程中的一些记录

为了一直以来收集的大量电子书不用受制于本地,能够方便地在线阅读查看,于是便开始了这番折腾。

在本地我是使用calibre进行管理的。线上应用自然也选择了可以直接使用calibre书库的calibre-web。于是就在服务器上搭建了一套calibre-web系统。

但是calibre-web用起来,实感功能还是有些不足,有着不少的功能缺失和使用不便。可目前也没有其他更好的选择,好在calibre-web是开源的,会使用Python语言和Flask框架就可以直接自行修改了。接下来就是一边记录自己使用过程中感觉到的问题,一边试着看源码自己修改。

在线阅读的分片加载

首先,最为严重的问题就是在线阅读时的加载。calibre-web需要将整个文件完全下载完成才能开始渲染,这大大降低了使用体验,浪费了时间与服务器流量。这个问题需要第一个解决。

最开始,我还以为会是一个很麻烦的问题,所以才会这么久都没有加入这个功能。还想着是否是需要后端读文件一页页解析再发给前端,后来发现其实并没有这么复杂。

先查看源码,发现calibre-web的在线阅读功能基本就是直接调用解析对应格式文件的js库,那么问题就在于这些js库是怎么请求、读取、渲染文件的了。

先从使用最多的pdf格式开始,calibre-web使用了Mozilla的pdf.js来解析pdf文件。查看pdf.js的使用说明,发现其实pdf.js已经内置了这项功能,只需要调用时设置开启就行。在readpdf.html中加入disableRangedisableAutoFetch两个参数

    window.addEventListener('webviewerloaded', function() {
        PDFViewerApplicationOptions.set('disableAutoFetch', true);
        PDFViewerApplicationOptions.set('disableRange', true);
    });

disableRange 设置为true开启了范围请求加载,这样就可以分块获取数据。 disableAutoFetch 设置为true开启了数据的预读取,即使是不需要显示的页面,PDF.js也会自动继续获取更多数据。

这个功能使用的是HTTP的 Range requests范围请求,也就是常说的断点续传。

服务器通过响应头Accept-Ranges: bytes告知客服端支持Range requests,通过Content-Length告知文件大小。

客户端可以通过请求头Range发送一个范围,告知本次请求的是那一段数据。这样就可以分片获取数据了。

后端也需要开启这个功能。对于flask来说则是返回Responseaccept_ranges要设置为True。

从calibre-web的源码来看。传输pdf文件使用的是send_from_directory()函数,send_from_directory()调用send_file()函数,而send_file()conditional参数默认为True,也就是并不需要修改,已经默认开启了该功能。

此时再进入在线阅读,能看到已经可以分片加载了。再打开开发人员工具网络窗口,就会看到大量的状态码为206的请求,这就是分片了的pdf文件

接下来就是查看epub.js 等其他库的使用

字体缺失

使用过程中发现不少pdf文件文字不显示。打开控制台可以看到各种bcmap文件的404警告,这明显是缺少字体了。

calibre-web并没有携带这些字体。那就自行下载,放入相应的目录中。但从官方的pdf.js中提取好字体出来后。再一看,这个请求的地址也很有问题,/calibre-web/read/web/cmaps/这个url,calibre-web内根本就没有写路由。我的calibre-web是用nginx部署的,要解决这个问题的方法,我首先想到的是使用nginx转发,在原有的conf设置文件中加入一条配置。

    location /calibre-web/read/web {
                alias /pdfjs/web;
        }

但要完全解决这个问题还是要找到根源,这个url是在哪里被请求的。查看源码可以看到,这个路径实际上是pdf.js的cMapUrl默认值../web/cmaps/,这个路径在完整的pdf.js内是正确的,但calibre-web只包含了主要的js文件,并没有携带相应的字体,发送请求时的相对路径也不是相对于js文件,而是相对于pdf文件路径,这就导致了这个奇怪的url。

在readpdf.html中修改调用pdf.js的cMapUrl设置,由../web/cmaps/改到static下,把下载来的文件放到static对应文件夹内就解决问题了。

本地化翻译

calibre-web的中文翻译并不完整,还有些错误。

calibre-web使用的是Flask本地化最通用的库Flask_Babel 要修改翻译文本,首先运行下面的命令:

pybabel extract -F babel.cfg -k lazy_gettext -o messages.pot .
# 先收集需要翻译的文本到messages.pot文件

pybabel update -i messages.pot -d cps/translations -l zh_Hans_CN
# 生成中文对应的po文件

然后打开calibre-web/cps/translations/zh_Hans_CN/LC_MESSAGES/messages.po文件。 这个文件记录原文本与翻译的对应关系。内容是像下面这样的格式:

#: cps/about.py:43 cps/about.py:59
msgid "installed"
msgstr "已安装"

其中,#:表明字符串在源码出现的位置,msgid 是原英文文本,msgstr 是对应的翻译。在msgstr中填入中文翻译就可以了。 在这个文件中添加好缺失的文本,修改错误的文本再保存后,运行下面的命令就完成了中文翻译的修改。再重启calibre-web就能看到效果。

pybabel compile -d cps/translations
# 编译生成mo文件

新用户的语言设置固定是英文

注册第二个用户并登录时发现一个问题。注册邮件是英文的,新用户的默认语言也是英文的,必须要登录后进入设置页面进行设置,才能改成中文。这个太别扭了。

我认为合适的逻辑应该是在注册页面就能够选择页面的语言,注册所发送的邮件和新用户默认语言也应该跟随这个语言设置。

不过这个逻辑需要修改的地方比较多,页面上要加按钮,注册要传额外数据加额外判断。暂时就直接把ub.py中User类的语言属性locale = Column(String(2), default="en"),默认值由en改为zh_Hans_CN。

calibre-web还有其它例如不能批量操作、不能按isbn抓取元数据、抓取数据的豆瓣源早已失效等不少的问题,有时间再能力范围内慢慢修改吧。


发表评论


暂无评论

Top