@eldment/meting-mcp 1.6.2 → 1.6.4
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 +29 -7
- package/package.json +6 -1
- package/src/index.js +6 -4
- package/src/mcp-server.js +83 -34
- package/src/meting.js +21 -22
- package/src/providers/baidu.js +91 -89
- package/src/providers/base.js +13 -13
- package/src/providers/index.js +7 -7
- package/src/providers/kugou.js +118 -113
- package/src/providers/kuwo.js +63 -57
- package/src/providers/netease.js +105 -98
- package/src/providers/tencent.js +98 -93
package/src/providers/tencent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import BaseProvider from
|
|
1
|
+
import BaseProvider from "./base.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* 腾讯音乐平台提供者
|
|
@@ -6,7 +6,7 @@ import BaseProvider from './base.js';
|
|
|
6
6
|
export default class TencentProvider extends BaseProvider {
|
|
7
7
|
constructor(meting) {
|
|
8
8
|
super(meting);
|
|
9
|
-
this.name =
|
|
9
|
+
this.name = "tencent";
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -14,13 +14,14 @@ export default class TencentProvider extends BaseProvider {
|
|
|
14
14
|
*/
|
|
15
15
|
getHeaders() {
|
|
16
16
|
return {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
Referer: "http://y.qq.com",
|
|
18
|
+
Cookie:
|
|
19
|
+
"pgv_pvi=22038528; pgv_si=s3156287488; pgv_pvid=5535248600; yplayer_open=1; ts_last=y.qq.com/portal/player.html; ts_uid=4847550686; yq_index=0; qqmusic_fromtag=66; player_exist=1",
|
|
20
|
+
"User-Agent": "QQ%E9%9F%B3%E4%B9%90/54409 CFNetwork/901.1 Darwin/17.6.0 (x86_64)",
|
|
21
|
+
Accept: "*/*",
|
|
22
|
+
"Accept-Language": "zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4",
|
|
23
|
+
Connection: "keep-alive",
|
|
24
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -29,19 +30,19 @@ export default class TencentProvider extends BaseProvider {
|
|
|
29
30
|
*/
|
|
30
31
|
search(keyword, option = {}) {
|
|
31
32
|
return {
|
|
32
|
-
method:
|
|
33
|
-
url:
|
|
33
|
+
method: "GET",
|
|
34
|
+
url: "https://c.y.qq.com/soso/fcgi-bin/client_search_cp",
|
|
34
35
|
body: {
|
|
35
|
-
format:
|
|
36
|
+
format: "json",
|
|
36
37
|
p: option.page || 1,
|
|
37
38
|
n: option.limit || 30,
|
|
38
39
|
w: keyword,
|
|
39
40
|
aggr: 1,
|
|
40
41
|
lossless: 1,
|
|
41
42
|
cr: 1,
|
|
42
|
-
new_json: 1
|
|
43
|
+
new_json: 1,
|
|
43
44
|
},
|
|
44
|
-
format:
|
|
45
|
+
format: "data.song.list",
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -50,14 +51,14 @@ export default class TencentProvider extends BaseProvider {
|
|
|
50
51
|
*/
|
|
51
52
|
song(id) {
|
|
52
53
|
return {
|
|
53
|
-
method:
|
|
54
|
-
url:
|
|
54
|
+
method: "GET",
|
|
55
|
+
url: "https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg",
|
|
55
56
|
body: {
|
|
56
57
|
songmid: id,
|
|
57
|
-
platform:
|
|
58
|
-
format:
|
|
58
|
+
platform: "yqq",
|
|
59
|
+
format: "json",
|
|
59
60
|
},
|
|
60
|
-
format:
|
|
61
|
+
format: "data",
|
|
61
62
|
};
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -66,15 +67,15 @@ export default class TencentProvider extends BaseProvider {
|
|
|
66
67
|
*/
|
|
67
68
|
album(id) {
|
|
68
69
|
return {
|
|
69
|
-
method:
|
|
70
|
-
url:
|
|
70
|
+
method: "GET",
|
|
71
|
+
url: "https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg",
|
|
71
72
|
body: {
|
|
72
73
|
albummid: id,
|
|
73
|
-
platform:
|
|
74
|
-
format:
|
|
75
|
-
newsong: 1
|
|
74
|
+
platform: "mac",
|
|
75
|
+
format: "json",
|
|
76
|
+
newsong: 1,
|
|
76
77
|
},
|
|
77
|
-
format:
|
|
78
|
+
format: "data.getSongInfo",
|
|
78
79
|
};
|
|
79
80
|
}
|
|
80
81
|
|
|
@@ -83,17 +84,17 @@ export default class TencentProvider extends BaseProvider {
|
|
|
83
84
|
*/
|
|
84
85
|
artist(id, limit = 50) {
|
|
85
86
|
return {
|
|
86
|
-
method:
|
|
87
|
-
url:
|
|
87
|
+
method: "GET",
|
|
88
|
+
url: "https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg",
|
|
88
89
|
body: {
|
|
89
90
|
singermid: id,
|
|
90
91
|
begin: 0,
|
|
91
92
|
num: limit,
|
|
92
|
-
order:
|
|
93
|
-
platform:
|
|
94
|
-
newsong: 1
|
|
93
|
+
order: "listen",
|
|
94
|
+
platform: "mac",
|
|
95
|
+
newsong: 1,
|
|
95
96
|
},
|
|
96
|
-
format:
|
|
97
|
+
format: "data.list",
|
|
97
98
|
};
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -102,15 +103,15 @@ export default class TencentProvider extends BaseProvider {
|
|
|
102
103
|
*/
|
|
103
104
|
playlist(id) {
|
|
104
105
|
return {
|
|
105
|
-
method:
|
|
106
|
-
url:
|
|
106
|
+
method: "GET",
|
|
107
|
+
url: "https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg",
|
|
107
108
|
body: {
|
|
108
109
|
id: id,
|
|
109
|
-
format:
|
|
110
|
+
format: "json",
|
|
110
111
|
newsong: 1,
|
|
111
|
-
platform:
|
|
112
|
+
platform: "jqspaframe.json",
|
|
112
113
|
},
|
|
113
|
-
format:
|
|
114
|
+
format: "data.cdlist.0.songlist",
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
117
|
|
|
@@ -119,14 +120,14 @@ export default class TencentProvider extends BaseProvider {
|
|
|
119
120
|
*/
|
|
120
121
|
url(id, br = 320) {
|
|
121
122
|
return {
|
|
122
|
-
method:
|
|
123
|
-
url:
|
|
123
|
+
method: "GET",
|
|
124
|
+
url: "https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg",
|
|
124
125
|
body: {
|
|
125
126
|
songmid: id,
|
|
126
|
-
platform:
|
|
127
|
-
format:
|
|
127
|
+
platform: "yqq",
|
|
128
|
+
format: "json",
|
|
128
129
|
},
|
|
129
|
-
decode:
|
|
130
|
+
decode: "tencent_url",
|
|
130
131
|
};
|
|
131
132
|
}
|
|
132
133
|
|
|
@@ -135,13 +136,13 @@ export default class TencentProvider extends BaseProvider {
|
|
|
135
136
|
*/
|
|
136
137
|
lyric(id) {
|
|
137
138
|
return {
|
|
138
|
-
method:
|
|
139
|
-
url:
|
|
139
|
+
method: "GET",
|
|
140
|
+
url: "https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg",
|
|
140
141
|
body: {
|
|
141
142
|
songmid: id,
|
|
142
|
-
g_tk:
|
|
143
|
+
g_tk: "5381",
|
|
143
144
|
},
|
|
144
|
-
decode:
|
|
145
|
+
decode: "tencent_lyric",
|
|
145
146
|
};
|
|
146
147
|
}
|
|
147
148
|
|
|
@@ -160,7 +161,7 @@ export default class TencentProvider extends BaseProvider {
|
|
|
160
161
|
if (data.musicData) {
|
|
161
162
|
data = data.musicData;
|
|
162
163
|
}
|
|
163
|
-
|
|
164
|
+
|
|
164
165
|
const result = {
|
|
165
166
|
id: data.mid,
|
|
166
167
|
name: data.name,
|
|
@@ -169,13 +170,13 @@ export default class TencentProvider extends BaseProvider {
|
|
|
169
170
|
pic_id: data.album.mid,
|
|
170
171
|
url_id: data.mid,
|
|
171
172
|
lyric_id: data.mid,
|
|
172
|
-
source:
|
|
173
|
+
source: "tencent",
|
|
173
174
|
};
|
|
174
|
-
|
|
175
|
-
data.singer.forEach(singer => {
|
|
175
|
+
|
|
176
|
+
data.singer.forEach((singer) => {
|
|
176
177
|
result.artist.push(singer.name);
|
|
177
178
|
});
|
|
178
|
-
|
|
179
|
+
|
|
179
180
|
return result;
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -183,9 +184,9 @@ export default class TencentProvider extends BaseProvider {
|
|
|
183
184
|
* 处理腾讯音乐的解码逻辑
|
|
184
185
|
*/
|
|
185
186
|
async handleDecode(decodeType, data) {
|
|
186
|
-
if (decodeType ===
|
|
187
|
+
if (decodeType === "tencent_url") {
|
|
187
188
|
return this.urlDecode(data);
|
|
188
|
-
} else if (decodeType ===
|
|
189
|
+
} else if (decodeType === "tencent_lyric") {
|
|
189
190
|
return this.lyricDecode(data);
|
|
190
191
|
}
|
|
191
192
|
return data;
|
|
@@ -197,27 +198,27 @@ export default class TencentProvider extends BaseProvider {
|
|
|
197
198
|
async urlDecode(result) {
|
|
198
199
|
const data = JSON.parse(result);
|
|
199
200
|
const guid = Math.floor(Math.random() * 10000000000);
|
|
200
|
-
|
|
201
|
+
|
|
201
202
|
const qualityMap = [
|
|
202
|
-
[
|
|
203
|
-
[
|
|
204
|
-
[
|
|
205
|
-
[
|
|
206
|
-
[
|
|
207
|
-
[
|
|
208
|
-
[
|
|
203
|
+
["size_flac", 999, "F000", "flac"],
|
|
204
|
+
["size_320mp3", 320, "M800", "mp3"],
|
|
205
|
+
["size_192aac", 192, "C600", "m4a"],
|
|
206
|
+
["size_128mp3", 128, "M500", "mp3"],
|
|
207
|
+
["size_96aac", 96, "C400", "m4a"],
|
|
208
|
+
["size_48aac", 48, "C200", "m4a"],
|
|
209
|
+
["size_24aac", 24, "C100", "m4a"],
|
|
209
210
|
];
|
|
210
|
-
|
|
211
|
-
let uin =
|
|
211
|
+
|
|
212
|
+
let uin = "0";
|
|
212
213
|
const uinMatch = this.meting.header.Cookie && this.meting.header.Cookie.match(/uin=(\d+)/);
|
|
213
214
|
if (uinMatch) {
|
|
214
215
|
uin = uinMatch[1];
|
|
215
216
|
}
|
|
216
|
-
|
|
217
|
+
|
|
217
218
|
const payload = {
|
|
218
219
|
req_0: {
|
|
219
|
-
module:
|
|
220
|
-
method:
|
|
220
|
+
module: "vkey.GetVkeyServer",
|
|
221
|
+
method: "CgiGetVkey",
|
|
221
222
|
param: {
|
|
222
223
|
guid: String(guid),
|
|
223
224
|
songmid: [],
|
|
@@ -225,31 +226,31 @@ export default class TencentProvider extends BaseProvider {
|
|
|
225
226
|
songtype: [],
|
|
226
227
|
uin: uin,
|
|
227
228
|
loginflag: 1,
|
|
228
|
-
platform:
|
|
229
|
-
}
|
|
230
|
-
}
|
|
229
|
+
platform: "20",
|
|
230
|
+
},
|
|
231
|
+
},
|
|
231
232
|
};
|
|
232
|
-
|
|
233
|
+
|
|
233
234
|
qualityMap.forEach(([sizeKey, br, prefix, ext]) => {
|
|
234
235
|
payload.req_0.param.songmid.push(data.data[0].mid);
|
|
235
236
|
payload.req_0.param.filename.push(`${prefix}${data.data[0].file.media_mid}.${ext}`);
|
|
236
237
|
payload.req_0.param.songtype.push(data.data[0].type);
|
|
237
238
|
});
|
|
238
|
-
|
|
239
|
+
|
|
239
240
|
const api = {
|
|
240
|
-
method:
|
|
241
|
-
url:
|
|
241
|
+
method: "GET",
|
|
242
|
+
url: "https://u.y.qq.com/cgi-bin/musicu.fcg",
|
|
242
243
|
body: {
|
|
243
|
-
format:
|
|
244
|
-
platform:
|
|
244
|
+
format: "json",
|
|
245
|
+
platform: "yqq.json",
|
|
245
246
|
needNewCode: 0,
|
|
246
|
-
data: JSON.stringify(payload)
|
|
247
|
-
}
|
|
247
|
+
data: JSON.stringify(payload),
|
|
248
|
+
},
|
|
248
249
|
};
|
|
249
|
-
|
|
250
|
+
|
|
250
251
|
const response = JSON.parse(await this.meting._exec(api));
|
|
251
252
|
const vkeys = response.req_0.data.midurlinfo;
|
|
252
|
-
|
|
253
|
+
|
|
253
254
|
let url;
|
|
254
255
|
for (let i = 0; i < qualityMap.length; i++) {
|
|
255
256
|
const [sizeKey, br, prefix, ext] = qualityMap[i];
|
|
@@ -258,21 +259,21 @@ export default class TencentProvider extends BaseProvider {
|
|
|
258
259
|
url = {
|
|
259
260
|
url: response.req_0.data.sip[0] + vkeys[i].purl,
|
|
260
261
|
size: data.data[0].file[sizeKey],
|
|
261
|
-
br: br
|
|
262
|
+
br: br,
|
|
262
263
|
};
|
|
263
264
|
break;
|
|
264
265
|
}
|
|
265
266
|
}
|
|
266
267
|
}
|
|
267
|
-
|
|
268
|
+
|
|
268
269
|
if (!url) {
|
|
269
270
|
url = {
|
|
270
|
-
url:
|
|
271
|
+
url: "",
|
|
271
272
|
size: 0,
|
|
272
|
-
br: -1
|
|
273
|
+
br: -1,
|
|
273
274
|
};
|
|
274
275
|
}
|
|
275
|
-
|
|
276
|
+
|
|
276
277
|
return JSON.stringify(url);
|
|
277
278
|
}
|
|
278
279
|
|
|
@@ -284,18 +285,18 @@ export default class TencentProvider extends BaseProvider {
|
|
|
284
285
|
|
|
285
286
|
// 常见HTML实体编码映射
|
|
286
287
|
const entityMap = {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
288
|
+
"'": "'",
|
|
289
|
+
""": '"',
|
|
290
|
+
"&": "&",
|
|
291
|
+
"<": "<",
|
|
292
|
+
">": ">",
|
|
293
|
+
" ": " ",
|
|
293
294
|
};
|
|
294
295
|
|
|
295
296
|
// 替换命名实体
|
|
296
297
|
let decoded = text;
|
|
297
298
|
for (const [entity, char] of Object.entries(entityMap)) {
|
|
298
|
-
decoded = decoded.replace(new RegExp(entity,
|
|
299
|
+
decoded = decoded.replace(new RegExp(entity, "g"), char);
|
|
299
300
|
}
|
|
300
301
|
|
|
301
302
|
// 替换数字实体(如 ' " 等)
|
|
@@ -319,10 +320,14 @@ export default class TencentProvider extends BaseProvider {
|
|
|
319
320
|
const data = JSON.parse(jsonStr);
|
|
320
321
|
|
|
321
322
|
const lyricData = {
|
|
322
|
-
lyric: data.lyric
|
|
323
|
-
|
|
323
|
+
lyric: data.lyric
|
|
324
|
+
? this.decodeHtmlEntities(Buffer.from(data.lyric, "base64").toString())
|
|
325
|
+
: "",
|
|
326
|
+
tlyric: data.trans
|
|
327
|
+
? this.decodeHtmlEntities(Buffer.from(data.trans, "base64").toString())
|
|
328
|
+
: "",
|
|
324
329
|
};
|
|
325
330
|
|
|
326
331
|
return JSON.stringify(lyricData);
|
|
327
332
|
}
|
|
328
|
-
}
|
|
333
|
+
}
|