Files
Koneko_api_for_QZ-Music/Koneko插件开发避坑指南_v0.0.2.md

147 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Koneko QZ Music v2/v3 插件开发避坑指南
> 版本: 0.0.2 | 作者: 云汀(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 替代方案
```js
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`
```js
// ✅ 正确
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 调用顺序:
1. 聆澜(需 `ceru_key` 环境变量)
2. HUIBQ (lxmusicapi)
3. 星海 / 忆音 / 念心 / 长青 / 星海备 / fish / HYW
网易云额外有:
4. bb / lx / ymc / unms / 官方 weapi
## 六、环境变量说明
| key | 用途 | 适用平台 | 必填 |
|-----|------|---------|------|
| `ceru_key` | 聆澜音源 API 密钥 | 全部 | 否 |
| `playlist_url` | 网易云个人主页链接 | 网易云 | 否 |
| `cookie` | 网易云 Cookie | 网易云 | 否 |
## 七、版本管理
- 所有平台统一版本号
- 当前版本:**0.0.2**
- 文件名格式:`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 格式错误或跨域 | 检查各平台封面图拼接规则 |
## 九、后续开发建议
1. 每次修改全部平台统一升级版本号
2. 先在浏览器/curl 测试 API 是否可用
3. 注意 Javet 兼容性,避免现代 JS 语法
4. 搜索返回务必包含 `list` 字段
5. getUrl 注意各平台音质参数格式差异
6. 所有异步操作加 `.catch()` 兜底
7. 优先使用官方搜索接口,音源用第三方 API 容灾