dsh-novel-shelf
A novel reader docked in the DSH right sidebar for office slacking, with an AI companion that roasts whatever you just read alongside you - import your own TXT three ways, five reading themes, and saved chapters, progress and annotations. The companion comments as you go, in one of four voices (shar
Install
dsh plugin --profile web add dsh-novel-shelf
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-novel-shelf
办公摸鱼专用:在 DSH(DeepSeek Harness)右侧栏里看本地 txt 小说,边看小说边做项目。v0.2.0 起还带一个 AI 陪读,边读边吐槽。English version: [README.en.md](README.en.md)
v0.4.3 新增 / What's new in v0.4.3
- 修正版本声明:
engines.dsh原来写的是>=0.2.0-rc.2,按 semver 规则这个范围不包含0.2.1-rc.5这类预发布版本(预发布必须与基线同 major.minor.patch 才能匹配)。现在改成>=0.2.0-0 <0.3.0-0 || >=0.2.1-0 <0.3.0-0,0.2.0 与 0.2.1 两个系列的预发布版本都被覆盖,同时明确排除尚未验证的 0.3.0。 - 新增
dsh.compatibility:逐一列出实测过的 DSH 版本(0.2.0-rc.2 / 0.2.1-rc.1 / 0.2.1-rc.5),市场与插件管理器可以直接读到。 - 功能与上一版一致,无代码改动。
v0.4.0 新增 / What's new in v0.4.0
这一版解决的是最根本的问题:读者不该自己去找书。
- 内置公版中文书库,434 本:书架工具栏多了一个书库按钮,打开就是一份书目——《西遊記》《紅樓夢》《三國志演義》《水滸傳》《封神演義》《聊齋志異》《儒林外史》《老殘遊記》这些都在,可搜书名或作者,点「下载」直接进书架开读。不用找 txt、不用填路径、不用配书源。
- 来源是 Project Gutenberg 的中文藏书:插件只内置书目(44 KB 的 JSON),正文在你点下载时才从 CDN 取,不占安装包体积。
- 下载即入库:落到
%APPDATA%/novel-reader/public-domain/,之后完全离线可读;重复下载同一本不会变成两本。 - 四个 CDN 自动回退:
cdn.jsdelivr.net→gcore→testingcf→fastly,哪个通走哪个。 - 正文自动剥掉 Gutenberg 的页眉页脚:授权说明、
Produced by、START/END OF THE PROJECT GUTENBERG EBOOK、文件命名说明全部去掉,打开就是「第一回」。《西遊記》实测 2.24 MB、切出 90 回,下载耗时约 1 秒。
v0.3.0 新增 / What's new in v0.3.0
这一版补上了书架最缺的东西:能自己把书导进来,不用先去文件管理器里翻绝对路径。
- 三条导入路径:工具栏的
+打开导入面板——选文件(也可以直接把 txt 拖进来)、浏览目录、手填路径,都通向同一个书架。 - 浏览目录是零复制:宿主自己
readdir拿到真实路径,点「导入」就把原文件路径记进书架,不搬、不复制、不占第二份磁盘。只列一层、只显示.txt(网文目录几千个文件,递归会卡死面板),带「上一层 / 主目录」跳转。 - 选文件才存副本:浏览器拿不到真实路径(
File.path早没了),所以这条路把字节传给宿主,宿主在%APPDATA%/novel-reader/imported/存一份带内容哈希的副本。同一个文件重复导入会命中原名,不会变成两本。 - 移除即清副本:从书架移除时,只有
imported/下的副本会被删掉;你原来那份文件永远不会被碰。 - 上传上限 100 MB:网络小说 txt 十几兆很常见,配置通道那条 1 MiB 的限制对上传单独放宽,其余接口照旧。
v0.2.0 新增 / What's new in v0.2.0
这一版把「AI 陪读」做成了真正能用的东西,也修掉了几个用着难受的毛病:
- 陪读常驻,不再藏在面板里:以前轮询器挂在「AI 陪读」面板上,面板一关轮询就停、悬浮人物也没了。现在开关一开就立刻说一句,然后按你设的间隔继续;面板收起时右下角的人物和气泡照样在。
- 右下角悬浮人物 + 气泡:阅读时有个小人站在右下角吐槽,点它展开气泡看历史吐槽。
- 模型可以自己挑:在「模型」面板里列出 DSH 已注册的 provider 和它们的模型,直接选;也可以自己填 OpenAI 兼容端点 + API key(baseURL / apiKey / 模型名),走你自己的额度。
- 报错说人话:之前只会显示「模型没有返回内容」,现在直接告诉你是哪个路由出的问题、什么原因(key 无效 / 没登录 / 模型名不存在 / 额度不足),provider 自己没配好时错误也直接摆在面板里。
- 切会话不丢阅读页:之前切到别的会话再回来会退回书架首页,现在阅读状态按会话记住,回到原处接着看。
功能 / Features
- 右侧栏阅读:作为 DSH 原生右栏标签打开,不开新窗口、不切应用,主界面继续留着你的项目,小说和干活同时进行。
- 本地 txt 书架:三条路加书——选文件 / 浏览目录 / 手填绝对路径。选文件由宿主存一份副本;浏览与手填都是零复制,插件只读取原文件,不上传、不外发。
- 内置公版书库(434 本):书目随包分发,点下载才取正文,落盘后离线可读。来源 Project Gutenberg。详见 [公版书库是怎么来的](#公版书库是怎么来的--how-the-public-domain-library-works)。
- 自带三本书:装上就有三本小说,首次打开右栏时自动装进书架,不用自己找文件、不用配置路径。想删就删,删了不会再回来。
- 章节切分:识别「第 N 章 / 节 / 回 / 卷 / 篇」标题;识别不到时按长度分段兜底。
- 编码探测:UTF-8 / UTF-8 BOM / UTF-16LE / UTF-16BE / GB18030 自动判定。
- 全书搜索:章节内全文匹配,命中给出章节名与上下文片段。
- 阅读进度:章节号与滚动比例自动回写,重开自动回到原处。
- 五套配色:白 / 护眼绿 / 米黄 / 深灰 / 纯黑,与 novel-reader 的
body[data-theme]同名同色。 - 与 novel-reader 共用数据:读写
%APPDATA%/novel-reader下的books.json、settings.json、annotations/*.json,两边切换主题/进度即时同步。 - 零依赖:只用 Node 内置模块与 DSH 宿主自带的服务,不引入第三方运行时依赖。插件只在两种情况下联网:你主动打开 AI 陪读,或你在公版书库里点「下载」。
- AI 陪读(默认关闭):开着之后 AI 每隔一段时间就着刚读到的内容吐槽一句,可选毒舌/温柔/侦探/摆烂四种风格,也可以点「现在就说」立刻来一句。开关一开就自动开口,不必先展开面板;右下角常驻一个陪读人物和吐槽气泡。模型可在「模型」面板里从 DSH 已注册的 provider 里挑,也可自己填 OpenAI 兼容端点 + API key。不开就一次都不调用模型。详见 [docs/ai-companion.md](docs/ai-companion.md)。
内置书目是怎么装上的 / How the bundled books work
插件 bundle 里带一个 books/ 目录(约 7.3 MB,三本 txt),随安装包一起分发。绝不把本机的 D:\... 绝对路径写进书架——换台机器路径不存在,书架会直接坏掉。所以流程是:
1. 首次读取书架(library.get)时,host 半边检查 books.json 里缺哪本内置书;
2. 缺的那几本从 bundle 的 books/ 复制到 %APPDATA%/novel-reader/books/<书名>.txt;
3. 再把这份数据目录内的副本路径写进 books.json,书架里就出现了。
三条硬约束:幂等(按书名判重,不会重复加)、失败不影响书架(某本复制失败只 console.warn 后继续)、用户删过的不会再回来(删一本就把书名记进 removed-bundled.json)。测试用环境变量 NOVEL_SHELF_BOOKS_DIR 把 bundle 目录指到沙箱,所以单测不依赖真实仓库里的小说。
公版书库是怎么来的 / How the public-domain library works
书架工具栏的书库按钮背后是 catalog/zh.json——只有书目,没有正文,44 KB / 434 本,每条记 {id, title, author, downloads, repo}。正文按需从 CDN 取:
1. 点「下载」→ catalog.download 按 id 找到那条书目;
2. 依次试四个 jsDelivr 边缘(cdn → gcore → testingcf → fastly),路径是 https://<host>/gh/GITenberg/<repo>@master/<id>-0.txt;
3. 拿到字节后剥掉 Gutenberg 的授权页眉、Produced by 行、 START/END 标记与文件命名说明,只留正文;
4. 存到 %APPDATA%/novel-reader/public-domain/<id>-<书名>.txt,再走和本地导入同一条 addBookAt 入库。
为什么是 GITenberg:Project Gutenberg 官方站与常见镜像在部分网络下不通,而 GITenberg 是它的 GitHub 镜像组织,可以借 jsDelivr 的 CDN 取到。仓库名规则是「标题里每个非 ASCII 字母数字字符替换成一个 -」,带副标题的会失配,所以生成目录时用 GitHub 搜索兜底(434 本里 345 本靠规则、89 本靠搜索)。目录生成脚本思路记在 docs/,不在运行时跑。
为什么只放书目不放正文:434 本正文约 900 MB,塞进包里既装不下也没必要——绝大多数人只读其中几本。
安装 / Install
方式一:插件市场(推荐)
在 DSH 的插件市场里搜索 dsh-novel-shelf,点安装。
方式二:命令行
dsh plugin --profile desktop add good-saltfish/dsh-novel-shelf
方式三:从源码安装
git clone https://github.com/good-saltfish/dsh-novel-shelf dsh plugin --profile desktop add link:<仓库路径>
方式四:手动装 tarball
从 Releases 下载 dsh-novel-shelf-<版本>.tgz,然后:
dsh plugin --profile desktop add file:<tgz 路径>
装完必须刷新 DSH 页面。插件的 client 半边是随页面加载的,安装或升级都不会热替换已加载的模块。刷新后右栏会出现「小说书架」标签。
使用步骤 / Usage steps
1. 打开右栏:点 DSH 界面右上角的右栏按钮,展开右侧列。
2. 切到「小说书架」标签:右栏顶部标签栏里选「小说书架」,进入书架页。
3. 三本内置书已经在架:第一次打开时,插件自带的三本小说会自动复制到本机数据目录并加进书架,点开就能读。
4. 想读公版名著:点书库按钮。工具栏上那个书本图标打开公版书库,434 本书目都在里面,搜书名或作者(例如「紅樓」),点某一行的「下载」,几百毫秒到一两秒后这本书就进了书架,点开直接读。下载过的会标「已加入书架」,重复点不会重复入库。
5. 继续加书:点工具栏的 + 打开导入面板,三条路随便挑——
- 选文件:点「选文件」,或直接把 txt 拖进面板。浏览器只肯把字节交给网页,拿不到真实路径,所以这一条由宿主在
%APPDATA%/novel-reader/imported/下落一份副本再记进书架(文件名带内容哈希前 16 位,同一个文件重复导入不会变成两本)。 - 浏览目录:点「浏览目录」,宿主自己列目录(只列一层,只显示 `.
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::8,最后更新 2026-11-02