有声书插件(项目已废弃,接口不再维护)

在聊天框中搜索、订阅并追更喜马拉雅有声书,支持记录播放进度。
作者: 蜥蜴


⚠️ 项目状态

本项目已废弃,所对接的第三方接口不再维护,插件可能无法正常返回搜索结果与音频。

本文保留作为使用记录与实现参考。如需在现有机器人中使用,请自行评估接口可用性。


背景

有声书通常需要在专门的 App 中搜索、加入书架、逐集播放,并在多设备之间同步收听进度。若希望在日常聊天中直接获取,需要通过机器人调用第三方有声书接口。

koishi-plugin-audiobook-lizard 将搜索、订阅、进度记录与音频获取整合为一组聊天指令,可在群聊或私聊中完成完整的收听流程。


工具定位

koishi-plugin-audiobook-lizard 是一款基于 Koishi 框架的有声书管理插件,主要能力如下:

能力 说明
关键词搜索 通过关键词搜索喜马拉雅有声书
订阅管理 将感兴趣的有声书加入订阅列表
进度记录 记录每本有声书的播放进度
顺序追更 自动按集数顺序获取下一集
音频下发 以文件形式发送音频,并附带原页链接
封面与简介 展示有声书封面图与简介

当前版本为 0.0.2,依赖 Koishi ^4.18.7 与 @koishijs/plugin-database-sqlite。

功能完成度

  • 记录播放进度
  • 管理订阅列表
  • 发送音频文件
  • 可选语音播放
  • 选择指定集数

安装

前置条件

  • 已搭建并可正常运行的 Koishi 项目(koishi-app)
  • 已启用 Koishi 的数据库服务(插件声明 inject: ['database'],订阅与进度记录均依赖数据库)

方式一:通过插件市场安装(推荐)

  1. 启动 Koishi 项目,打开控制台(默认地址 http://localhost:5140)。
  2. 进入左侧「插件市场」。
  3. 在搜索框中输入 audiobook-lizard。
  4. 找到插件后点击「添加」,Koishi 会自动完成依赖安装与配置写入。

方式二:通过 npm 安装

在 Koishi 项目根目录执行:

1
npm install koishi-plugin-audiobook-lizard

随后在 koishi.yml 中手动添加配置:

1
2
3
4
plugins:
audiobook-lizard:
apiUrl: https://www.hhlqilongzhu.cn/api/ximalaya/ximalaya.php
maxResults: 10

方式三:通过 yarn / pnpm 安装

若项目使用 yarn 或 pnpm,可执行:

1
2
3
4
5
# yarn
yarn add koishi-plugin-audiobook-lizard

# pnpm
pnpm add koishi-plugin-audiobook-lizard

启用数据库

插件订阅与进度记录依赖数据库。若项目尚未配置,可在控制台「插件配置」中找到 database-sqlite 并启用:

1
2
3
plugins:
database-sqlite:
path: data/koishi.db

保存配置后重启 Koishi 项目,即可正常使用订阅功能。

验证安装

在任意已接入机器人的聊天窗口输入:

1
有声书.订阅列表

若返回「你还没有订阅任何有声书。」,则说明安装成功。


配置

配置项

参数 类型 默认值 取值范围 说明
apiUrl string https://www.hhlqilongzhu.cn/api/ximalaya/ximalaya.php — 第三方接口地址,默认值请勿更改
maxResults number 10 1 ~ 100 搜索结果展示的最大条数

配置示例

1
2
3
4
plugins:
audiobook-lizard:
apiUrl: https://www.hhlqilongzhu.cn/api/ximalaya/ximalaya.php
maxResults: 10

maxResults 控制单次搜索返回的候选条数。默认 10 条足以覆盖常规需求,若需查看更多结果可调高至 100。


使用流程

指令均绑定在父指令 有声书 之下。

完整指令列表

指令 说明 示例
有声书.搜索 <关键词> 按关键词搜索有声书 有声书.搜索 遮天
有声书.订阅列表 查看订阅并追更 有声书.订阅列表
有声书.取消订阅 从订阅列表中取消订阅 有声书.取消订阅

流程一:搜索并订阅有声书

步骤 1:发送搜索指令

1
有声书.搜索 遮天

若无关键词,插件将返回提示「请提供关键词,例如:有声书 遮天」。

步骤 2:从搜索结果中选择目标

插件返回带序号的搜索结果(最多 maxResults 条):

1
2
3
4
1. 遮天(全集)
2. 遮天(大灰狼版)
3. ...
请输入编号选择查看详情,输入"0"退出搜索。

在 15 秒内回复对应编号,或输入 0 退出搜索。

步骤 3:查看有声书详情

选择编号后,插件返回该有声书的标题、简介与封面图:

1
2
3
标题:遮天
简介:……
[封面图]

步骤 4:选择是否订阅

若该书尚未订阅,插件会询问:

1
2
是否将本书添加到订阅列表?
回复"是"以确认。
  • 回复「是」:插件拉取全部集数信息并写入订阅列表,随后提示「已添加至订阅列表」
  • 回复其他内容:插件提示「放弃添加」

若该书已在订阅列表中,插件提示「你已订阅该有声书」。


流程二:查看订阅并追更

步骤 1:发送订阅列表指令

1
有声书.订阅列表

若尚未订阅任何有声书,插件提示「你还没有订阅任何有声书。」。否则返回带序号的订阅列表:

1
2
3
1. 遮天
2. ……
请输入编号选择查看详情,输入"0"退出。

在 10 秒内回复编号,或输入 0 退出。

步骤 2:根据进度获取音频

选择编号后,插件根据该有声书的播放记录分两种情况处理:

情况 A:尚无播放记录

1
当前有声书无获取记录,是否获取第一集?(是/否)

回复「是」后,插件获取第一集音频并将进度更新为第一集。

情况 B:已有播放记录

1
2
3
4
5
当前有声书进度:

<当前集数标题>

是否获取下一集?(是/否)

回复「是」后,插件获取下一集音频并更新进度。

若当前集已是最后一集,插件提示「已经是该有声书的最后一集。」。

步骤 3:接收音频

获取音频成功后,插件分两条消息发送:

1
2
3
<标题>

链接:<原页地址>
1
[音频文件]

音频以 M4A 文件形式下发,文件名为 <标题>.m4a。


流程三:取消订阅

步骤 1:发送取消订阅指令

1
有声书.取消订阅

步骤 2:从列表中选择目标

插件返回与「订阅列表」相同的带序号列表,在 10 秒内回复编号。

步骤 3:确认取消

选择成功后,插件将该记录从数据库中移除,并提示「已取消订阅:<标题>」。


使用场景

场景一:日常追更

订阅多本有声书后,每日通过 有声书.订阅列表 依次追更。插件自动按集数顺序推进,无需手动记忆进度。

场景二:多人共享机器人的进度独立

进度记录按 用户ID 存储,不同用户在同一群聊中的订阅与进度互不影响。

场景三:找到目标后立即试听

在 有声书.搜索 的详情页中即可直接进入订阅与播放流程,无需额外跳转。


技术实现

技术栈

技术 用途
Koishi 机器人框架
TypeScript 开发语言
@koishijs/plugin-database-sqlite 数据持久化
第三方有声书接口 搜索与音频数据来源

接口调用

插件通过 apiUrl 拼接参数获取数据,共涉及三个调用:

参数 用途 返回内容
?name=<关键词> 关键词搜索 有声书列表(标题、简介、封面、albumId)
?albumId=<专辑ID> 获取专辑集数 全部集数信息
?trackId=<集数ID> 获取指定集数音频 标题、原页链接、音频地址

核心设计

数据表结构

订阅与进度记录存储于 audiobooks 表,字段如下:

字段 类型 说明
id unsigned 自增主键
userId string 用户 ID
albumId string 专辑 ID
title string 有声书标题
totalTrack string 全部集数信息(JSON 字符串)
trackId string 当前播放进度对应的集数 ID

totalTrack 存有专辑的全部集数信息,追更时直接从该字段解析,无需重复请求接口。

进度记录

每次获取音频后,通过 updateTrack 更新 trackId 字段:

1
2
3
4
5
6
await ctx.database.set('audiobooks', {
userId: session.userId,
albumId,
}, {
trackId,
});

因此再次进入订阅列表时可直接定位到进度位置,并自动推荐下一集。

会话缓存与超时

搜索与订阅列表的选择过程使用内存缓存 cache[userId],并通过 session.prompt(timeout) 等待用户输入:

  • 搜索场景:15 秒超时
  • 订阅列表与取消订阅场景:10 秒超时

超时后视为放弃操作,返回缓存清理或退出提示。

封面图内联

封面图以 base64 内联方式发送,避免依赖外链可达性:

1
return `data:image/jpeg;base64,${Buffer.from(imageBuffer).toString('base64')}`;

重复订阅检测

在添加订阅前,插件会检查 albumId 是否已存在于当前用户的订阅列表中,避免重复写入。


注意事项

1. 项目已废弃

所依赖的第三方接口已不再维护,插件可能无法正常返回搜索结果与音频。本文档仅作为使用记录保留。

2. 数据库依赖

插件声明了 inject: ['database'],订阅与进度记录均依赖数据库服务。若未启用数据库,相关指令将不可用。

3. 接口稳定性

默认接口为第三方服务,可能出现限流或返回异常。如遇请求失败,建议稍后重试,不建议自行修改 apiUrl。

4. 进度按用户隔离

播放进度以 userId 为维度存储。同一账号在不同群聊中共享同一进度,不同账号之间互不影响。

5. 音频下发形式

当前版本仅以文件形式下发音频,暂不支持语音形式播放。文件形式对客户端兼容性更好。


常见问题

Q1:安装后输入指令无响应?

依次检查以下项:

  • 插件是否已在控制台启用
  • @koishijs/plugin-database-sqlite 是否已安装并启用
  • 机器人是否已成功连接至目标平台
  • 指令是否完整输入(父指令 有声书 与子指令之间以点号分隔)

Q2:搜索时提示「未找到相关有声书」?

可能的原因包括:

  • 关键词与实际标题不符,可尝试更换关键词
  • 第三方接口暂时不可用
  • 该书未收录于接口数据源中

Q3:订阅后为何无法获取音频?

订阅流程需要先后调用两次接口:搜索时获取专辑集数、追更时获取指定集数的音频。若其中任一接口不可用,均会导致获取失败。所依赖的第三方接口已不再维护,出现获取失败属预期情况。

Q4:播放进度会丢失吗?

进度存储于数据库中,机器人重启不会丢失。而搜索与选择过程使用内存缓存,超时或重启后会清空,需重新搜索。

Q5:是否可以指定获取某一集?

当前版本仅支持顺序追更,尚不支持指定集数。该功能已列入待开发项。

Q6:能否在多个设备之间同步进度?

进度以 userId 为维度存储,只要使用同一账号在同一机器人下操作,进度即可同步。


获取工具