// Plugin Developer Guide
插件开发概览
Mio Music 的在线内容全部来自插件。插件是一个自包含的 JavaScript 文件,在应用内的受限沙箱里运行,不需要编译,也不需要任何构建工具。
快速上手
十分钟写出并安装第一个列表插件,看到它出现在来源菜单里。
列表插件参考
元数据、来源与能力、配置表单,以及每个方法的参数与返回值。
运行时 API
cerumusic.request、存储、配置、加密工具与全部限制。
调试与发布
读日志、排错清单,以及把插件提交到内置插件仓库的约定。
两类插件
| 音乐列表插件 | 音源插件 | |
|---|---|---|
| 解决什么问题 | 「有什么歌」:搜索、歌单、专辑、发现、歌手、歌词、评论、封面。还可以自己提供播放与下载地址。 | 「怎么播」:给定来源、歌曲与音质,返回一个可播放的地址。 |
| 入口 | module.exports = { listPlugin: {…} } | pluginInfo + sources + musicUrl(澜音),或洛雪脚本(自动转换) |
| 文件名 | 通常 *.list.js | 任意 .js |
| 能否多个同时启用 | 可以 | 同一时间使用一个,需显式切换 |
| 配置表单 | 支持(config) | 不支持 |
| 持久化存储 | cerumusic.storage | 无 |
| 参考 | 列表插件参考 | 音源插件 |
该写哪一种?
要对接一个自托管服务器(Subsonic、Jellyfin、你自己的服务……),或者想提供搜索、歌单、歌手页,写列表插件,并在其中同时实现
musicUrl,一个文件就够了。只有当你已经有一份「根据歌曲 ID 解析地址」的脚本(例如洛雪脚本)时,才需要音源插件。
运行环境
插件由宿主内嵌的 QuickJS(通过 rquickjs)执行。它是一个标准的 ECMAScript 引擎,async / await、Promise、解构、模板字符串、Map / Set 都可以直接使用。与浏览器和 Node.js 的差别需要特别注意:
- 没有文件系统、进程、
require、import、DOM。调用require()会直接抛错。 - 网络只能通过
cerumusic.request(或fetch的最小实现),且只允许http/https、不带用户名密码的地址。 - 有
setTimeout,没有setInterval(调用会抛错)。 - 每次调用执行 30 秒就会被中断;请求次数、响应体、内存、脚本体积都有上限,见 限制一览。
每次调用都是全新的上下文
宿主为每一次方法调用新建一个 JS 运行时,再执行你的整个脚本。模块顶层的变量(缓存、登录态)不会在两次调用之间保留。需要保留的东西——会话令牌、缓存——写进
cerumusic.storage。这是写插件时最常见的误区。
开发流程
- 写脚本
- 安装
设置 → 插件 → 音乐列表插件 → 安装列表插件,选择本地文件或输入 URL。同名重装即更新,配置保留。
- 配置并测试
在插件卡片上填写配置、点「测试连接」(如果声明了),然后到搜索页实际使用。
- 看日志
插件卡片上的「插件日志」会显示你的
console.*输出和宿主记录的失败原因。 - 发布
分享一个
.js文件即可;想随应用内置,向 mio-music-plugins 提交,见 调试与发布。
最小的例子
module.exports = {
listPlugin: {
name: 'Hello',
version: '1.0.0',
author: 'you',
sources: {
hello: { name: 'Hello', capabilities: ['search'] },
},
async search(source, { keyword, page, limit }) {
return {
list: [{ songmid: '1', name: keyword, singer: 'Mio', albumName: '', img: '', interval: '03:00' }],
allPage: 1, limit, total: 1, source,
};
},
},
};
安全与合规
- 宿主只提供运行框架,本项目不直接获取、存储或传输任何音乐数据。通过插件取得的数据是否合法,由插件的提供者与使用者自行负责。
- 插件可以访问它被允许的任意 HTTP(S) 地址并读写自己的存储,请只安装你信任来源的插件。宿主对地址形式、响应体大小与执行时间做限制,但不提供按域名的权限隔离。
- 不要在插件里内置自己的密钥或第三方服务的凭据,并避免把令牌写入日志与错误信息。