feat(login): kg 扫码/短信验证码登录、QQ 扫码登录
- kg:sdk/auth 新增 qrKey/qrCheck 扫码与 sendCaptcha/cellphoneLogin 短信登录,路由接线 - tx:新增 /login/tx/qr(/check)(移植 sansenjian/qq-music-api):ptlogin 扫码 → check_sig 换 p_skey → OAuth authorize 换 code → QQConnectLogin 换凭据; 状态码对齐 wy(800 过期/801 等待/802 已扫/803 成功),qrsig 失效 403 映射 800; 成功凭据入库(通常含 openid/refresh_key,可走自动续期)
This commit is contained in:
1 parent
96f6a7fe91
commit
0f9989b26f
4 files changed
+479
-25
No files matched your search
@@ -18,6 +18,8 @@ pnpm test # 类型检查(tsc)+ 冒烟测试(自动启动/关闭本
|
||||
pnpm typecheck # 仅类型检查,不运行
|
||||
```
|
||||
|
||||
环境变量(`PORT`、`SOURCE_*` 等)可写入项目根目录的 `.env` 文件(已 gitignore),启动时自动加载;已存在的真实环境变量优先于 `.env` 文件值。
|
||||
|
||||
## HTTP 接口
|
||||
|
||||
接口统一为路径参数风格(`/search`、`/find` 搜索类使用 query 参数)。
|
||||
@@ -39,7 +41,11 @@ pnpm typecheck # 仅类型检查,不运行
|
||||
| `GET /album/:source/:id?page=1` | 专辑详情与曲目(kg/kw/tx) |
|
||||
| `POST /login/wy/qr` → `POST /login/wy/qr/check` | 网易云扫码登录(扫码后轮询完成登录) |
|
||||
| `POST /login/wy/cellphone` | 网易云手机号登录(password 或 captcha) |
|
||||
| `POST /login/kg/qr` → `POST /login/kg/qr/check` | 酷狗扫码登录(扫码后轮询完成登录) |
|
||||
| `POST /login/kg/captcha` → `POST /login/kg/cellphone` | 酷狗手机验证码登录 |
|
||||
| `POST /login/kg` + `userid` | 绑定酷狗 token(App 抓包获取,服务端验证) |
|
||||
| `POST /login/tx/qr` → `POST /login/tx/qr/check` | QQ 音乐扫码登录(QQ/微信扫一扫,扫码后轮询完成登录) |
|
||||
| `POST /login/tx` | 绑定 QQ 音乐 cookie(y.qq.com 复制,可选 App 抓包字段供自动续期) |
|
||||
| `GET /login/status` | 登录状态(登录后取流/请求自动携带凭据) |
|
||||
| `GET /sources` | 平台列表(音质与能力) |
|
||||
| `GET /health` | 健康检查 |
|
||||
@@ -54,34 +60,56 @@ pnpm typecheck # 仅类型检查,不运行
|
||||
- **kw / tx / wy**:`songmid`(如 `228908`、`0039MnYb0qxYhV`)
|
||||
- **kg**:`hash`(搜索结果的 `hash` 字段;当前环境 kg 取流接口被服务端限制,URL 获取可能失败)
|
||||
|
||||
## 外部音源
|
||||
|
||||
设置 `SOURCE_ENABLED=1` 后取流切换到外部音源(默认未设置时走 SDK 官方直连接口;是否启用由服务端在 `src/server.ts` 决策)。两种脚本都放 `sources/` 目录(不入库),按文件名混排成候选链:取流失败自动切换下一个,某平台连续失败 3 次的脚本降权冷却 5 分钟。音源模式下登录态不参与取流,登录自动续期不会启动(手动 `POST /login/refresh` 仍可用)。详见 [docs/source-ivm.md](docs/source-ivm.md) 与 [docs/source-simple.md](docs/source-simple.md)。
|
||||
|
||||
**社区音源脚本(`.js`)** —— 通用格式,isolated-vm 硬隔离沙箱执行(详见 `src/source-ivm.ts` 头注释),文件名排序即优先级;`SOURCE_SCRIPT_PATH` 可改为指定目录外单脚本,`SOURCE_LOG=0` 关闭请求日志,`SOURCE_ALLOW_ALL_HTTP=1` 放开 HTTP 白名单(调试用)。
|
||||
|
||||
**简单 API 脚本(`.mjs`)** —— 进程内直接加载、无沙箱的第二套极简契约,只需导出一个 `getMusicUrl`,适合自己写的取流脚本(运行于服务器进程内,请只放自己审计过的代码):
|
||||
|
||||
```js
|
||||
// sources/99-my-api.mjs —— dev 热重载模式下保存即自动重启生效
|
||||
export const sources = ['kw', 'kg', 'tx', 'wy'] // 可选,默认四平台
|
||||
export const timeout = 15000 // 可选,单次取流超时 ms(默认 15000)
|
||||
|
||||
export async function getMusicUrl({ source, id, songInfo, quality, signal }) {
|
||||
// source: 平台 id(kw/kg/tx/wy);id: 歌曲 id(songmid/hash)
|
||||
// quality: 128k/320k/flac/flac24bit
|
||||
// signal: 取消/超时信号(AbortSignal),fetch(url, { signal }) 透传即可支持取消
|
||||
const res = await fetch(`https://your-api/get?source=${source}&id=${id}&quality=${quality}`, { signal })
|
||||
const { data } = await res.json()
|
||||
return data.url // 播放地址字符串,或 { type, url }
|
||||
}
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
src/ HTTP 应用层(Fastify 服务器,全部 TypeScript 源码)
|
||||
server.ts HTTP 服务器入口(pnpm start 实际启动文件)
|
||||
routes.ts 业务路由(JSON Schema 校验 + OpenAPI 元数据)
|
||||
routes-login.ts 登录路由(wy 扫码/手机号、kg token、tx cookie)
|
||||
routes-login.ts 登录路由(wy 扫码/手机号、kg 扫码/短信/token、tx 扫码/cookie)
|
||||
source.ts 外部音源候选链(SOURCE_ENABLED 时 /url 取流重定向到 sources/ 脚本)
|
||||
source-ivm.ts 社区音源脚本加载器(isolated-vm 硬隔离沙箱)
|
||||
source-simple.ts 简单 API 音源脚本加载器(.mjs 进程内直载)
|
||||
http/
|
||||
api-error.ts 业务错误类型(404/502 等 → 统一 JSON 响应)
|
||||
openapi/
|
||||
components.ts OpenAPI 共享 schema(与路由校验同源)
|
||||
ui.ts ReDoc 页面模板
|
||||
sdk/ 音乐聚合 SDK(自包含:平台模块 + 取流 + 凭据 + 基础设施;kw/kg/tx/wy 四平台)
|
||||
sdk/ 音乐聚合 SDK(仅官方平台:平台模块 + 官方直连取流 + 凭据 + 基础设施;kw/kg/tx/wy 四平台)
|
||||
index.ts 平台聚合入口(通用工具转发,实现在 common/utils.ts)
|
||||
api-source.ts 接口选择层(internal 内置直连 / sources/ 外部音源脚本,SOURCE_ENABLED 切换)
|
||||
apis/ 各平台 URL 直连取流实现(kw/kg/tx/wy)+ 外部音源加载器(source.ts / source-ivm.ts)
|
||||
auth/ 登录态与登录协议(store.ts 持久化凭据到 data/auth.json;wy.ts 扫码/手机号、kg.ts token)
|
||||
apis/ 各平台官方 URL 直连取流实现(kw/kg/tx/wy)
|
||||
auth/ 登录态与登录协议(store.ts 持久化凭据到 data/auth.json;wy.ts 扫码/手机号、kg.ts 扫码/短信/token)
|
||||
common/ SDK 基础设施
|
||||
request.ts HTTP 请求(可取消、自动 JSON 解析、gzip/deflate 解压)
|
||||
utils.ts 工具函数(sizeFormate/formatPlayTime/dateFormat 等)
|
||||
message.ts 请求错误消息
|
||||
ipcNames.ts IPC 事件名(兼容 lx-music 结构)
|
||||
rendererIpc.ts IPC 本地实现(kw/tx 歌词解码)
|
||||
lyricDecode.ts 酷我/QQ 歌词解码
|
||||
qrcDecode.ts QQ 歌词 3DES 解密(纯 JS 移植)
|
||||
lyricUtils/kg.ts 酷狗 krc 歌词解码
|
||||
kg/ kw/ tx/ wy/ 平台模块(搜索/歌词/榜单/歌单等 + 各自的歌词解码器)
|
||||
test/
|
||||
smoke-test.ts 冒烟测试(pnpm test 运行,自动启动/关闭本地服务器)
|
||||
smoke-test.ts 冒烟测试(自动启动/关闭本地服务器,验证各平台接口)
|
||||
source-simple-test.ts 简单 API 音源脚本加载器测试(离线)
|
||||
```
|
||||
|
||||
> 分层依赖严格单向:`src` → `sdk`,`sdk` 内部自包含(不反向依赖 src)。源码统一为 TypeScript(import 一律写 `.ts` 后缀),由 Node ≥22.18 的原生类型剥离直接运行——**无编译产物**,改完即跑;tsc 仅用于类型检查(`pnpm typecheck`)。代码只使用可剥离的 TS 语法(无 enum/namespace/参数属性),新增代码也须遵守。
|
||||
@@ -90,4 +118,4 @@ test/
|
||||
|
||||
- **kg 取流**:酷狗当前环境下 `wwwapi`/`trackercdn`/`m.kugou.com` 等取流接口均被服务端风控(err_code 30020/20010),播放地址获取可能失败;歌词、搜索、榜单正常。
|
||||
- **kw flac**:`antiserver` 接口对 flac 返回 `refuse`,高音质会回退官方接口(需要 csrf token,token 失效时自动重试)。
|
||||
- 平台接口随时可能变更,遇失效时可对照 `src/apis/` 内的接口文档调整。
|
||||
- 平台接口随时可能变更,遇失效时可对照 `sdk/apis/` 内的接口文档调整。
|
||||
Reference in new issue
Block a user