@sansenjian/qq-music-api 2.2.7 → 2.2.10
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/CHANGELOG.md +23 -1
- package/README.md +2 -0
- package/dist/api/index.js +9 -0
- package/dist/app.js +30 -45
- package/dist/config/service-config.js +37 -0
- package/dist/index.js +13 -1
- package/dist/jest.config.js +14 -2
- package/dist/koaApp.js +45 -0
- package/dist/middlewares/fallback-middleware.js +29 -0
- package/dist/module/apis/music/getLyric.js +220 -16
- package/dist/module/apis/music/getMusicPlay.js +187 -0
- package/dist/module/apis/u_common.js +8 -2
- package/dist/module/apis/user/getUserPlaylists.js +5 -5
- package/dist/module/index.js +3 -1
- package/dist/package.json +5 -2
- package/dist/routers/context/batchGetSongInfo.js +11 -16
- package/dist/routers/context/batchGetSongLists.js +18 -20
- package/dist/routers/context/getAlbumInfo.js +10 -17
- package/dist/routers/context/getComments.js +12 -19
- package/dist/routers/context/getDailyRecommend.js +5 -17
- package/dist/routers/context/getHotkey.js +7 -8
- package/dist/routers/context/getLyric.js +12 -2
- package/dist/routers/context/getMusicPlay.js +23 -81
- package/dist/routers/context/getMv.js +16 -22
- package/dist/routers/context/getMvPlay.js +48 -49
- package/dist/routers/context/getPersonalRecommend.js +13 -25
- package/dist/routers/context/getPlaylistTags.js +20 -26
- package/dist/routers/context/getRanks.js +9 -16
- package/dist/routers/context/getSingerAlbum.js +16 -22
- package/dist/routers/context/getSingerHotsong.js +16 -22
- package/dist/routers/context/getSingerList.js +9 -21
- package/dist/routers/context/getSongInfo.js +9 -16
- package/dist/routers/context/getSongListCategories.js +6 -7
- package/dist/routers/context/getSongListDetail.js +6 -8
- package/dist/routers/context/getUserAvatar.js +20 -33
- package/dist/routers/context/getUserPlaylists.js +6 -3
- package/dist/routers/context/index.js +94 -103
- package/dist/routers/util.js +31 -0
- package/dist/scripts/run-tests-with-flags.js +139 -0
- package/dist/util/cookie.js +15 -7
- package/dist/util/cookieResolver.js +66 -0
- package/dist/util/request.js +15 -6
- package/docs-dist/404.html +2 -2
- package/docs-dist/CHANGELOG-ARCHITECTURE.html +6 -6
- package/docs-dist/COOKIE_CONFIG_GUIDE.html +6 -6
- package/docs-dist/FALLBACK_MODE_GUIDE.html +101 -0
- package/docs-dist/README.html +6 -6
- package/docs-dist/TEST_USER_PLAYLISTS.html +6 -6
- package/docs-dist/USER_AVATAR_GUIDE.html +6 -6
- package/docs-dist/api/comments.html +6 -6
- package/docs-dist/api/index.html +6 -6
- package/docs-dist/api/music.html +6 -6
- package/docs-dist/api/other.html +6 -6
- package/docs-dist/api/playlist.html +6 -6
- package/docs-dist/api/rank.html +6 -6
- package/docs-dist/api/search.html +6 -6
- package/docs-dist/api/singer.html +6 -6
- package/docs-dist/api/user.html +6 -6
- package/docs-dist/assets/{CHANGELOG-ARCHITECTURE.md.BOe0ZtyR.js → CHANGELOG-ARCHITECTURE.md.DV9Xr7ve.js} +1 -1
- package/docs-dist/assets/{CHANGELOG-ARCHITECTURE.md.BOe0ZtyR.lean.js → CHANGELOG-ARCHITECTURE.md.DV9Xr7ve.lean.js} +1 -1
- package/docs-dist/assets/{COOKIE_CONFIG_GUIDE.md.D68AwXR2.js → COOKIE_CONFIG_GUIDE.md.B2-aTdcH.js} +1 -1
- package/docs-dist/assets/{COOKIE_CONFIG_GUIDE.md.D68AwXR2.lean.js → COOKIE_CONFIG_GUIDE.md.B2-aTdcH.lean.js} +1 -1
- package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.0wqXqYxw.js +75 -0
- package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.0wqXqYxw.lean.js +1 -0
- package/docs-dist/assets/{README.md.ZJQGJ1Gb.js → README.md.DFCMeLFa.js} +1 -1
- package/docs-dist/assets/{README.md.ZJQGJ1Gb.lean.js → README.md.DFCMeLFa.lean.js} +1 -1
- package/docs-dist/assets/{TEST_USER_PLAYLISTS.md.C02575X2.js → TEST_USER_PLAYLISTS.md.Bj0AVpHw.js} +1 -1
- package/docs-dist/assets/{TEST_USER_PLAYLISTS.md.C02575X2.lean.js → TEST_USER_PLAYLISTS.md.Bj0AVpHw.lean.js} +1 -1
- package/docs-dist/assets/{USER_AVATAR_GUIDE.md.BOqjn5Cm.js → USER_AVATAR_GUIDE.md.CGPI9GUj.js} +1 -1
- package/docs-dist/assets/{USER_AVATAR_GUIDE.md.BOqjn5Cm.lean.js → USER_AVATAR_GUIDE.md.CGPI9GUj.lean.js} +1 -1
- package/docs-dist/assets/{api_comments.md.DADvndEA.js → api_comments.md.CATvWhrg.js} +1 -1
- package/docs-dist/assets/{api_comments.md.DADvndEA.lean.js → api_comments.md.CATvWhrg.lean.js} +1 -1
- package/docs-dist/assets/{api_index.md.D5IASxxG.js → api_index.md.Dqx3qXyO.js} +1 -1
- package/docs-dist/assets/{api_index.md.D5IASxxG.lean.js → api_index.md.Dqx3qXyO.lean.js} +1 -1
- package/docs-dist/assets/{api_music.md.BgB8NmZq.js → api_music.md.D20_neZB.js} +1 -1
- package/docs-dist/assets/{api_music.md.BgB8NmZq.lean.js → api_music.md.D20_neZB.lean.js} +1 -1
- package/docs-dist/assets/{api_other.md.BkRWXX2z.js → api_other.md.CXyEsl8R.js} +1 -1
- package/docs-dist/assets/{api_other.md.BkRWXX2z.lean.js → api_other.md.CXyEsl8R.lean.js} +1 -1
- package/docs-dist/assets/{api_playlist.md.Dc0hTrZ4.js → api_playlist.md.CyLdLRR9.js} +1 -1
- package/docs-dist/assets/{api_playlist.md.Dc0hTrZ4.lean.js → api_playlist.md.CyLdLRR9.lean.js} +1 -1
- package/docs-dist/assets/{api_rank.md.DRisCFyT.js → api_rank.md.Z3xyYG_S.js} +1 -1
- package/docs-dist/assets/{api_rank.md.DRisCFyT.lean.js → api_rank.md.Z3xyYG_S.lean.js} +1 -1
- package/docs-dist/assets/{api_search.md.DNnMUZK0.js → api_search.md.D_lbFmYo.js} +1 -1
- package/docs-dist/assets/{api_search.md.DNnMUZK0.lean.js → api_search.md.D_lbFmYo.lean.js} +1 -1
- package/docs-dist/assets/{api_singer.md.DCmuxQkk.js → api_singer.md.BbyYE88D.js} +1 -1
- package/docs-dist/assets/{api_singer.md.DCmuxQkk.lean.js → api_singer.md.BbyYE88D.lean.js} +1 -1
- package/docs-dist/assets/{api_user.md.Cjm9GG3z.js → api_user.md.4WdmTXIB.js} +1 -1
- package/docs-dist/assets/{api_user.md.Cjm9GG3z.lean.js → api_user.md.4WdmTXIB.lean.js} +1 -1
- package/docs-dist/assets/{app.Dx_1wB58.js → app.2f7gcITE.js} +1 -1
- package/docs-dist/assets/chunks/@localSearchIndexroot.D461xa5C.js +1 -0
- package/docs-dist/assets/chunks/{VPLocalSearchBox.DwKWtsdX.js → VPLocalSearchBox.BiPSl83v.js} +1 -1
- package/docs-dist/assets/chunks/framework.aJbMEiY9.js +19 -0
- package/docs-dist/assets/chunks/{theme.pGVgJ9Cx.js → theme.BrMPT0hE.js} +2 -2
- package/docs-dist/assets/{guide_architecture.md.DGtNyuMH.js → guide_architecture.md.D_46khUI.js} +1 -1
- package/docs-dist/assets/{guide_architecture.md.DGtNyuMH.lean.js → guide_architecture.md.D_46khUI.lean.js} +1 -1
- package/docs-dist/assets/{guide_authentication.md.mtI5LfCw.js → guide_authentication.md.nCiAu07w.js} +1 -1
- package/docs-dist/assets/{guide_authentication.md.mtI5LfCw.lean.js → guide_authentication.md.nCiAu07w.lean.js} +1 -1
- package/docs-dist/assets/{guide_index.md.B-0SG46T.js → guide_index.md.gLozHqz5.js} +1 -1
- package/docs-dist/assets/{guide_index.md.B-0SG46T.lean.js → guide_index.md.gLozHqz5.lean.js} +1 -1
- package/docs-dist/assets/{guide_installation.md.k-KpAfxv.js → guide_installation.md.BUDl8zk1.js} +1 -1
- package/docs-dist/assets/guide_installation.md.BUDl8zk1.lean.js +1 -0
- package/docs-dist/assets/{guide_quickstart.md.Bff_KFOD.js → guide_quickstart.md.COQUzUN9.js} +1 -1
- package/docs-dist/assets/guide_quickstart.md.COQUzUN9.lean.js +1 -0
- package/docs-dist/assets/{index.md.xrs-uIyo.js → index.md.DBZfQ2kF.js} +1 -1
- package/docs-dist/assets/{index.md.xrs-uIyo.lean.js → index.md.DBZfQ2kF.lean.js} +1 -1
- package/docs-dist/assets/{reference_response-format.md.DKYTK6uJ.js → reference_response-format.md.yrdeqFUN.js} +1 -1
- package/docs-dist/assets/{reference_response-format.md.DKYTK6uJ.lean.js → reference_response-format.md.yrdeqFUN.lean.js} +1 -1
- package/docs-dist/guide/architecture.html +6 -6
- package/docs-dist/guide/authentication.html +6 -6
- package/docs-dist/guide/index.html +6 -6
- package/docs-dist/guide/installation.html +6 -6
- package/docs-dist/guide/quickstart.html +6 -6
- package/docs-dist/hashmap.json +1 -1
- package/docs-dist/index.html +5 -5
- package/docs-dist/reference/response-format.html +6 -6
- package/docs-dist/version.json +3 -3
- package/package.json +5 -2
- package/docs-dist/assets/chunks/@localSearchIndexroot.CMY5EIwU.js +0 -1
- package/docs-dist/assets/chunks/framework.o40iizuP.js +0 -19
- package/docs-dist/assets/guide_installation.md.k-KpAfxv.lean.js +0 -1
- package/docs-dist/assets/guide_quickstart.md.Bff_KFOD.lean.js +0 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const UCommon_1 = __importDefault(require("../UCommon/UCommon"));
|
|
7
|
+
const config_1 = require("../../config");
|
|
8
|
+
const cookieResolver_1 = require("../../../util/cookieResolver");
|
|
9
|
+
const DEFAULT_QUALITY = '128';
|
|
10
|
+
const FILE_TYPE_MAP = {
|
|
11
|
+
m4a: { prefix: 'C400', suffix: '.m4a' },
|
|
12
|
+
128: { prefix: 'M500', suffix: '.mp3' },
|
|
13
|
+
320: { prefix: 'M800', suffix: '.mp3' },
|
|
14
|
+
ape: { prefix: 'A000', suffix: '.ape' },
|
|
15
|
+
flac: { prefix: 'F000', suffix: '.flac' }
|
|
16
|
+
};
|
|
17
|
+
const normalizeFirstValue = (value) => {
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
return normalizeFirstValue(value[0]);
|
|
20
|
+
}
|
|
21
|
+
if (typeof value !== 'string') {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const normalized = value.trim();
|
|
25
|
+
return normalized || undefined;
|
|
26
|
+
};
|
|
27
|
+
const normalizeSongmidList = (songmid) => {
|
|
28
|
+
const values = Array.isArray(songmid) ? songmid : [songmid];
|
|
29
|
+
return values
|
|
30
|
+
.flatMap(value => {
|
|
31
|
+
if (typeof value !== 'string')
|
|
32
|
+
return [];
|
|
33
|
+
return value.split(',');
|
|
34
|
+
})
|
|
35
|
+
.map(item => item.trim())
|
|
36
|
+
.filter(Boolean);
|
|
37
|
+
};
|
|
38
|
+
const normalizeQuality = (value) => {
|
|
39
|
+
const quality = normalizeFirstValue(value) || String(value || '');
|
|
40
|
+
if (quality === 'm4a' || quality === 'ape' || quality === 'flac') {
|
|
41
|
+
return quality;
|
|
42
|
+
}
|
|
43
|
+
const numericQuality = Number(quality);
|
|
44
|
+
if (numericQuality === 320) {
|
|
45
|
+
return '320';
|
|
46
|
+
}
|
|
47
|
+
if (numericQuality === 128) {
|
|
48
|
+
return '128';
|
|
49
|
+
}
|
|
50
|
+
return DEFAULT_QUALITY;
|
|
51
|
+
};
|
|
52
|
+
const pickPlayableDomain = (sip) => {
|
|
53
|
+
if (!Array.isArray(sip))
|
|
54
|
+
return '';
|
|
55
|
+
const urls = sip.filter((item) => typeof item === 'string' && item.length > 0);
|
|
56
|
+
return (urls.find(url => !url.startsWith('http://ws')) ||
|
|
57
|
+
urls.find(url => url.startsWith('https://')) ||
|
|
58
|
+
urls[0] ||
|
|
59
|
+
'');
|
|
60
|
+
};
|
|
61
|
+
const joinUrl = (domain, path) => {
|
|
62
|
+
if (domain.endsWith('/') && path.startsWith('/')) {
|
|
63
|
+
return `${domain}${path.slice(1)}`;
|
|
64
|
+
}
|
|
65
|
+
if (!domain.endsWith('/') && !path.startsWith('/')) {
|
|
66
|
+
return `${domain}/${path}`;
|
|
67
|
+
}
|
|
68
|
+
return `${domain}${path}`;
|
|
69
|
+
};
|
|
70
|
+
const buildPlayUrl = (domain, info, guid) => {
|
|
71
|
+
if (!domain)
|
|
72
|
+
return '';
|
|
73
|
+
if (info.purl) {
|
|
74
|
+
return joinUrl(domain, info.purl);
|
|
75
|
+
}
|
|
76
|
+
// Fallback for payloads where purl is empty but vkey/filename are present.
|
|
77
|
+
if (info.vkey && info.filename) {
|
|
78
|
+
return `${joinUrl(domain, info.filename)}?vkey=${info.vkey}&guid=${guid}&fromtag=66`;
|
|
79
|
+
}
|
|
80
|
+
return '';
|
|
81
|
+
};
|
|
82
|
+
const resolveUin = (cookie) => {
|
|
83
|
+
const defaultUin = String(global.userInfo?.uin || global.userInfo?.loginUin || '0');
|
|
84
|
+
return (0, cookieResolver_1.extractUinFromCookie)(cookie) || defaultUin;
|
|
85
|
+
};
|
|
86
|
+
const getCookieFromOptions = (option) => {
|
|
87
|
+
if (!option || typeof option !== 'object') {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const headers = option.headers;
|
|
91
|
+
if (!headers || typeof headers !== 'object') {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
const cookie = headers.Cookie || headers.cookie;
|
|
95
|
+
return typeof cookie === 'string' ? cookie : undefined;
|
|
96
|
+
};
|
|
97
|
+
exports.default = async ({ method = 'get', params = {}, option = {} }) => {
|
|
98
|
+
const musicParams = params;
|
|
99
|
+
const songmidList = normalizeSongmidList(musicParams.songmid);
|
|
100
|
+
if (songmidList.length === 0) {
|
|
101
|
+
return {
|
|
102
|
+
status: 400,
|
|
103
|
+
body: {
|
|
104
|
+
data: {
|
|
105
|
+
message: 'no songmid'
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const justPlayUrl = (normalizeFirstValue(musicParams.resType) || 'play') === 'play';
|
|
111
|
+
const mediaId = normalizeFirstValue(musicParams.mediaId);
|
|
112
|
+
const quality = normalizeQuality(musicParams.quality);
|
|
113
|
+
const guid = String(config_1._guid || '1429839143');
|
|
114
|
+
const cookie = getCookieFromOptions(option);
|
|
115
|
+
const uin = resolveUin(cookie);
|
|
116
|
+
const fileType = FILE_TYPE_MAP[quality];
|
|
117
|
+
const filename = songmidList.map(item => `${fileType.prefix}${item}${mediaId || item}${fileType.suffix}`);
|
|
118
|
+
const requestPayload = {
|
|
119
|
+
req_0: {
|
|
120
|
+
module: 'vkey.GetVkeyServer',
|
|
121
|
+
method: 'CgiGetVkey',
|
|
122
|
+
param: {
|
|
123
|
+
filename,
|
|
124
|
+
guid,
|
|
125
|
+
songmid: songmidList,
|
|
126
|
+
songtype: [0],
|
|
127
|
+
uin,
|
|
128
|
+
loginflag: 1,
|
|
129
|
+
platform: '20'
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
loginUin: uin,
|
|
133
|
+
comm: {
|
|
134
|
+
uin,
|
|
135
|
+
format: 'json',
|
|
136
|
+
ct: 24,
|
|
137
|
+
cv: 0
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const upstreamParams = {
|
|
141
|
+
format: 'json',
|
|
142
|
+
sign: 'zzannc1o6o9b4i971602f3554385022046ab796512b7012',
|
|
143
|
+
data: JSON.stringify(requestPayload)
|
|
144
|
+
};
|
|
145
|
+
try {
|
|
146
|
+
const response = await (0, UCommon_1.default)({
|
|
147
|
+
method: method,
|
|
148
|
+
params: upstreamParams,
|
|
149
|
+
option
|
|
150
|
+
});
|
|
151
|
+
const upstreamData = response.data;
|
|
152
|
+
const domain = pickPlayableDomain(upstreamData?.req_0?.data?.sip);
|
|
153
|
+
const midurlinfo = Array.isArray(upstreamData?.req_0?.data?.midurlinfo)
|
|
154
|
+
? upstreamData.req_0.data.midurlinfo
|
|
155
|
+
: [];
|
|
156
|
+
const playUrl = {};
|
|
157
|
+
const midInfoMap = new Map();
|
|
158
|
+
midurlinfo.forEach(item => {
|
|
159
|
+
if (item.songmid) {
|
|
160
|
+
midInfoMap.set(item.songmid, item);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
songmidList.forEach(songmid => {
|
|
164
|
+
const item = midInfoMap.get(songmid);
|
|
165
|
+
const url = item ? buildPlayUrl(domain, item, guid) : '';
|
|
166
|
+
playUrl[songmid] = {
|
|
167
|
+
url,
|
|
168
|
+
error: url ? undefined : '\u6682\u65e0\u64ad\u653e\u94fe\u63a5'
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
upstreamData.playUrl = playUrl;
|
|
172
|
+
return {
|
|
173
|
+
status: 200,
|
|
174
|
+
body: {
|
|
175
|
+
data: justPlayUrl ? { playUrl } : upstreamData
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return {
|
|
181
|
+
status: 502,
|
|
182
|
+
body: {
|
|
183
|
+
error: error instanceof Error ? error.message : error
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
};
|
|
@@ -38,7 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
const request_1 = __importDefault(require("../../util/request"));
|
|
40
40
|
const config = __importStar(require("../config"));
|
|
41
|
-
exports.default = ({ options = {}, method = 'get' }) => {
|
|
41
|
+
exports.default = ({ options = {}, method = 'get', customCookie }) => {
|
|
42
42
|
const opts = { ...options };
|
|
43
43
|
// Merge commonParams into params for query string
|
|
44
44
|
opts.params = { ...config.commonParams, ...(opts.params || {}) };
|
|
@@ -52,5 +52,11 @@ exports.default = ({ options = {}, method = 'get' }) => {
|
|
|
52
52
|
const logOpts = { ...opts, headers: { ...opts.headers, cookie: '[REDACTED]' } };
|
|
53
53
|
console.log('https://u.y.qq.com/cgi-bin/musicu.fcg', { opts: logOpts });
|
|
54
54
|
}
|
|
55
|
-
return (0, request_1.default)(
|
|
55
|
+
return (0, request_1.default)({
|
|
56
|
+
url: 'https://u.y.qq.com/cgi-bin/musicu.fcg',
|
|
57
|
+
method: method,
|
|
58
|
+
options: opts,
|
|
59
|
+
isUUrl: 'u',
|
|
60
|
+
cookie: customCookie
|
|
61
|
+
});
|
|
56
62
|
};
|
|
@@ -59,7 +59,7 @@ const getErrorMessage = (payload) => {
|
|
|
59
59
|
// 获取用户创建的歌单
|
|
60
60
|
// 注意:此接口需要有效的 QQ 音乐 Cookie 才能正常工作
|
|
61
61
|
const getUserPlaylists = async (params) => {
|
|
62
|
-
const { uin, offset = 0, limit = 30 } = params;
|
|
62
|
+
const { uin, offset = 0, limit = 30, cookie } = params;
|
|
63
63
|
// 使用 c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg 接口
|
|
64
64
|
// 这是通过 Chrome DevTools 抓包发现的实际使用的接口
|
|
65
65
|
const url = 'https://c6.y.qq.com/rsc/fcgi-bin/fcg_get_profile_homepage.fcg';
|
|
@@ -71,13 +71,14 @@ const getUserPlaylists = async (params) => {
|
|
|
71
71
|
offset,
|
|
72
72
|
limit,
|
|
73
73
|
pageOffset,
|
|
74
|
-
|
|
75
|
-
cookieLength:
|
|
74
|
+
hasCookie: Boolean(cookie),
|
|
75
|
+
cookieLength: cookie?.length || 0
|
|
76
76
|
});
|
|
77
77
|
const response = await (0, request_1.default)({
|
|
78
78
|
url,
|
|
79
79
|
method: 'GET',
|
|
80
80
|
isUUrl: 'u',
|
|
81
|
+
cookie,
|
|
81
82
|
options: {
|
|
82
83
|
params: {
|
|
83
84
|
_: Date.now(),
|
|
@@ -100,8 +101,7 @@ const getUserPlaylists = async (params) => {
|
|
|
100
101
|
loginUin: Number.parseInt(uin, 10)
|
|
101
102
|
},
|
|
102
103
|
headers: {
|
|
103
|
-
Referer: `https://y.qq.com/portal/profile.html?uin=${uin}
|
|
104
|
-
Cookie: global.userInfo?.cookie || ''
|
|
104
|
+
Referer: `https://y.qq.com/portal/profile.html?uin=${uin}`
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
});
|
package/dist/module/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getUserLikedSongs = exports.getUserAvatar = exports.getUserPlaylists = exports.checkQQLoginQr = exports.getQQLoginQr = exports.getTopLists = exports.UCommon = exports.getComments = exports.getAlbumInfo = exports.getLyric = exports.getDigitalAlbumLists = exports.getRadioLists = exports.getSingerStarNum = exports.getSingerDesc = exports.getSingerMv = exports.getSimilarSinger = exports.getMvByTag = exports.songListDetail = exports.songListCategories = exports.songLists = exports.getSmartbox = exports.getSearchByKey = exports.getHotKey = exports.downloadQQMusic = void 0;
|
|
6
|
+
exports.getUserLikedSongs = exports.getUserAvatar = exports.getUserPlaylists = exports.checkQQLoginQr = exports.getQQLoginQr = exports.getTopLists = exports.UCommon = exports.getComments = exports.getAlbumInfo = exports.getMusicPlay = exports.getLyric = exports.getDigitalAlbumLists = exports.getRadioLists = exports.getSingerStarNum = exports.getSingerDesc = exports.getSingerMv = exports.getSimilarSinger = exports.getMvByTag = exports.songListDetail = exports.songListCategories = exports.songLists = exports.getSmartbox = exports.getSearchByKey = exports.getHotKey = exports.downloadQQMusic = void 0;
|
|
7
7
|
const downloadQQMusic_1 = __importDefault(require("./apis/downloadQQMusic"));
|
|
8
8
|
exports.downloadQQMusic = downloadQQMusic_1.default;
|
|
9
9
|
// search
|
|
@@ -41,6 +41,8 @@ exports.getDigitalAlbumLists = getDigitalAlbumLists_1.default;
|
|
|
41
41
|
// music
|
|
42
42
|
const getLyric_1 = __importDefault(require("./apis/music/getLyric"));
|
|
43
43
|
exports.getLyric = getLyric_1.default;
|
|
44
|
+
const getMusicPlay_1 = __importDefault(require("./apis/music/getMusicPlay"));
|
|
45
|
+
exports.getMusicPlay = getMusicPlay_1.default;
|
|
44
46
|
// album
|
|
45
47
|
const getAlbumInfo_1 = __importDefault(require("./apis/album/getAlbumInfo"));
|
|
46
48
|
exports.getAlbumInfo = getAlbumInfo_1.default;
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sansenjian/qq-music-api",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.10",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
"test:watch": "jest --watch",
|
|
32
32
|
"test:coverage": "jest --coverage",
|
|
33
33
|
"test:verbose": "jest --verbose",
|
|
34
|
+
"test:unit": "jest --testPathPattern=tests/unit",
|
|
35
|
+
"test:flags": "tsx scripts/run-tests-with-flags.ts all",
|
|
36
|
+
"test:flags:unit": "tsx scripts/run-tests-with-flags.ts unit",
|
|
34
37
|
"docs:dev": "vitepress dev docs --port 9611",
|
|
35
38
|
"docs:preview": "vitepress preview docs",
|
|
36
39
|
"commit-push": "./scripts/commit-push.sh",
|
|
@@ -112,6 +115,6 @@
|
|
|
112
115
|
"vue": "^3.5.29"
|
|
113
116
|
},
|
|
114
117
|
"engines": {
|
|
115
|
-
"node": "
|
|
118
|
+
"node": "22.x"
|
|
116
119
|
}
|
|
117
120
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const module_1 = require("../../module");
|
|
4
|
-
const
|
|
4
|
+
const util_1 = require("../util");
|
|
5
|
+
const apiResponse_1 = require("../../util/apiResponse");
|
|
6
|
+
const batchGetSongInfoController = (0, util_1.withErrorHandler)(async (ctx) => {
|
|
5
7
|
const { songs } = ctx.request.body || {};
|
|
6
|
-
const params =
|
|
8
|
+
const params = {
|
|
7
9
|
format: 'json',
|
|
8
10
|
inCharset: 'utf8',
|
|
9
11
|
outCharset: 'utf-8',
|
|
10
12
|
notice: 0,
|
|
11
13
|
platform: 'yqq.json',
|
|
12
14
|
needNewCode: 0
|
|
13
|
-
}
|
|
15
|
+
};
|
|
14
16
|
const props = {
|
|
15
17
|
method: 'get',
|
|
16
18
|
option: {},
|
|
@@ -18,7 +20,7 @@ const controller = async (ctx, next) => {
|
|
|
18
20
|
};
|
|
19
21
|
const data = await Promise.all((songs || []).map(async (song) => {
|
|
20
22
|
const [song_mid, song_id = ''] = song;
|
|
21
|
-
|
|
23
|
+
const response = await (0, module_1.UCommon)({
|
|
22
24
|
...props,
|
|
23
25
|
params: {
|
|
24
26
|
...params,
|
|
@@ -38,16 +40,9 @@ const controller = async (ctx, next) => {
|
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
|
-
})
|
|
43
|
+
});
|
|
44
|
+
return response.data;
|
|
42
45
|
}));
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
response: {
|
|
47
|
-
code: 0,
|
|
48
|
-
data
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
exports.default = controller;
|
|
46
|
+
(0, util_1.setApiResponse)(ctx, (0, apiResponse_1.customResponse)({ response: { code: 0, data } }, 200));
|
|
47
|
+
});
|
|
48
|
+
exports.default = batchGetSongInfoController;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const module_1 = require("../../module");
|
|
4
|
-
const
|
|
4
|
+
const util_1 = require("../util");
|
|
5
|
+
const apiResponse_1 = require("../../util/apiResponse");
|
|
6
|
+
const batchGetSongListsController = (0, util_1.withErrorHandler)(async (ctx) => {
|
|
5
7
|
const { limit: ein = 19, page: sin = 0, sortId = 5, categoryIds = [10000000] } = ctx.request.body || {};
|
|
6
8
|
const params = {
|
|
7
9
|
sortId,
|
|
@@ -13,25 +15,21 @@ const controller = async (ctx, next) => {
|
|
|
13
15
|
option: {},
|
|
14
16
|
params
|
|
15
17
|
};
|
|
16
|
-
const data = await Promise.all(categoryIds.map(async (categoryId) =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
const data = await Promise.all(categoryIds.map(async (categoryId) => {
|
|
19
|
+
const result = await (0, module_1.songLists)({
|
|
20
|
+
...props,
|
|
21
|
+
params: {
|
|
22
|
+
...params,
|
|
23
|
+
categoryId
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (result.body.response && +result.body.response.code === 0) {
|
|
27
|
+
return result.body.response.data;
|
|
25
28
|
}
|
|
26
29
|
else {
|
|
27
|
-
return
|
|
28
|
-
}
|
|
29
|
-
})));
|
|
30
|
-
Object.assign(ctx, {
|
|
31
|
-
body: {
|
|
32
|
-
status: 200,
|
|
33
|
-
data
|
|
30
|
+
return result.body.response;
|
|
34
31
|
}
|
|
35
|
-
});
|
|
36
|
-
};
|
|
37
|
-
|
|
32
|
+
}));
|
|
33
|
+
(0, util_1.setApiResponse)(ctx, (0, apiResponse_1.customResponse)({ status: 200, data }, 200));
|
|
34
|
+
});
|
|
35
|
+
exports.default = batchGetSongListsController;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const module_1 = require("../../module");
|
|
4
|
-
const
|
|
4
|
+
const util_1 = require("../util");
|
|
5
|
+
const apiResponse_1 = require("../../util/apiResponse");
|
|
6
|
+
const getAlbumInfoController = (0, util_1.withErrorHandler)(async (ctx) => {
|
|
5
7
|
const { albummid } = ctx.query;
|
|
6
8
|
const props = {
|
|
7
9
|
method: 'get',
|
|
@@ -10,20 +12,11 @@ const controller = async (ctx, next) => {
|
|
|
10
12
|
},
|
|
11
13
|
option: {}
|
|
12
14
|
};
|
|
13
|
-
if (albummid) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
status,
|
|
17
|
-
body
|
|
18
|
-
});
|
|
15
|
+
if (!albummid) {
|
|
16
|
+
(0, util_1.setApiResponse)(ctx, (0, apiResponse_1.errorResponse)('no albummid', 400));
|
|
17
|
+
return;
|
|
19
18
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
message: 'no albummid'
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
exports.default = controller;
|
|
19
|
+
const result = await (0, module_1.getAlbumInfo)(props);
|
|
20
|
+
(0, util_1.setApiResponse)(ctx, result);
|
|
21
|
+
});
|
|
22
|
+
exports.default = getAlbumInfoController;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const module_1 = require("../../module");
|
|
4
|
-
const
|
|
4
|
+
const util_1 = require("../util");
|
|
5
|
+
const apiResponse_1 = require("../../util/apiResponse");
|
|
6
|
+
const getCommentsController = (0, util_1.withErrorHandler)(async (ctx) => {
|
|
5
7
|
const { id, pagesize = 25, pagenum = 0, cid = 205360772, cmd = 8, reqtype = 2, biztype = 1, rootcommentid = !pagenum && '' } = ctx.query;
|
|
6
8
|
const checkrootcommentid = !pagenum ? true : !!rootcommentid;
|
|
7
|
-
const params =
|
|
9
|
+
const params = {
|
|
8
10
|
cid,
|
|
9
11
|
reqtype,
|
|
10
12
|
biztype,
|
|
@@ -13,26 +15,17 @@ const controller = async (ctx, next) => {
|
|
|
13
15
|
pagenum,
|
|
14
16
|
pagesize,
|
|
15
17
|
lasthotcommentid: rootcommentid
|
|
16
|
-
}
|
|
18
|
+
};
|
|
17
19
|
const props = {
|
|
18
20
|
method: 'get',
|
|
19
21
|
params,
|
|
20
22
|
option: {}
|
|
21
23
|
};
|
|
22
|
-
if (id
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
status,
|
|
26
|
-
body
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
ctx.status = 400;
|
|
31
|
-
ctx.body = {
|
|
32
|
-
data: {
|
|
33
|
-
message: 'Don\'t have id or rootcommentid'
|
|
34
|
-
}
|
|
35
|
-
};
|
|
24
|
+
if (!id || !checkrootcommentid) {
|
|
25
|
+
(0, util_1.setApiResponse)(ctx, (0, apiResponse_1.errorResponse)('Don\'t have id or rootcommentid', 400));
|
|
26
|
+
return;
|
|
36
27
|
}
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
const result = await (0, module_1.getComments)(props);
|
|
29
|
+
(0, util_1.setApiResponse)(ctx, result);
|
|
30
|
+
});
|
|
31
|
+
exports.default = getCommentsController;
|
|
@@ -7,31 +7,19 @@ exports.getDailyRecommendController = getDailyRecommendController;
|
|
|
7
7
|
exports.getPrivateFMController = getPrivateFMController;
|
|
8
8
|
exports.getNewSongsController = getNewSongsController;
|
|
9
9
|
const getDailyRecommend_1 = __importDefault(require("../../module/apis/recommend/getDailyRecommend"));
|
|
10
|
-
|
|
11
|
-
* 获取每日推荐歌曲
|
|
12
|
-
*/
|
|
10
|
+
const cookieResolver_1 = require("../../util/cookieResolver");
|
|
13
11
|
async function getDailyRecommendController(ctx) {
|
|
14
|
-
const { cookie } = ctx
|
|
15
|
-
|
|
16
|
-
const normalizedCookie = Array.isArray(cookie) ? cookie[0] : cookie;
|
|
17
|
-
const result = await getDailyRecommend_1.default.getDailyRecommend(normalizedCookie);
|
|
12
|
+
const { cookie } = (0, cookieResolver_1.resolveRequestCookie)(ctx);
|
|
13
|
+
const result = await getDailyRecommend_1.default.getDailyRecommend(cookie);
|
|
18
14
|
ctx.status = result.status;
|
|
19
15
|
ctx.body = result.body;
|
|
20
16
|
}
|
|
21
|
-
/**
|
|
22
|
-
* 获取私人 FM
|
|
23
|
-
*/
|
|
24
17
|
async function getPrivateFMController(ctx) {
|
|
25
|
-
const { cookie } = ctx
|
|
26
|
-
|
|
27
|
-
const normalizedCookie = Array.isArray(cookie) ? cookie[0] : cookie;
|
|
28
|
-
const result = await getDailyRecommend_1.default.getPrivateFM(normalizedCookie);
|
|
18
|
+
const { cookie } = (0, cookieResolver_1.resolveRequestCookie)(ctx);
|
|
19
|
+
const result = await getDailyRecommend_1.default.getPrivateFM(cookie);
|
|
29
20
|
ctx.status = result.status;
|
|
30
21
|
ctx.body = result.body;
|
|
31
22
|
}
|
|
32
|
-
/**
|
|
33
|
-
* 获取新歌速递
|
|
34
|
-
*/
|
|
35
23
|
async function getNewSongsController(ctx) {
|
|
36
24
|
const { areaId = '5', limit = '20' } = ctx.query;
|
|
37
25
|
const result = await getDailyRecommend_1.default.getNewSongs(Number(areaId), Number(limit));
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const module_1 = require("../../module");
|
|
4
|
-
|
|
4
|
+
const util_1 = require("../util");
|
|
5
|
+
const getHotkeyController = (0, util_1.withErrorHandler)(async (ctx) => {
|
|
5
6
|
const props = {
|
|
6
7
|
method: 'get',
|
|
7
8
|
params: {},
|
|
@@ -10,12 +11,10 @@ exports.default = async (ctx, next) => {
|
|
|
10
11
|
if (process.env.DEBUG === 'true') {
|
|
11
12
|
console.log('[getHotkey] controller props:', props);
|
|
12
13
|
}
|
|
13
|
-
const
|
|
14
|
+
const result = await (0, module_1.getHotKey)(props);
|
|
14
15
|
if (process.env.DEBUG === 'true') {
|
|
15
|
-
console.log('[getHotkey] controller response status:', status);
|
|
16
|
+
console.log('[getHotkey] controller response status:', result.status);
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
});
|
|
21
|
-
};
|
|
18
|
+
(0, util_1.setApiResponse)(ctx, result);
|
|
19
|
+
});
|
|
20
|
+
exports.default = getHotkeyController;
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const module_1 = require("../../module");
|
|
4
|
+
const cookieResolver_1 = require("../../util/cookieResolver");
|
|
4
5
|
const controller = async (ctx, next) => {
|
|
5
|
-
const songmid = Array.isArray(ctx.query.songmid)
|
|
6
|
+
const songmid = Array.isArray(ctx.query.songmid)
|
|
7
|
+
? ctx.query.songmid[0]
|
|
8
|
+
: (ctx.query.songmid || ctx.params.songmid);
|
|
6
9
|
const rawIsFormat = Array.isArray(ctx.query.isFormat) ? ctx.query.isFormat[0] : ctx.query.isFormat;
|
|
10
|
+
const { cookie: effectiveCookie } = (0, cookieResolver_1.resolveRequestCookie)(ctx);
|
|
11
|
+
const headers = {};
|
|
12
|
+
if (effectiveCookie) {
|
|
13
|
+
headers.Cookie = effectiveCookie;
|
|
14
|
+
}
|
|
7
15
|
const props = {
|
|
8
16
|
method: 'get',
|
|
9
17
|
params: {
|
|
10
18
|
songmid
|
|
11
19
|
},
|
|
12
|
-
option: {
|
|
20
|
+
option: {
|
|
21
|
+
headers
|
|
22
|
+
},
|
|
13
23
|
isFormat: rawIsFormat
|
|
14
24
|
};
|
|
15
25
|
if (songmid) {
|