qqmusic-api-enhanced 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -2
- package/interface.d.ts +329 -0
- package/main.js +65 -0
- package/main.ts +113 -0
- package/module/artist_detail.d.ts +11 -0
- package/module/artist_detail.js +35 -0
- package/module/artist_detail.ts +46 -0
- package/module/artist_songs.d.ts +17 -0
- package/module/artist_songs.js +39 -0
- package/module/artist_songs.ts +57 -0
- package/module/login_qr_check.d.ts +15 -0
- package/module/login_qr_check.js +204 -0
- package/module/login_qr_check.ts +259 -0
- package/module/login_qr_create.d.ts +10 -0
- package/module/login_qr_create.js +88 -0
- package/module/login_qr_create.ts +110 -0
- package/module/login_refresh.d.ts +14 -0
- package/module/login_refresh.js +35 -0
- package/module/login_refresh.ts +52 -0
- package/module/login_status.d.ts +9 -0
- package/module/login_status.js +23 -0
- package/module/login_status.ts +34 -0
- package/module/lyric.d.ts +17 -0
- package/module/lyric.js +76 -0
- package/module/lyric.ts +98 -0
- package/module/playlist_detail.d.ts +11 -0
- package/module/playlist_detail.js +37 -0
- package/module/playlist_detail.ts +48 -0
- package/module/playlist_track_all.d.ts +15 -0
- package/module/playlist_track_all.js +46 -0
- package/module/playlist_track_all.ts +64 -0
- package/module/recommend_songs.d.ts +11 -0
- package/module/recommend_songs.js +24 -0
- package/module/recommend_songs.ts +35 -0
- package/module/search.d.ts +19 -0
- package/module/search.js +43 -0
- package/module/search.ts +63 -0
- package/module/song_detail.d.ts +12 -0
- package/module/song_detail.js +30 -0
- package/module/song_detail.ts +42 -0
- package/module/song_url.d.ts +15 -0
- package/module/song_url.js +91 -0
- package/module/song_url.ts +124 -0
- package/module/user_detail.d.ts +11 -0
- package/module/user_detail.js +30 -0
- package/module/user_detail.ts +42 -0
- package/module/user_playlist.d.ts +11 -0
- package/module/user_playlist.js +30 -0
- package/module/user_playlist.ts +42 -0
- package/module/user_vip_info.d.ts +9 -0
- package/module/user_vip_info.js +20 -0
- package/module/user_vip_info.ts +30 -0
- package/package.json +37 -4
- package/util/cookie.d.ts +21 -0
- package/util/cookie.js +69 -0
- package/util/cookie.ts +76 -0
- package/util/crypto.d.ts +31 -0
- package/util/crypto.js +92 -0
- package/util/crypto.ts +96 -0
- package/util/des.d.ts +6 -0
- package/util/des.js +289 -0
- package/util/des.ts +346 -0
- package/util/mobile_qr_session.d.ts +12 -0
- package/util/mobile_qr_session.js +151 -0
- package/util/mobile_qr_session.ts +169 -0
- package/util/option.d.ts +37 -0
- package/util/option.js +92 -0
- package/util/option.ts +137 -0
- package/util/request.d.ts +44 -0
- package/util/request.js +131 -0
- package/util/request.ts +172 -0
- package/util/sign.d.ts +8 -0
- package/util/sign.js +26 -0
- package/util/sign.ts +31 -0
package/README.md
CHANGED
|
@@ -1,3 +1,135 @@
|
|
|
1
|
-
#
|
|
1
|
+
# qqmusic-api-enhanced
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
QQ 音乐增强版 Node.js / Bun API 客户端,基于 QQ 音乐逆向协议与签名机制实现。项目架构与设计风格严格对齐 `@neteasecloudmusicapienhanced/api`,旨在为音乐播放器、猜歌游戏(如 SonGuessr)、数据分析等应用提供开箱即用、零外部生产依赖的纯 TypeScript 解决方案。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 特性亮点
|
|
8
|
+
|
|
9
|
+
- **零外部生产依赖**:纯 TypeScript 编写,直接利用 Node.js / Bun 原生 `crypto`、`zlib`、`fetch`,无需安装 heavy C++ 插件或额外加密包。
|
|
10
|
+
- **全平台扫码登录**:支持手机 QQ 快捷扫码、微信网页扫码、QQ 音乐移动端 App 扫码,玩家可自主完成身份凭据提取与长效刷新。
|
|
11
|
+
- **VKey 播放直链提取**:基于 `UrlGetVkey` 逆向调度,支持 128kbps (mp3)、320kbps (高品质 mp3)、FLAC (无损)、M4A 以及试听片段直链解析。
|
|
12
|
+
- **QRC 逐字歌词解密**:内置原生定制版 Triple-DES(支持 QQ 音乐特定 PC-2 偏移置换)及 zlib 解压算法,自动将加密 QRC 转换为带时间戳的明文逐字歌词。
|
|
13
|
+
- **完整类型支持**:提供详尽的 `interface.d.ts` 类型定义,全面涵盖入参参数、返回格式与枚举项。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# npm
|
|
21
|
+
npm install qqmusic-api-enhanced
|
|
22
|
+
|
|
23
|
+
# pnpm
|
|
24
|
+
pnpm add qqmusic-api-enhanced
|
|
25
|
+
|
|
26
|
+
# bun
|
|
27
|
+
bun add qqmusic-api-enhanced
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 快速上手
|
|
33
|
+
|
|
34
|
+
### 1. 基础调用与默认导出
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import qqmusic, { song_detail, song_url, lyric } from "qqmusic-api-enhanced";
|
|
38
|
+
|
|
39
|
+
// 获取歌曲详情 (支持数字 ID 或字符串 MID)
|
|
40
|
+
const detail = await song_detail({ id: "0039MnYb0qxYAc" });
|
|
41
|
+
console.log(detail.body.data.track_info.name); // 晴天
|
|
42
|
+
|
|
43
|
+
// 获取播放音频 CDN 直链 (支持 '128' | '320' | 'flac' | 'm4a' | 'try')
|
|
44
|
+
const urlRes = await song_url({
|
|
45
|
+
id: "0039MnYb0qxYAc",
|
|
46
|
+
type: "320",
|
|
47
|
+
cookie: "uin=12345678; qm_keyst=YOUR_COOKIE_KEY", // VIP/付费歌曲需传入有效 Cookie
|
|
48
|
+
});
|
|
49
|
+
console.log(urlRes.body.data[0].url);
|
|
50
|
+
|
|
51
|
+
// 获取歌词 (包含普通 LRC 与自动解密的逐字 QRC)
|
|
52
|
+
const lyricRes = await lyric({ id: "0039MnYb0qxYAc", qrc: true });
|
|
53
|
+
console.log(lyricRes.body.lyric);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. 玩家自助扫码登录流程
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { login_qr_create, login_qr_check, login_status } from "qqmusic-api-enhanced";
|
|
60
|
+
|
|
61
|
+
// 第一步:生成二维码 (支持 'qq' | 'wx' | 'mobile')
|
|
62
|
+
const qr = await login_qr_create({ type: "qq" });
|
|
63
|
+
console.log("扫码链接:", qr.body.url);
|
|
64
|
+
console.log("二维码 Base64 图片:", qr.body.qrimg);
|
|
65
|
+
|
|
66
|
+
// 第二步:轮询扫码状态 (需传入 第一步返回的 qrsig 或 uuid)
|
|
67
|
+
const timer = setInterval(async () => {
|
|
68
|
+
const check = await login_qr_check({
|
|
69
|
+
type: "qq",
|
|
70
|
+
qrsig: qr.body.qrsig,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (check.body.code === 200) {
|
|
74
|
+
clearInterval(timer);
|
|
75
|
+
console.log("登录成功!用户 uin:", check.body.uin);
|
|
76
|
+
console.log("获取到的 Cookie 字符串:", check.body.cookieStr);
|
|
77
|
+
|
|
78
|
+
// 第三步:验证登录状态
|
|
79
|
+
const status = await login_status({ cookie: check.body.cookieStr });
|
|
80
|
+
console.log("用户信息:", status.body.userInfo);
|
|
81
|
+
} else if (check.body.code === 800) {
|
|
82
|
+
clearInterval(timer);
|
|
83
|
+
console.log("二维码已过期,请重新生成");
|
|
84
|
+
} else {
|
|
85
|
+
console.log("等待用户扫码/确认中:", check.body.message);
|
|
86
|
+
}
|
|
87
|
+
}, 2000);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## API 列表
|
|
93
|
+
|
|
94
|
+
| 模块名称 | 功能说明 | 关键参数 | 备注 |
|
|
95
|
+
|---|---|---|---|
|
|
96
|
+
| `login_qr_create` | 创建登录二维码 | `type?: 'qq' \| 'wx' \| 'mobile'` | 返回二维码 Base64 图片与轮询凭据 |
|
|
97
|
+
| `login_qr_check` | 轮询二维码扫码结果 | `type, qrsig?, uuid?` | 登录成功后直接返回完整 Cookie |
|
|
98
|
+
| `login_status` | 校验当前登录态 | `cookie?: string` | 检查 Cookie 有效性与用户账号信息 |
|
|
99
|
+
| `login_refresh` | 刷新登录凭证 | `cookie?: string` | 延长 musickey / qm_keyst 有效期 |
|
|
100
|
+
| `song_detail` | 歌曲详情元数据 | `id: string \| number` | 支持纯数字 song_id 或字符串 mid |
|
|
101
|
+
| `song_url` | 提取歌曲音频 CDN 直链 | `id, type?: '128'\|'320'\|'flac'\|'m4a'\|'try'` | 自动计算 VKey 与 CDN 地址拼接 |
|
|
102
|
+
| `lyric` | 获取歌曲歌词 | `id, qrc?: boolean, trans?: boolean` | 自动执行定制 Triple-DES 解密 QRC |
|
|
103
|
+
| `playlist_detail` | 获取歌单基本信息 | `id: string \| number` | 歌单 disstid |
|
|
104
|
+
| `playlist_track_all` | 歌单全量曲目分页展开 | `id, limit?: number, offset?: number` | 最大支持每次抓取 1000 首歌曲 |
|
|
105
|
+
| `artist_detail` | 歌手主页详情 | `id: string` (歌手 mid) | 歌手基本资料与统计信息 |
|
|
106
|
+
| `artist_songs` | 歌手单曲列表分页 | `id, page?: number, limit?: number, order?: number` | 分页拉取歌手所有歌曲 |
|
|
107
|
+
| `search` | 综合分类检索 | `keywords, type?: 0\|1\|2\|3\|7, page?, limit?` | 0-单曲, 1-歌手, 2-专辑, 3-歌单, 7-歌词 |
|
|
108
|
+
| `user_detail` | 用户主页信息 | `id?: string \| number` (uin) | 查询指定或当前登录用户的公开资料 |
|
|
109
|
+
| `user_playlist` | 用户创建与收藏歌单 | `id?: string \| number, limit?: number` | 获取用户歌单列表 |
|
|
110
|
+
| `recommend_songs` | 热门与新歌推荐 | `type?: 1\|2\|3\|4` | 1-华语, 2-欧美, 3-韩国, 4-日本 |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 底层工具集导出
|
|
115
|
+
|
|
116
|
+
本包同时导出所有基础密码学与网络方法,便于深度定制:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import {
|
|
120
|
+
zzcSign, // 计算 QQ 音乐客户端请求的 zzc 签名
|
|
121
|
+
qrcDecrypt, // 独立解密 QRC 逐字歌词 (Triple-DES 变体 + zlib)
|
|
122
|
+
hash33, // 经典 hash33 哈希计算
|
|
123
|
+
getGtk, // 从 skey 计算 g_tk
|
|
124
|
+
getGuid, // 生成设备与会话 32 位 GUID
|
|
125
|
+
request, // 统一网络调度器 (自动判断 cgi 或 raw http)
|
|
126
|
+
requestCgi, // 请求 musicu.fcg / musics.fcg
|
|
127
|
+
requestRaw, // 原始 fetch 包装
|
|
128
|
+
} from "qqmusic-api-enhanced";
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 协议与免责声明
|
|
134
|
+
|
|
135
|
+
本项目仅供个人学习、技术研究与教育用途。所有接口数据与媒体资源版权归腾讯公司所有。请勿将本项目用于任何商业用途或违反相关法律法规的场景。
|
package/interface.d.ts
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
export interface RequestBaseConfig {
|
|
2
|
+
cookie?: string | Record<string, string>;
|
|
3
|
+
proxy?: string;
|
|
4
|
+
realIP?: string;
|
|
5
|
+
guid?: string;
|
|
6
|
+
uin?: string | number;
|
|
7
|
+
musickey?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Response<Body = any> {
|
|
11
|
+
status: number;
|
|
12
|
+
body: Body;
|
|
13
|
+
cookie?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ApiResponse<T = any> {
|
|
17
|
+
status: number;
|
|
18
|
+
body: T;
|
|
19
|
+
cookie?: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ==============================
|
|
23
|
+
// 1. 登录与凭证模块 (Login & Auth)
|
|
24
|
+
// ==============================
|
|
25
|
+
|
|
26
|
+
export interface LoginQrCreateQuery extends RequestBaseConfig {
|
|
27
|
+
/** 登录方式: 'qq' (默认手机QQ扫码) | 'wx' (微信扫码) | 'mobile' (QQ音乐移动端App扫码) */
|
|
28
|
+
type?: "qq" | "wx" | "mobile";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface LoginQrCreateResult {
|
|
32
|
+
code: number;
|
|
33
|
+
type: "qq" | "wx" | "mobile";
|
|
34
|
+
qrsig?: string;
|
|
35
|
+
ptqrtoken?: string | number;
|
|
36
|
+
uuid?: string;
|
|
37
|
+
qrimg: string;
|
|
38
|
+
url: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface LoginQrCheckQuery extends RequestBaseConfig {
|
|
42
|
+
/** 登录方式: 'qq' | 'wx' | 'mobile' */
|
|
43
|
+
type?: "qq" | "wx" | "mobile";
|
|
44
|
+
/** 手机 QQ 轮询凭证,来源于 login_qr_create */
|
|
45
|
+
qrsig?: string;
|
|
46
|
+
/** 微信轮询凭证 uuid,来源于 login_qr_create */
|
|
47
|
+
uuid?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface LoginQrCheckResult {
|
|
51
|
+
code: number;
|
|
52
|
+
message: string;
|
|
53
|
+
uin?: string;
|
|
54
|
+
musickey?: string;
|
|
55
|
+
cookie?: Record<string, string>;
|
|
56
|
+
cookieStr?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface LoginStatusQuery extends RequestBaseConfig {}
|
|
60
|
+
|
|
61
|
+
export interface LoginStatusResult {
|
|
62
|
+
code: number;
|
|
63
|
+
isLogin: boolean;
|
|
64
|
+
uin?: string;
|
|
65
|
+
userInfo?: Record<string, any>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface LoginRefreshQuery extends RequestBaseConfig {}
|
|
69
|
+
|
|
70
|
+
export interface LoginRefreshResult {
|
|
71
|
+
code: number;
|
|
72
|
+
musickey?: string;
|
|
73
|
+
raw?: Record<string, any>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ==============================
|
|
77
|
+
// 2. 歌曲与播放 (Songs & Playback)
|
|
78
|
+
// ==============================
|
|
79
|
+
|
|
80
|
+
export interface SongDetailQuery extends RequestBaseConfig {
|
|
81
|
+
/** 歌曲数字 ID 或 字母数字混合 MID */
|
|
82
|
+
id?: string | number;
|
|
83
|
+
/** 兼容 ids 参数 */
|
|
84
|
+
ids?: string | number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface SongDetailResult {
|
|
88
|
+
code: number;
|
|
89
|
+
data: Record<string, any>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface SongUrlQuery extends RequestBaseConfig {
|
|
93
|
+
/** 歌曲 mid (单条或数组) */
|
|
94
|
+
id?: string | string[];
|
|
95
|
+
/** 兼容 ids 参数 */
|
|
96
|
+
ids?: string | string[];
|
|
97
|
+
/** 音质: '128' (默认) | '320' | 'flac' | 'm4a' | 'try' */
|
|
98
|
+
type?: "128" | "320" | "flac" | "m4a" | "try" | string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface SongUrlResult {
|
|
102
|
+
code: number;
|
|
103
|
+
data: Array<{
|
|
104
|
+
id?: number;
|
|
105
|
+
mid: string;
|
|
106
|
+
url: string;
|
|
107
|
+
type: string;
|
|
108
|
+
sip: string[];
|
|
109
|
+
purl: string;
|
|
110
|
+
expiration?: number;
|
|
111
|
+
}>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ==============================
|
|
115
|
+
// 3. 歌词与解密 (Lyrics & QRC)
|
|
116
|
+
// ==============================
|
|
117
|
+
|
|
118
|
+
export interface LyricQuery extends RequestBaseConfig {
|
|
119
|
+
/** 歌曲 ID 或 MID */
|
|
120
|
+
id?: string | number;
|
|
121
|
+
/** 是否拉取并解密逐字歌词 (默认 true) */
|
|
122
|
+
qrc?: boolean;
|
|
123
|
+
/** 是否拉取翻译歌词 (默认 true) */
|
|
124
|
+
trans?: boolean;
|
|
125
|
+
/** 是否拉取罗马音歌词 (默认 false) */
|
|
126
|
+
roma?: boolean;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface LyricResult {
|
|
130
|
+
code: number;
|
|
131
|
+
lyric: string;
|
|
132
|
+
trans: string;
|
|
133
|
+
roma: string;
|
|
134
|
+
raw: Record<string, any>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ==============================
|
|
138
|
+
// 4. 歌单模块 (Playlists)
|
|
139
|
+
// ==============================
|
|
140
|
+
|
|
141
|
+
export interface PlaylistDetailQuery extends RequestBaseConfig {
|
|
142
|
+
/** 歌单 ID (disstid) */
|
|
143
|
+
id?: string | number;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface PlaylistDetailResult {
|
|
147
|
+
code: number;
|
|
148
|
+
data: Record<string, any>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface PlaylistTrackAllQuery extends RequestBaseConfig {
|
|
152
|
+
/** 歌单 ID (disstid) */
|
|
153
|
+
id?: string | number;
|
|
154
|
+
/** 抓取数量 (默认 100, 上限 1000) */
|
|
155
|
+
limit?: number;
|
|
156
|
+
/** 分页偏移量 (默认 0) */
|
|
157
|
+
offset?: number;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface PlaylistTrackAllResult {
|
|
161
|
+
code: number;
|
|
162
|
+
songs: any[];
|
|
163
|
+
total: number;
|
|
164
|
+
raw: Record<string, any>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ==============================
|
|
168
|
+
// 5. 歌手模块 (Artists)
|
|
169
|
+
// ==============================
|
|
170
|
+
|
|
171
|
+
export interface ArtistDetailQuery extends RequestBaseConfig {
|
|
172
|
+
/** 歌手 MID (如 0025NhlC2yWrP4) */
|
|
173
|
+
id?: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface ArtistDetailResult {
|
|
177
|
+
code: number;
|
|
178
|
+
data: Record<string, any>;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface ArtistSongsQuery extends RequestBaseConfig {
|
|
182
|
+
/** 歌手 MID */
|
|
183
|
+
id?: string;
|
|
184
|
+
/** 分页页码 (从 1 开始,默认 1) */
|
|
185
|
+
page?: number;
|
|
186
|
+
/** 每页数量 (默认 20, 上限 100) */
|
|
187
|
+
limit?: number;
|
|
188
|
+
/** 排序: 0-最新, 1-最热(默认) */
|
|
189
|
+
order?: number;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface ArtistSongsResult {
|
|
193
|
+
code: number;
|
|
194
|
+
songs: any[];
|
|
195
|
+
total: number;
|
|
196
|
+
raw: Record<string, any>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ==============================
|
|
200
|
+
// 6. 搜索模块 (Search)
|
|
201
|
+
// ==============================
|
|
202
|
+
|
|
203
|
+
export interface SearchQuery extends RequestBaseConfig {
|
|
204
|
+
/** 搜索关键词 */
|
|
205
|
+
keywords?: string;
|
|
206
|
+
/** 兼容 keyword 参数 */
|
|
207
|
+
keyword?: string;
|
|
208
|
+
/** 搜索类型: 0-单曲(默认), 1-歌手, 2-专辑, 3-歌单, 7-歌词 */
|
|
209
|
+
type?: number | string;
|
|
210
|
+
/** 页码 (默认 1) */
|
|
211
|
+
page?: number;
|
|
212
|
+
/** 每页大小 (默认 20) */
|
|
213
|
+
limit?: number;
|
|
214
|
+
searchid?: string;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface SearchResult {
|
|
218
|
+
code: number;
|
|
219
|
+
data: Record<string, any>;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ==============================
|
|
223
|
+
// 7. 用户模块 (User)
|
|
224
|
+
// ==============================
|
|
225
|
+
|
|
226
|
+
export interface UserDetailQuery extends RequestBaseConfig {
|
|
227
|
+
/** 用户数字 QQ/uin 或加密 encrypt_uin (为空时默认当前登录账号) */
|
|
228
|
+
id?: string | number;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface UserDetailResult {
|
|
232
|
+
code: number;
|
|
233
|
+
data: Record<string, any>;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface UserPlaylistQuery extends RequestBaseConfig {
|
|
237
|
+
/** 用户数字 QQ/uin 或加密 encrypt_uin */
|
|
238
|
+
id?: string | number;
|
|
239
|
+
/** 歌单数量限制 (默认 100) */
|
|
240
|
+
limit?: number;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface UserPlaylistResult {
|
|
244
|
+
code: number;
|
|
245
|
+
playlists: any[];
|
|
246
|
+
total: number;
|
|
247
|
+
raw: Record<string, any>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ==============================
|
|
251
|
+
// 8. 推荐模块 (Recommendations)
|
|
252
|
+
// ==============================
|
|
253
|
+
|
|
254
|
+
export interface RecommendSongsQuery extends RequestBaseConfig {
|
|
255
|
+
/** 地区分类: 1-华语, 2-欧美, 3-韩国, 4-日本 (默认 1) */
|
|
256
|
+
type?: number | string;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface RecommendSongsResult {
|
|
260
|
+
code: number;
|
|
261
|
+
songs: any[];
|
|
262
|
+
raw: Record<string, any>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ==============================
|
|
266
|
+
// 函数签名声明
|
|
267
|
+
// ==============================
|
|
268
|
+
|
|
269
|
+
export function artist_detail(query?: ArtistDetailQuery): Promise<Response<ArtistDetailResult>>;
|
|
270
|
+
export function artist_songs(query?: ArtistSongsQuery): Promise<Response<ArtistSongsResult>>;
|
|
271
|
+
export function login_qr_check(query?: LoginQrCheckQuery): Promise<Response<LoginQrCheckResult>>;
|
|
272
|
+
export function login_qr_create(query?: LoginQrCreateQuery): Promise<Response<LoginQrCreateResult>>;
|
|
273
|
+
export function login_refresh(query?: LoginRefreshQuery): Promise<Response<LoginRefreshResult>>;
|
|
274
|
+
export function login_status(query?: LoginStatusQuery): Promise<Response<LoginStatusResult>>;
|
|
275
|
+
export function lyric(query?: LyricQuery): Promise<Response<LyricResult>>;
|
|
276
|
+
export function playlist_detail(query?: PlaylistDetailQuery): Promise<Response<PlaylistDetailResult>>;
|
|
277
|
+
export function playlist_track_all(query?: PlaylistTrackAllQuery): Promise<Response<PlaylistTrackAllResult>>;
|
|
278
|
+
export function recommend_songs(query?: RecommendSongsQuery): Promise<Response<RecommendSongsResult>>;
|
|
279
|
+
export function search(query?: SearchQuery): Promise<Response<SearchResult>>;
|
|
280
|
+
export function song_detail(query?: SongDetailQuery): Promise<Response<SongDetailResult>>;
|
|
281
|
+
export function song_url(query?: SongUrlQuery): Promise<Response<SongUrlResult>>;
|
|
282
|
+
export function user_detail(query?: UserDetailQuery): Promise<Response<UserDetailResult>>;
|
|
283
|
+
export function user_playlist(query?: UserPlaylistQuery): Promise<Response<UserPlaylistResult>>;
|
|
284
|
+
|
|
285
|
+
// 基础网络调度器与工具函数
|
|
286
|
+
export function request(arg1: string, arg2?: any, arg3?: any, arg4?: any): Promise<ApiResponse>;
|
|
287
|
+
export function requestCgi<T = any>(module: string, method: string, param?: Record<string, any>, options?: any): Promise<ApiResponse<T>>;
|
|
288
|
+
export function requestRaw(url: string, options?: any): Promise<{ status: number; data: any; headers: any; cookie: string[] }>;
|
|
289
|
+
export function zzcSign(data: string): string;
|
|
290
|
+
export function qrcDecrypt(hexData: string): string | null;
|
|
291
|
+
export function hash33(str: string): number;
|
|
292
|
+
export function getGtk(skey: string): number;
|
|
293
|
+
export function getGuid(): string;
|
|
294
|
+
export function getSearchId(): string;
|
|
295
|
+
export function cookieToJson(cookie: string | Record<string, string> | undefined | null): Record<string, string>;
|
|
296
|
+
export function cookieToString(cookieObj: Record<string, string> | undefined | null): string;
|
|
297
|
+
export function parseSetCookie(setCookieHeaders?: string[]): Record<string, string>;
|
|
298
|
+
|
|
299
|
+
declare const api: {
|
|
300
|
+
artist_detail: typeof artist_detail;
|
|
301
|
+
artist_songs: typeof artist_songs;
|
|
302
|
+
login_qr_check: typeof login_qr_check;
|
|
303
|
+
login_qr_create: typeof login_qr_create;
|
|
304
|
+
login_refresh: typeof login_refresh;
|
|
305
|
+
login_status: typeof login_status;
|
|
306
|
+
lyric: typeof lyric;
|
|
307
|
+
playlist_detail: typeof playlist_detail;
|
|
308
|
+
playlist_track_all: typeof playlist_track_all;
|
|
309
|
+
recommend_songs: typeof recommend_songs;
|
|
310
|
+
search: typeof search;
|
|
311
|
+
song_detail: typeof song_detail;
|
|
312
|
+
song_url: typeof song_url;
|
|
313
|
+
user_detail: typeof user_detail;
|
|
314
|
+
user_playlist: typeof user_playlist;
|
|
315
|
+
request: typeof request;
|
|
316
|
+
requestCgi: typeof requestCgi;
|
|
317
|
+
requestRaw: typeof requestRaw;
|
|
318
|
+
zzcSign: typeof zzcSign;
|
|
319
|
+
qrcDecrypt: typeof qrcDecrypt;
|
|
320
|
+
hash33: typeof hash33;
|
|
321
|
+
getGtk: typeof getGtk;
|
|
322
|
+
getGuid: typeof getGuid;
|
|
323
|
+
getSearchId: typeof getSearchId;
|
|
324
|
+
cookieToJson: typeof cookieToJson;
|
|
325
|
+
cookieToString: typeof cookieToString;
|
|
326
|
+
parseSetCookie: typeof parseSetCookie;
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
export default api;
|
package/main.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import artist_detail_fn from "./module/artist_detail.js";
|
|
2
|
+
import artist_songs_fn from "./module/artist_songs.js";
|
|
3
|
+
import login_qr_check_fn from "./module/login_qr_check.js";
|
|
4
|
+
import login_qr_create_fn from "./module/login_qr_create.js";
|
|
5
|
+
import login_refresh_fn from "./module/login_refresh.js";
|
|
6
|
+
import login_status_fn from "./module/login_status.js";
|
|
7
|
+
import lyric_fn from "./module/lyric.js";
|
|
8
|
+
import playlist_detail_fn from "./module/playlist_detail.js";
|
|
9
|
+
import playlist_track_all_fn from "./module/playlist_track_all.js";
|
|
10
|
+
import recommend_songs_fn from "./module/recommend_songs.js";
|
|
11
|
+
import search_fn from "./module/search.js";
|
|
12
|
+
import song_detail_fn from "./module/song_detail.js";
|
|
13
|
+
import song_url_fn from "./module/song_url.js";
|
|
14
|
+
import user_detail_fn from "./module/user_detail.js";
|
|
15
|
+
import user_playlist_fn from "./module/user_playlist.js";
|
|
16
|
+
import { cookieToJson, cookieToString, parseSetCookie } from "./util/cookie.js";
|
|
17
|
+
import { getGtk, getGuid, getSearchId, hash33, qrcDecrypt } from "./util/crypto.js";
|
|
18
|
+
import { request, requestCgi, requestRaw } from "./util/request.js";
|
|
19
|
+
import { zzcSign } from "./util/sign.js";
|
|
20
|
+
export const artist_detail = (query = {}) => artist_detail_fn(query, request);
|
|
21
|
+
export const artist_songs = (query = {}) => artist_songs_fn(query, request);
|
|
22
|
+
export const login_qr_check = (query = {}) => login_qr_check_fn(query, request);
|
|
23
|
+
export const login_qr_create = (query = {}) => login_qr_create_fn(query, request);
|
|
24
|
+
export const login_refresh = (query = {}) => login_refresh_fn(query, request);
|
|
25
|
+
export const login_status = (query = {}) => login_status_fn(query, request);
|
|
26
|
+
export const lyric = (query = {}) => lyric_fn(query, request);
|
|
27
|
+
export const playlist_detail = (query = {}) => playlist_detail_fn(query, request);
|
|
28
|
+
export const playlist_track_all = (query = {}) => playlist_track_all_fn(query, request);
|
|
29
|
+
export const recommend_songs = (query = {}) => recommend_songs_fn(query, request);
|
|
30
|
+
export const search = (query = {}) => search_fn(query, request);
|
|
31
|
+
export const song_detail = (query = {}) => song_detail_fn(query, request);
|
|
32
|
+
export const song_url = (query = {}) => song_url_fn(query, request);
|
|
33
|
+
export const user_detail = (query = {}) => user_detail_fn(query, request);
|
|
34
|
+
export const user_playlist = (query = {}) => user_playlist_fn(query, request);
|
|
35
|
+
export { request, requestCgi, requestRaw, zzcSign, qrcDecrypt, hash33, getGtk, getGuid, getSearchId, cookieToJson, cookieToString, parseSetCookie, };
|
|
36
|
+
const api = {
|
|
37
|
+
artist_detail,
|
|
38
|
+
artist_songs,
|
|
39
|
+
login_qr_check,
|
|
40
|
+
login_qr_create,
|
|
41
|
+
login_refresh,
|
|
42
|
+
login_status,
|
|
43
|
+
lyric,
|
|
44
|
+
playlist_detail,
|
|
45
|
+
playlist_track_all,
|
|
46
|
+
recommend_songs,
|
|
47
|
+
search,
|
|
48
|
+
song_detail,
|
|
49
|
+
song_url,
|
|
50
|
+
user_detail,
|
|
51
|
+
user_playlist,
|
|
52
|
+
request,
|
|
53
|
+
requestCgi,
|
|
54
|
+
requestRaw,
|
|
55
|
+
zzcSign,
|
|
56
|
+
qrcDecrypt,
|
|
57
|
+
hash33,
|
|
58
|
+
getGtk,
|
|
59
|
+
getGuid,
|
|
60
|
+
getSearchId,
|
|
61
|
+
cookieToJson,
|
|
62
|
+
cookieToString,
|
|
63
|
+
parseSetCookie,
|
|
64
|
+
};
|
|
65
|
+
export default api;
|
package/main.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import artist_detail_fn from "./module/artist_detail.js";
|
|
2
|
+
import artist_songs_fn from "./module/artist_songs.js";
|
|
3
|
+
import login_qr_check_fn from "./module/login_qr_check.js";
|
|
4
|
+
import login_qr_create_fn from "./module/login_qr_create.js";
|
|
5
|
+
import login_refresh_fn from "./module/login_refresh.js";
|
|
6
|
+
import login_status_fn from "./module/login_status.js";
|
|
7
|
+
import lyric_fn from "./module/lyric.js";
|
|
8
|
+
import playlist_detail_fn from "./module/playlist_detail.js";
|
|
9
|
+
import playlist_track_all_fn from "./module/playlist_track_all.js";
|
|
10
|
+
import recommend_songs_fn from "./module/recommend_songs.js";
|
|
11
|
+
import search_fn from "./module/search.js";
|
|
12
|
+
import song_detail_fn from "./module/song_detail.js";
|
|
13
|
+
import song_url_fn from "./module/song_url.js";
|
|
14
|
+
import user_detail_fn from "./module/user_detail.js";
|
|
15
|
+
import user_playlist_fn from "./module/user_playlist.js";
|
|
16
|
+
|
|
17
|
+
import { cookieToJson, cookieToString, parseSetCookie } from "./util/cookie.js";
|
|
18
|
+
import { getGtk, getGuid, getSearchId, hash33, qrcDecrypt } from "./util/crypto.js";
|
|
19
|
+
import { request, requestCgi, requestRaw, type ApiResponse } from "./util/request.js";
|
|
20
|
+
import { zzcSign } from "./util/sign.js";
|
|
21
|
+
|
|
22
|
+
export const artist_detail = (query: Parameters<typeof artist_detail_fn>[0] = {}) =>
|
|
23
|
+
artist_detail_fn(query, request);
|
|
24
|
+
|
|
25
|
+
export const artist_songs = (query: Parameters<typeof artist_songs_fn>[0] = {}) =>
|
|
26
|
+
artist_songs_fn(query, request);
|
|
27
|
+
|
|
28
|
+
export const login_qr_check = (query: Parameters<typeof login_qr_check_fn>[0] = {}) =>
|
|
29
|
+
login_qr_check_fn(query, request);
|
|
30
|
+
|
|
31
|
+
export const login_qr_create = (query: Parameters<typeof login_qr_create_fn>[0] = {}) =>
|
|
32
|
+
login_qr_create_fn(query, request);
|
|
33
|
+
|
|
34
|
+
export const login_refresh = (query: Parameters<typeof login_refresh_fn>[0] = {}) =>
|
|
35
|
+
login_refresh_fn(query, request);
|
|
36
|
+
|
|
37
|
+
export const login_status = (query: Parameters<typeof login_status_fn>[0] = {}) =>
|
|
38
|
+
login_status_fn(query, request);
|
|
39
|
+
|
|
40
|
+
export const lyric = (query: Parameters<typeof lyric_fn>[0] = {}) =>
|
|
41
|
+
lyric_fn(query, request);
|
|
42
|
+
|
|
43
|
+
export const playlist_detail = (query: Parameters<typeof playlist_detail_fn>[0] = {}) =>
|
|
44
|
+
playlist_detail_fn(query, request);
|
|
45
|
+
|
|
46
|
+
export const playlist_track_all = (query: Parameters<typeof playlist_track_all_fn>[0] = {}) =>
|
|
47
|
+
playlist_track_all_fn(query, request);
|
|
48
|
+
|
|
49
|
+
export const recommend_songs = (query: Parameters<typeof recommend_songs_fn>[0] = {}) =>
|
|
50
|
+
recommend_songs_fn(query, request);
|
|
51
|
+
|
|
52
|
+
export const search = (query: Parameters<typeof search_fn>[0] = {}) =>
|
|
53
|
+
search_fn(query, request);
|
|
54
|
+
|
|
55
|
+
export const song_detail = (query: Parameters<typeof song_detail_fn>[0] = {}) =>
|
|
56
|
+
song_detail_fn(query, request);
|
|
57
|
+
|
|
58
|
+
export const song_url = (query: Parameters<typeof song_url_fn>[0] = {}) =>
|
|
59
|
+
song_url_fn(query, request);
|
|
60
|
+
|
|
61
|
+
export const user_detail = (query: Parameters<typeof user_detail_fn>[0] = {}) =>
|
|
62
|
+
user_detail_fn(query, request);
|
|
63
|
+
|
|
64
|
+
export const user_playlist = (query: Parameters<typeof user_playlist_fn>[0] = {}) =>
|
|
65
|
+
user_playlist_fn(query, request);
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
request,
|
|
69
|
+
requestCgi,
|
|
70
|
+
requestRaw,
|
|
71
|
+
zzcSign,
|
|
72
|
+
qrcDecrypt,
|
|
73
|
+
hash33,
|
|
74
|
+
getGtk,
|
|
75
|
+
getGuid,
|
|
76
|
+
getSearchId,
|
|
77
|
+
cookieToJson,
|
|
78
|
+
cookieToString,
|
|
79
|
+
parseSetCookie,
|
|
80
|
+
type ApiResponse,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const api = {
|
|
84
|
+
artist_detail,
|
|
85
|
+
artist_songs,
|
|
86
|
+
login_qr_check,
|
|
87
|
+
login_qr_create,
|
|
88
|
+
login_refresh,
|
|
89
|
+
login_status,
|
|
90
|
+
lyric,
|
|
91
|
+
playlist_detail,
|
|
92
|
+
playlist_track_all,
|
|
93
|
+
recommend_songs,
|
|
94
|
+
search,
|
|
95
|
+
song_detail,
|
|
96
|
+
song_url,
|
|
97
|
+
user_detail,
|
|
98
|
+
user_playlist,
|
|
99
|
+
request,
|
|
100
|
+
requestCgi,
|
|
101
|
+
requestRaw,
|
|
102
|
+
zzcSign,
|
|
103
|
+
qrcDecrypt,
|
|
104
|
+
hash33,
|
|
105
|
+
getGtk,
|
|
106
|
+
getGuid,
|
|
107
|
+
getSearchId,
|
|
108
|
+
cookieToJson,
|
|
109
|
+
cookieToString,
|
|
110
|
+
parseSetCookie,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export default api;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { request, type ApiResponse } from "../util/request.js";
|
|
2
|
+
/**
|
|
3
|
+
* 获取歌手详细资料与百科背景.
|
|
4
|
+
*
|
|
5
|
+
* @param query.id 歌手 MID (例如: 0025NhlC2yWrP4)
|
|
6
|
+
* @param query.cookie 登录 Cookie (可选)
|
|
7
|
+
*/
|
|
8
|
+
export default function artist_detail(query?: {
|
|
9
|
+
id?: string;
|
|
10
|
+
cookie?: any;
|
|
11
|
+
}, req?: typeof request): Promise<ApiResponse>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { request } from "../util/request.js";
|
|
2
|
+
/**
|
|
3
|
+
* 获取歌手详细资料与百科背景.
|
|
4
|
+
*
|
|
5
|
+
* @param query.id 歌手 MID (例如: 0025NhlC2yWrP4)
|
|
6
|
+
* @param query.cookie 登录 Cookie (可选)
|
|
7
|
+
*/
|
|
8
|
+
export default async function artist_detail(query = {}, req = request) {
|
|
9
|
+
const mid = query.id?.trim();
|
|
10
|
+
if (!mid) {
|
|
11
|
+
return {
|
|
12
|
+
status: 400,
|
|
13
|
+
body: { code: 400, message: "缺少歌手 mid" },
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const cgiRes = await req("music.musichallSinger.SingerInfoInter", "GetSingerDetail", {
|
|
17
|
+
singer_mids: [mid],
|
|
18
|
+
group_singer: 1,
|
|
19
|
+
wiki_singer: 1,
|
|
20
|
+
ex_singer: 1,
|
|
21
|
+
pic: 1,
|
|
22
|
+
photos: 1,
|
|
23
|
+
}, {
|
|
24
|
+
cookie: query.cookie,
|
|
25
|
+
platform: "web",
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
status: cgiRes.status,
|
|
29
|
+
body: {
|
|
30
|
+
code: cgiRes.body?.code ?? 200,
|
|
31
|
+
data: cgiRes.body,
|
|
32
|
+
},
|
|
33
|
+
cookie: cgiRes.cookie,
|
|
34
|
+
};
|
|
35
|
+
}
|