4.8 KiB
4.8 KiB
Koneko QZ Music v2/v3 插件开发避坑指南
版本: 0.0.4 | 作者: 云汀(Miao-moe) | 目标: 支持迁移到其他 AI 继续开发
一、项目背景
QZ Music v2/v3 是一款 Android/PC 音乐播放器,支持通过拓展插件接入多平台音源。插件系统基于 Node.js 运行时(Javet/V8),每个插件是一个单独的 .js 文件,通过 module.exports 导出接口。
插件加载机制
- 运行时环境变量通过
global.env访问,不是process.env - 插件为单
.js文件格式
二、Javet/V8 兼容性大坑(最重要)
QZ Music 使用 Javet 作为 JS 运行时(基于 V8),不支持现代 ES 语法:
| 语法 | 状态 | 正确写法 |
|---|---|---|
let / const |
❌ | var |
箭头函数 () => {} |
❌ | function() {} |
async / await |
❌ | Promise 链式 |
catch { }(无参数) |
❌ | catch (e) { } |
Promise.allSettled |
❌ | Promise.all + 手动包装 |
Object.entries / Object.values |
❌ | for...in 遍历 |
Array.prototype.includes |
❌ | indexOf(...) !== -1 |
String.prototype.startsWith |
❌ | indexOf(...) === 0 |
class |
❌ | 对象字面量 |
模板字符串 ${} |
✅ | 可用 |
Buffer |
✅ | Node.js 内置 |
Promise.allSettled 替代方案
Promise.all(promises.map(function(p) {
return p.then(function(v) {
return { status: 'fulfilled', value: v }
}).catch(function(e) {
return { status: 'rejected', reason: e }
})
})).then(function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i].status === 'fulfilled') return results[i].value
}
throw new Error('all failed')
})
三、搜索结果格式
App 的 MusicListResponse 要求必须有 list 字段,不是 songs!
// ✅ 正确
return { list: [...], allPage: N, limit: N, total: N, source: 'tx' }
// ❌ 错误
return { songs: [...], total: N }
字段名对照
| 含义 | 正确字段 | 错误字段 |
|---|---|---|
| 歌手 | artists |
artist |
| 封面图 | pic/mPic/sPic |
picUrl |
| 时长 | interval (m:ss) |
duration |
| 列表 | list |
songs |
四、各平台踩坑点
QQ音乐 (tx)
- 搜索签名:
zzcSign= SHA1 + 索引提取 + XOR + base64 - 封面图:有专辑ID用 T002,无专辑ID用 T001
- getUrl 音质参数:带
k(128k/320k/999k)
酷狗音乐 (kg)
- 搜索返回值字段是
errcode(不是error_code) - 封面图:替换
{size}为400
酷我音乐 (kw)
- 音质信息在
N_MINFO字段解析 - 封面图:
https://img2.kuwo.cn/star/albumcover/300/{ALBUMID}.jpg
网易云音乐 (wy)
- 搜索用 GET:
/api/search/get/web,不需要 weapi - 封面图:
picId需 Base64 编码 - getUrl 音质参数:数字格式
128000/320000/999000 - Cookie 用于 weapi 加密接口(每日推荐、私人FM、喜欢歌曲、歌单、专辑、歌词)
咪咕音乐 (mg)
- 搜索需 MD5 签名
- 封面图:相对路径需拼接
https://d.musicapp.migu.cn
GIT音源 (git)
- 无搜索,纯音源
- getUrl 音质参数:
128k/320k/999k
五、getUrl 容灾逻辑
所有平台使用并发测速模式:同时请求多个 API,取第一个成功结果。
API 调用顺序:
- 聆澜(需
ceru_key环境变量) - HUIBQ (lxmusicapi)
- 星海 / 忆音 / 念心 / 长青 / 星海备 / fish / HYW
网易云额外有: 4. bb / lx / ymc / unms / 官方 weapi
六、环境变量说明
| key | 用途 | 适用平台 | 必填 |
|---|---|---|---|
ceru_key |
聆澜音源 API 密钥 | 全部 | 否 |
playlist_url |
网易云个人主页链接 | 网易云 | 否 |
cookie |
网易云 Cookie | 网易云 | 否 |
七、版本管理
- 所有平台统一版本号
- 当前版本:0.0.4
- 文件名格式:
Koneko_{平台名}_v{版本号}.js
八、常见报错
| 报错 | 原因 | 解决 |
|---|---|---|
Cannot find module 'axios' |
用了 axios | 改用 http/https 内置模块 |
Field 'list' is required |
搜索返回 songs 而非 list |
改字段名为 list |
SyntaxError: Invalid or unexpected token |
用了 catch { } |
改为 catch (e) { } |
| 搜索无结果 | 字段名不匹配 | 检查 errcode vs error_code |
| 播放失败 | mapBr 返回格式不对 |
QQ/kg/kw/mg/git 用 320k,wy 用 320000 |
| 封面图不显示 | URL 格式错误或跨域 | 检查各平台封面图拼接规则 |
九、后续开发建议
- 每次修改全部平台统一升级版本号
- 先在浏览器/curl 测试 API 是否可用
- 注意 Javet 兼容性,避免现代 JS 语法
- 搜索返回务必包含
list字段 - getUrl 注意各平台音质参数格式差异
- 所有异步操作加
.catch()兜底 - 优先使用官方搜索接口,音源用第三方 API 容灾