Administrator
发布于 2026-09-05 / 5 阅读
0

4核4G的破服务器上,我又搭了个个人书库

起因:念头一冒,就收不住

上回在博客里折腾 Qwen2.5-3B 把这台腾讯云 CVM 折腾完,过了几天它又开始"游手好闲"——4核4G/40G 的小机器,CPU 占用常年 5% 以下。我盯着监控盯出了灵感:要不,再让它干点活?

活儿很快想到了:个人书库。需求很朴素——我从初中开始零散买的纸质书,搬家丢了三次,现在家里一本不剩;而我又舍不得一年花两三百块在京东读书上开会员(虽然已经在用,但总惦记能存一本"自己的")。再加上今年开始带娃,绘本、科普、童书需求量陡增,与其每次现搜,不如自己攒一个。

脑子里第一个冒出来的念头是:"让小布自动去爬。" 我第一反应是——不行。盗版资源站上的书 90% 是近五年内的出版物,扫一本就侵权一本;就是公版书里(Project Gutenberg 那类老古董),也只有作者去世满 50 年以上的才是真正"公版"。能合法采集的,其实只有那一小撮老东西。

好,那就老实一点:先收目录、按需下载,手机上看。不要 APP,要原生支持 OPDS 协议的应用——这是开源阅读器的通用钩子,一套服务端能挂 N 个客户端。

选型:先扫一遍战场

提问:京东读书 APP 能接入吗?

答:不能。京东、微信读书这类是封闭生态,只认自家的书城,第三方书库一概不接。

那就只剩开源阅读器这条路了:

  • Legado(阅读)——国产之光,UI 漂亮,OPDS 书源丰富;
  • Anx Reader——比 Legado 更新更勤,UI 现代,自带 WebDAV;
  • KOReader——主攻 Kindle/电子墨水屏,手机端不算强项;
  • Librera Pro——老牌俄罗斯老哥,OPDS 配置简单;
  • KyBook(iOS)——iPhone 上的选择,但需要收点小钱。

广告:以上全部开源免费,无广告,无内购。京东、微信读书里买过的书无法导入(DRM 锁死),这是行业惯例,没办法。

手机里现有的书(PDF/EPUB)能直接拖进任何一款。挑哪个主要看眼缘。我自己选 Legado——名字好听("拾遗"),社区活跃。

服务端选 Calibre-Web + OPDS:这是开源电子书管理的事实标准,原版 Calibre-Web 长这样,国内有个中文 forkTaleBooktalebook/talebook:latest),后台汉化、对中文书名/作者排序做了适配、首字符兼容,对中文用户更友好。Docker 部署几分钟搞定。

路线图敲定:TaleBook 服务端 + OPDS 公开 + Legado/Anx 客户端订阅,开干。

部署:TaleBook 起手式

服务器 IP 还是那位老朋友 106.53.178.213,Caddy 已经把 80/443 站得稳稳的;书库另开一个端口跑 TaleBook:

docker run -d --name talebook --restart unless-stopped \
  -p 8080:8080 \
  -v /opt/blog/talebook:/data \
  -e HALO_ADMIN_USERNAME=admin \
  -e TALebook_USER_CREATE_ADMIN=1 \
  talebook/talebook:latest

HALO_* 那是 Halo 博客的环境变量;TaleBook 镜像里我用了一个老的环境变量 TALEBOOK_USER_CREATE_ADMIN=1(新版可能改名了,按自己镜像版的 README 来)。容器起来 5 秒,浏览器开 http://106.53.178.213:8080,初始化管理员,登录,注册个普通账号留着给手机用。

然后采集公版书。Project Gutenberg 中文区用 gutendex.com 这个社区维护的镜像,API 干净。注意一个坑:必须带 User-Agent,不然返回 403。

import requests, time
UA = {"User-Agent": "tale-book-fetcher/1.0 (mailto:21899412@qq.com)"}
url = "https://gutendex.com/books?languages=zh&page=1"
# 翻页拉元数据,下载 epub

最后用 TaleBook 自带的 calibredb 把书塞进库:

docker exec talebook calibredb add --duplicates --library-path /data/books/library /tmp/zh_001.epub

443 本中文公版书,灌进 /data/books/library/。Web 端书架上终于不是 10 本书了,网页显示 455 本(中间手动加了一本《随身带着星际争霸》凑数)。

移动端:第一关就栽了

书上架了,下一步装客户端。

Legado:打开 GitHub releases,404——这货作者早在三年前就停止更新了,最后一版还停留在 release 页面找不到的尴尬境地。再换一个。

Anx Reader(v1.14.0):通过 ghfast.top 镜像拿到 APK,安装没毛病。配 WebDAV——故事从这里开始。

坑一:Anx 填完 WebDAV 地址提示「链接失败」。

排查:TaleBook 默认没开 WebDAV,需要在容器内的 /data/books/settings/auto.py 里把 WEBDAV_SYNC_FOLDER 打开(同步目录名设个 anx),重启。还要 chown talebook:talebook /data/anx,不然权限 403。

坑二:链接上了,但目录一片空

排查:直接 curl -X PROPFIND http://106.53.178.213:8080/books/anx 测,返回 HTTP 500。翻 TaleBook 源码:内嵌的 wsgidav 升级后,多了个 fs_opts 属性,新版代码没初始化。给 /var/www/talebook/webserver/webdav/dav_provider.pyMyBooksDavProvider.__init__ 加一行 self.fs_opts = {},重启,207 正常。

坑三:链接通了,目录也有了,但书架还是空的——只有我从手机导进去的《随身带着星际争霸》。

排查:我把 443 本书复制到了 /opt/books/data/anx/1/,但 Anx 只认 /anx/data/file/ 这一层。移动到正确路径,443 本书全部出现。

到这里我都觉得自己要赢了。然后,第二天打开 Anx,书架又空了——只剩 178 本。

ls /anx/data/file/ | wc -l
# 178

真相大白:Anx 的 WebDAV 是设备同步协议,不是书库协议。每次连接它会反向同步:服务器上有但本机没的,本机去下;本机有但服务器没注册的,本机去。我没在 TaleBook 里注册过那些 epub,所以 265 本被判定为"孤儿",删除。

当晚把 443 本书全部导入 TaleBook(calibredb add 注册到元数据库),问题终于稳定下来。但 Anx 这个机制太坑了——新书还没来得及在 TaleBook 后台点"登记",手机一连就给你删掉。

临时结论:Anx 不是 WebDAV 书库客户端,是 WebDAV 同步客户端。不适合当主力阅读器

补救方案:转 Librera + OPDS——Librera 通过 OPDS 协议从 TaleBook 拉目录(不走 WebDAV),下载到本地只读,绝不删服务器上的东西。验证:OPDS 地址 http://106.53.178.213:8080/opds/,Basic 认证用注册的普通账号密码,50 本/页分页加载,书目录正常,下书正常,进度不丢。Librera 拿来当 OPDS 备份方案

Anx 不删了,但留着作为网页 WebDAV 直连工具——需要从服务器取某个文件时,用 Anx 登上去点对点下载,临时用。

恍然大悟:官方早就有客户端

Librera 用了一周,舒服是舒服,就是两个不爽:
1. 进度不同步:手机上看一半的进度,电脑打开要重新翻页;
2. 没有推送:书库更新了,得手动进 OPDS 刷新。

某天深夜我盯着 TaleBook 项目页发呆,忽然意识到——TaleBook 项目官方客户端,不就是 Moke 吗(中文叫"墨客")。

我去翻了仓库:talebook/moke,Windows / macOS / Linux / Android / iOS 全平台都有 APK 直链。Android v1.1.3 才发布几天,GitHub 上个月还在持续迭代。完全对接 TaleBook 后端——登录、搜索、下载、离线、进度同步、划线笔记,一条龙。

当晚就去拉 APK。

坑四:APK 装不上,提示「解析错误」。

排查:unzip -t Moke.apk,报 End-of-central-directory signature not found——文件被截断了。回头看 ls -la 文件大小只有 35MB,而真实文件是 198MBghfast.top 这个 GitHub 镜像代理对大文件偶尔会中途断流,下载没报错,但只传了一半。

修:换其他镜像,重下,unzip -t 校验通过(文件末尾 D30B 0000——ZIP 结束标志),198MB 正常大小,arm64+armeabi 双架构都齐。

教训:从镜像下 APK,下载完务必 unzip -t 校验,长度对的不一定是完整的。

APK 重下,安装成功。Moke 登录服务器(http://106.53.178.213:8080,账号密码和网页版一致),455 本书全在,搜索秒出,在线/离线阅读一气呵成,进度、划线全部回写到 TaleBook 数据库。

这才是终局方案。

顺手提的功能建议

Moke 用起来唯一的不爽:进入阅读自动隐藏状态栏,沉浸式全屏。荣耀手机挖孔屏本来就小,再把状态栏藏了,看时间还得从顶部往下滑,挺别扭。手机系统设置(设置→显示和亮度→更多显示设置→应用全屏显示)也管不了 Moke——它走 edge-to-edge 的路子,系统级开关对它无效。

我去翻了 Moke 源码:从 v1.0.0 到 v1.1.3 安卓端的 MainActivity.kt 都是同一个写法——enableEdgeToEdge() 写死,没有全屏开关。但是上游 Readest 阅读器(Moke 嵌的就是它)其实有这个能力——系统设置里有个 alwaysShowStatusBar(默认 false),控制 systemUIVisible 是否常显。入口在 Readest 书库设置菜单,叫 "Always Show Status Bar",isMobileApp 时显示**。

只是 Moke 的 UI 层没有把这个入口暴露出来

我没有 GitHub 账号(网站打不开),于是从 Moke 项目公开的提交记录里翻到了主要开发者的邮箱 shangzhen0831@163.com,通过代理邮箱把这条建议连同源码定位一起发了过去。看作者回复速度吧,开源作者看邮件频率不定,没回也正常。

收官与版本号

最终阵容:

角色 软件 作用
服务端 TaleBook(talebook/talebook:latest 书目管理、OPDS、用户、Web 阅读
公版书源 Project Gutenberg + gutendex API 443 本中文公版 + 手动 12 本
安卓主力 Moke v1.1.3(官方客户端) 登录即同步、离线、进度回写
安卓备份 Librera Pro(OPDS) 应急,能浏览目录但不同步进度
安卓辅具 Anx Reader(WebDAV) 只用「网页→WebDAV 直连」功能取文件
APK 分发 Caddy /apk/* 服务器直链,国内下载免代理

占用:TaleBook 容器约 250M 内存,书库本身 1.2G(epub 体积小),磁盘总用量比预想的少——40G 盘至今只用 22G。

服务清单:
- http://106.53.178.213 → "进哥小院"博客(Halo)
- http://106.53.178.213:8080 → 个人书库(TaleBook)
- http://106.53.178.213/apk/Moke-1.1.3-android.apk → Moke 安卓 APK
- http://106.53.213/apk/Librera-9.5.7-arm64.apk → Librera 备份
- http://106.53.213/apk/AnxReader-1.14.0.apk → Anx 备用

进哥小院现在的模样:博客里聊技术、书库里装古今。4核4G 的小机器,又多了一个正经活儿。