用Readeck和KOReader在电纸书上稍后阅读网页
可能出于对自己阅读兴趣的自信,又或者真的需要大量读小说/专业书籍/盗版or正版电子书,总之你购买了一个电纸书(E-Ink阅读器)。
问题在于,日常生活、网上冲浪时,大量信息并不是一份独立、完善的「书籍」,而是一篇篇网页文章,散落在互联网上。电纸书针对「书籍阅读」开发,难以应对这种松散场景。因此,我们需要一些开源软件的帮助:稍后阅读软件「Readeck」和一个阅读软件「KOReader」。
1. 搭建Readeck
首先,我们需要把散落的文章收集汇总到一处。
为了方便手机收集文章,最好是在一个有公网IP/域名的设备上运行Readeck。
假设现在已经有了一个IP地址为 114.514.191.180
的Linux服务器,只需要按官方手册指南下载二进制安装即可:
首先创建文件夹:
mkdir -p readeck-install
cd readeck-install
从这里下载最新的分发文件,记得把链接替换一下:
wget -O readeck https://codeberg.org/readeck/readeck/releases/download/0.19.2/readeck-0.19.2-linux-amd64
chmod a+x readeck
由于readeck默认不是后台模式,用 screen
新建一个进程页面:
screen -S readeck
./readeck serve
然后可以按 Ctrl+c
数次退出,并编辑 config.toml
(可以用nano直接 nano config.toml
),修改下面部分:
[server]
host = 127.0.0.1
port = 8000
为
[server]
host = 0.0.0.0
port = 8000
并把服务器防火墙的 8000
端口放行。
再运行 ./readeck serve
之后按 Ctrl+a Ctrl+d
,将screen放回后台。这样一来,你就可以通过网页访问搭建的Readeck了。
2. 配置readeck
访问服务器对应端口(示例为 http://114.514.191.180:8000
),会要求你进行初次用户注册。
注册之后,我们可以参考少数派的这篇文章设置浏览器扩展、iOS快捷方式。
根据我的测试,浏览器扩展可以根据当前页面内容较好提取文章,即使你用的网页翻译软件,也可以把翻译结果保存下来。
配置readeck浏览器插件?实际上根本不需要怎么介绍吧。
选项 | 说明 |
---|---|
账号 | 注册的账号 |
密码 | 注册的密码 |
网址 | 这里是 http://114.514.191.180:8000 |
然后浏览器扩展会自动注册一个名为 browser-extension
的API令牌,并自动使用。
Readeck默认有OPDS功能,可以通过网址访问自动转换出来的EPUB格式电子书。对应的OPDS域名应为 http://114.514.191.180:8000/opds
3. 配置KOReader
由于我用的安卓电纸书,直接从GitHub下载apk安装就行。下面以最新版(2025-08)为例。
为了通过OPDS浏览Readeck,请参考KOReader Wiki的这个章节,简述如下。
点击KOReader默认界面(文件浏览)的上侧中间位置(KOREADER Logo),点击放大镜按钮,点击最下方的「OPDS书目」,进入OPDS页面。
点击左上角三横,选择「添加目录」,输入下列信息
选项 | 说明 |
---|---|
书目名称 | 自定义显示的名称,随便起 |
书目url | 上一节所说的「对应OPDS域名」 |
用户名 | 见下文 |
密码 | 见下文 |
注意,根据这个commit,Readeck已经移除了「应用密码」功能。所以这里的用户名我们随便填,但密码需要填入Readeck生成的API令牌。
作为密码
或者,您可以将此令牌用作 HTTP 基本身份验证的密码。
例如,如果应用程序仅接受用户名和密码,您可以将此令牌作为密码提供。 用户名被忽略,可以是任何值,包括空值。
保存之后,我们就可以点击查看了。从上到下为五个类别:未读书签、已归档书签、已收藏书签、全部书签、书签收藏集。
前面四个只能单独一份份查看网页,也就是说每一个收藏的网页都需要单独下载一个文件。虽然KOReader在阅读完一个文件后会智能弹窗提示是否删除文件,但删除完了后又会自动返回默认目录,然后要再多点几次进入OPDS页面。
如果想一次性把所有收藏的网页下载为一份电子书,需要创建收藏集。在Readeck的书签页面侧栏最下方,具体路径为 http://114.514.191.180:8000/bookmarks/collections
。
点击「创建新收藏集」,然后右侧可以起名、填入搜索条件。如果你只想看前一天到今天的书签,则可调整起始日期为「前 -1 天」,结束日期为「前 0 天」,然后保存。需要点一下加减,否则什么也不操作的话不会输入「前 0 天」。
这样一来,在刚才提到的OPDS页面,选择最下方「书签收藏集」,就能看见我们刚才创建的收藏集了。点进去,选择第一个「收藏集电子书」,则可以将收藏集匹配的所有网页合并为一个EPUB文件下载浏览。
4. (废弃)一键清空书签的elisp代码
Readeck并未提供批量选择功能,因此写了一段小elisp代码,通过API一键清空所有书签,需要安装 plz
包:
(defun my/delete-all-readeck ()
(interactive)
(let* ((api-token "用生成的API替换这里")
(server-url "用readeck服务器链接替换这里,带http、端口,不带斜杠,如http://114.514.191.98:8000")
(bookmarks (plz 'get (concat server-url "/api/bookmarks")
:headers `(("User-Agent" . "tomoemami/emacs")
("Authorization" . (concat "Bearer " api-token))
("Accept" . "application/json"))
:as #'json-read)))
(dolist (bookmark (seq-into bookmarks 'list))
(when-let* ((id (alist-get 'id bookmark)))
(call-process-shell-command (concat "curl -X DELETE '" server-url "/api/bookmarks/" id "' -H 'accept: application/json' -H 'Authorization: Bearer " api-token "' -H 'User-Agent: tomoemami/emacs'") nil 0)))
(message "Readeck bookmarks DELETED")))
5. 一键点击页面所有删除按键的js脚本
用脚本管理器安装,记得把 //@match
后的链接替换为自建的Readeck链接
// ==UserScript==
// @name Readeck Delete All
// @namespace http://tampermonkey.net/
// @version 2025-09-01
// @description Click ALL delete botton on current readeck page
// @author TomoeMami
// @match http://114.514.191.180:8000/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 创建一个悬浮按钮
var floatingButton = document.createElement('button');
floatingButton.textContent = '全部删除';
floatingButton.style.position = 'fixed';
floatingButton.style.bottom = '20px';
floatingButton.style.right = '20px';
floatingButton.style.zIndex = '1000';
floatingButton.style.padding = '10px 20px';
floatingButton.style.backgroundColor = '#f44336';
floatingButton.style.color = 'white';
floatingButton.style.border = 'none';
floatingButton.style.borderRadius = '5px';
floatingButton.style.cursor = 'pointer';
// 将按钮添加到页面中
document.body.appendChild(floatingButton);
// 为按钮添加点击事件监听器
floatingButton.addEventListener('click', function() {
// 查找所有符合条件的删除按钮
var deleteButtons = document.querySelectorAll('button[name="is_deleted"][title="删除此书签"][value="1"]');
if (deleteButtons.length > 0) {
// 遍历并点击每一个找到的删除按钮
deleteButtons.forEach(function(button) {
button.click();
});
alert('已点击 ' + deleteButtons.length + ' 个删除按钮。');
} else {
alert('没有找到可以删除的书签。');
}
});
})();