@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/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Meting-MCP
|
|
2
2
|
|
|
3
|
-
`Meting-MCP` 是基于 **[metowolf/Meting](https://github.com/metowolf/Meting)** 构建的 MCP Server,支持
|
|
3
|
+
`Meting-MCP` 是基于 **[metowolf/Meting](https://github.com/metowolf/Meting)** 构建的 MCP Server,支持 [网易云音乐](https://music.163.com/)(`netease`)、[腾讯音乐](https://y.qq.com/)(`tencent`)、[酷狗音乐](https://www.kugou.com/)(`kugou`)、[千千音乐](https://music.taihe.com/)(`baidu`)、[酷我音乐](https://www.kuwo.cn/)(`kuwo`) 等音乐平台,提供搜索、歌曲、专辑、歌手、歌单、播放链接、歌词、封面等能力
|
|
4
4
|
|
|
5
5
|
## 提供的 MCP 工具
|
|
6
6
|
|
|
@@ -23,11 +23,11 @@ Claude 示例配置:
|
|
|
23
23
|
"mcpServers": {
|
|
24
24
|
"meting": {
|
|
25
25
|
"command": "npx",
|
|
26
|
-
"args": [
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
"args": ["-y", "@eldment/meting-mcp@latest"],
|
|
27
|
+
"env": {
|
|
28
|
+
"METING_NETEASE_COOKIE": "...",
|
|
29
|
+
"METING_TENCENT_COOKIE": "..."
|
|
30
|
+
},
|
|
31
31
|
"timeout": 60000
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -44,11 +44,33 @@ args = [
|
|
|
44
44
|
"-y",
|
|
45
45
|
"@eldment/meting-mcp@latest",
|
|
46
46
|
]
|
|
47
|
-
env = {
|
|
47
|
+
env = {
|
|
48
|
+
METING_NETEASE_COOKIE = "...",
|
|
49
|
+
METING_TENCENT_COOKIE = "...",
|
|
50
|
+
}
|
|
48
51
|
tool_timeout_sec = 60
|
|
49
52
|
disabled = false
|
|
50
53
|
```
|
|
51
54
|
|
|
55
|
+
## Cookie 配置
|
|
56
|
+
|
|
57
|
+
MCP 运行时会优先从环境变量读取 cookie,再回退到工具输入参数传入的 cookie,优先级如下:
|
|
58
|
+
|
|
59
|
+
1. `METING_<PLATFORM>_COOKIE`
|
|
60
|
+
2. `METING_COOKIE`
|
|
61
|
+
3. MCP 工具调用时传入的 `cookie`
|
|
62
|
+
|
|
63
|
+
当前支持的环境变量:
|
|
64
|
+
|
|
65
|
+
- `METING_NETEASE_COOKIE`
|
|
66
|
+
- `METING_TENCENT_COOKIE`
|
|
67
|
+
- `METING_KUGOU_COOKIE`
|
|
68
|
+
- `METING_BAIDU_COOKIE`
|
|
69
|
+
- `METING_KUWO_COOKIE`
|
|
70
|
+
- `METING_COOKIE`(兜底变量)
|
|
71
|
+
|
|
72
|
+
如果只需要给某一个平台带 cookie,优先使用对应的平台变量;如果想统一兜底,可以只设置 `METING_COOKIE`
|
|
73
|
+
|
|
52
74
|
---
|
|
53
75
|
|
|
54
76
|
关键词: MCP Server | Model Context Protocol | Music API | Node.js MCP | AI Tool Integration | NetEase Cloud Music | Tencent QQ Music | KuGou Music | Baidu Music | Kuwo Music | Lyrics API | Playlist API
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eldment/meting-mcp",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "MCP server wrapper for the Meting multi-platform music API core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/mcp-server.js",
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"start": "node src/index.js",
|
|
19
19
|
"lint": "node --check src/index.js && node --check src/mcp-server.js && node --check src/meting.js && node --check src/providers/index.js && node --check test/test.js && node --check test/example.js",
|
|
20
|
+
"format": "prettier --write .",
|
|
21
|
+
"format:check": "prettier --check .",
|
|
20
22
|
"test": "node test/test.js",
|
|
21
23
|
"example": "node test/example.js",
|
|
22
24
|
"build": "npm pack --dry-run",
|
|
@@ -59,5 +61,8 @@
|
|
|
59
61
|
"dependencies": {
|
|
60
62
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
61
63
|
"zod": "^4.3.6"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"prettier": "^3.6.2"
|
|
62
67
|
}
|
|
63
68
|
}
|
package/src/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { CreateMcpServer, serviceMetadata } from "./mcp-server.js";
|
|
@@ -12,7 +12,7 @@ function GetHelpText() {
|
|
|
12
12
|
"Usage:",
|
|
13
13
|
" meting-mcp Start the MCP stdio server",
|
|
14
14
|
" meting-mcp --help Show help",
|
|
15
|
-
" meting-mcp --version Show version"
|
|
15
|
+
" meting-mcp --version Show version",
|
|
16
16
|
].join("\n");
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -47,7 +47,9 @@ async function Main() {
|
|
|
47
47
|
await StartServer();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
Main().catch(error => {
|
|
51
|
-
process.stderr.write(
|
|
50
|
+
Main().catch((error) => {
|
|
51
|
+
process.stderr.write(
|
|
52
|
+
`meting-mcp failed to start: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}\n`
|
|
53
|
+
);
|
|
52
54
|
process.exit(1);
|
|
53
55
|
});
|
package/src/mcp-server.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
import { createRequire } from "module";
|
|
1
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
3
|
import * as z from "zod/v4";
|
|
3
4
|
import Meting from "./meting.js";
|
|
4
5
|
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const { name: packageName, version } = require("../package.json");
|
|
8
|
+
|
|
9
|
+
const packageUrl = `https://www.npmjs.com/package/${packageName}`;
|
|
10
|
+
|
|
5
11
|
export const serviceMetadata = Object.freeze({
|
|
6
12
|
name: "meting-mcp",
|
|
7
|
-
version
|
|
13
|
+
version,
|
|
14
|
+
title: "Meting MCP",
|
|
15
|
+
description:
|
|
16
|
+
"Search music and fetch song, album, artist, playlist, lyrics, cover, and play URL data across NetEase, Tencent, KuGou, Baidu, and Kuwo.",
|
|
17
|
+
websiteUrl: packageUrl,
|
|
8
18
|
});
|
|
9
19
|
|
|
10
20
|
const platformCatalog = Object.freeze([
|
|
@@ -12,15 +22,36 @@ const platformCatalog = Object.freeze([
|
|
|
12
22
|
{ name: "Tencent Music", code: "tencent" },
|
|
13
23
|
{ name: "KuGou Music", code: "kugou" },
|
|
14
24
|
{ name: "Baidu Music", code: "baidu" },
|
|
15
|
-
{ name: "Kuwo Music", code: "kuwo" }
|
|
25
|
+
{ name: "Kuwo Music", code: "kuwo" },
|
|
16
26
|
]);
|
|
17
27
|
|
|
18
28
|
const platformSchema = z.enum(Meting.getSupportedPlatforms());
|
|
19
29
|
|
|
20
|
-
|
|
30
|
+
const cookieEnvNames = Object.freeze({
|
|
31
|
+
netease: "METING_NETEASE_COOKIE",
|
|
32
|
+
tencent: "METING_TENCENT_COOKIE",
|
|
33
|
+
kugou: "METING_KUGOU_COOKIE",
|
|
34
|
+
baidu: "METING_BAIDU_COOKIE",
|
|
35
|
+
kuwo: "METING_KUWO_COOKIE",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
function ReadEnvValue(name) {
|
|
39
|
+
const value = process.env[name];
|
|
40
|
+
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function ResolveCookie(platform, inputCookie) {
|
|
44
|
+
const platformCookie = ReadEnvValue(cookieEnvNames[platform]);
|
|
45
|
+
const fallbackCookie = ReadEnvValue("METING_COOKIE");
|
|
46
|
+
return platformCookie ?? fallbackCookie ?? inputCookie;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function CreateClient(platform, inputCookie) {
|
|
21
50
|
const meting = new Meting(platform);
|
|
22
51
|
meting.format(true);
|
|
23
52
|
|
|
53
|
+
const cookie = ResolveCookie(platform, inputCookie);
|
|
54
|
+
|
|
24
55
|
if (cookie) {
|
|
25
56
|
meting.cookie(cookie);
|
|
26
57
|
}
|
|
@@ -46,9 +77,9 @@ function CreateTextResult(result, isError = false) {
|
|
|
46
77
|
content: [
|
|
47
78
|
{
|
|
48
79
|
type: "text",
|
|
49
|
-
text: JSON.stringify(result, null, 2)
|
|
50
|
-
}
|
|
51
|
-
]
|
|
80
|
+
text: JSON.stringify(result, null, 2),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
52
83
|
};
|
|
53
84
|
}
|
|
54
85
|
|
|
@@ -57,7 +88,7 @@ function CreateOperationResult(operation, platform, data) {
|
|
|
57
88
|
ok: true,
|
|
58
89
|
operation,
|
|
59
90
|
platform,
|
|
60
|
-
data
|
|
91
|
+
data,
|
|
61
92
|
};
|
|
62
93
|
}
|
|
63
94
|
|
|
@@ -66,27 +97,32 @@ function CreateOperationError(operation, platform, error) {
|
|
|
66
97
|
ok: false,
|
|
67
98
|
operation,
|
|
68
99
|
platform,
|
|
69
|
-
message: error instanceof Error ? error.message : String(error)
|
|
100
|
+
message: error instanceof Error ? error.message : String(error),
|
|
70
101
|
};
|
|
71
102
|
}
|
|
72
103
|
|
|
73
104
|
function WithCommonInput(extraSchema) {
|
|
74
105
|
return {
|
|
75
106
|
platform: platformSchema.describe("Music platform code."),
|
|
76
|
-
cookie: z
|
|
77
|
-
|
|
107
|
+
cookie: z
|
|
108
|
+
.string()
|
|
109
|
+
.optional()
|
|
110
|
+
.describe(
|
|
111
|
+
"Optional platform cookie. Lower priority than METING_<PLATFORM>_COOKIE and METING_COOKIE."
|
|
112
|
+
),
|
|
113
|
+
...extraSchema,
|
|
78
114
|
};
|
|
79
115
|
}
|
|
80
116
|
|
|
81
|
-
function RegisterTool(server, toolName, description, inputSchema, handler) {
|
|
117
|
+
function RegisterTool(server, toolName, title, description, inputSchema, handler) {
|
|
82
118
|
server.registerTool(
|
|
83
119
|
toolName,
|
|
84
120
|
{
|
|
85
|
-
title
|
|
121
|
+
title,
|
|
86
122
|
description,
|
|
87
|
-
inputSchema
|
|
123
|
+
inputSchema,
|
|
88
124
|
},
|
|
89
|
-
async input => {
|
|
125
|
+
async (input) => {
|
|
90
126
|
try {
|
|
91
127
|
const data = await handler(input);
|
|
92
128
|
return CreateTextResult(CreateOperationResult(toolName, input.platform, data));
|
|
@@ -103,13 +139,13 @@ export function CreateMcpServer() {
|
|
|
103
139
|
server.registerTool(
|
|
104
140
|
"platforms",
|
|
105
141
|
{
|
|
106
|
-
title: "
|
|
107
|
-
description: "List supported music platforms."
|
|
142
|
+
title: "List Supported Platforms",
|
|
143
|
+
description: "List supported music platforms.",
|
|
108
144
|
},
|
|
109
145
|
async () => {
|
|
110
146
|
return CreateTextResult({
|
|
111
147
|
ok: true,
|
|
112
|
-
data: platformCatalog
|
|
148
|
+
data: platformCatalog,
|
|
113
149
|
});
|
|
114
150
|
}
|
|
115
151
|
);
|
|
@@ -117,14 +153,20 @@ export function CreateMcpServer() {
|
|
|
117
153
|
RegisterTool(
|
|
118
154
|
server,
|
|
119
155
|
"search",
|
|
156
|
+
"Search Music",
|
|
120
157
|
"Search songs, albums or artists on a specific platform.",
|
|
121
158
|
WithCommonInput({
|
|
122
159
|
keyword: z.string().min(1).describe("Search keyword."),
|
|
123
|
-
type: z
|
|
160
|
+
type: z
|
|
161
|
+
.number()
|
|
162
|
+
.int()
|
|
163
|
+
.positive()
|
|
164
|
+
.optional()
|
|
165
|
+
.describe("Optional platform-specific search type."),
|
|
124
166
|
page: z.number().int().positive().optional().describe("Optional page number."),
|
|
125
|
-
limit: z.number().int().positive().max(100).optional().describe("Optional page size.")
|
|
167
|
+
limit: z.number().int().positive().max(100).optional().describe("Optional page size."),
|
|
126
168
|
}),
|
|
127
|
-
async input => {
|
|
169
|
+
async (input) => {
|
|
128
170
|
const meting = CreateClient(input.platform, input.cookie);
|
|
129
171
|
const options = {};
|
|
130
172
|
|
|
@@ -147,11 +189,12 @@ export function CreateMcpServer() {
|
|
|
147
189
|
RegisterTool(
|
|
148
190
|
server,
|
|
149
191
|
"song",
|
|
192
|
+
"Get Song Details",
|
|
150
193
|
"Get song detail by id.",
|
|
151
194
|
WithCommonInput({
|
|
152
|
-
id: z.string().min(1).describe("Song id.")
|
|
195
|
+
id: z.string().min(1).describe("Song id."),
|
|
153
196
|
}),
|
|
154
|
-
async input => {
|
|
197
|
+
async (input) => {
|
|
155
198
|
const meting = CreateClient(input.platform, input.cookie);
|
|
156
199
|
return ParseResult(await meting.song(input.id));
|
|
157
200
|
}
|
|
@@ -160,11 +203,12 @@ export function CreateMcpServer() {
|
|
|
160
203
|
RegisterTool(
|
|
161
204
|
server,
|
|
162
205
|
"album",
|
|
206
|
+
"Get Album Details",
|
|
163
207
|
"Get album detail by id.",
|
|
164
208
|
WithCommonInput({
|
|
165
|
-
id: z.string().min(1).describe("Album id.")
|
|
209
|
+
id: z.string().min(1).describe("Album id."),
|
|
166
210
|
}),
|
|
167
|
-
async input => {
|
|
211
|
+
async (input) => {
|
|
168
212
|
const meting = CreateClient(input.platform, input.cookie);
|
|
169
213
|
return ParseResult(await meting.album(input.id));
|
|
170
214
|
}
|
|
@@ -173,12 +217,13 @@ export function CreateMcpServer() {
|
|
|
173
217
|
RegisterTool(
|
|
174
218
|
server,
|
|
175
219
|
"artist",
|
|
220
|
+
"Get Artist Works",
|
|
176
221
|
"Get artist songs by id.",
|
|
177
222
|
WithCommonInput({
|
|
178
223
|
id: z.string().min(1).describe("Artist id."),
|
|
179
|
-
limit: z.number().int().positive().max(200).optional().describe("Optional result size.")
|
|
224
|
+
limit: z.number().int().positive().max(200).optional().describe("Optional result size."),
|
|
180
225
|
}),
|
|
181
|
-
async input => {
|
|
226
|
+
async (input) => {
|
|
182
227
|
const meting = CreateClient(input.platform, input.cookie);
|
|
183
228
|
return ParseResult(await meting.artist(input.id, input.limit));
|
|
184
229
|
}
|
|
@@ -187,11 +232,12 @@ export function CreateMcpServer() {
|
|
|
187
232
|
RegisterTool(
|
|
188
233
|
server,
|
|
189
234
|
"playlist",
|
|
235
|
+
"Get Playlist Details",
|
|
190
236
|
"Get playlist detail by id.",
|
|
191
237
|
WithCommonInput({
|
|
192
|
-
id: z.string().min(1).describe("Playlist id.")
|
|
238
|
+
id: z.string().min(1).describe("Playlist id."),
|
|
193
239
|
}),
|
|
194
|
-
async input => {
|
|
240
|
+
async (input) => {
|
|
195
241
|
const meting = CreateClient(input.platform, input.cookie);
|
|
196
242
|
return ParseResult(await meting.playlist(input.id));
|
|
197
243
|
}
|
|
@@ -200,12 +246,13 @@ export function CreateMcpServer() {
|
|
|
200
246
|
RegisterTool(
|
|
201
247
|
server,
|
|
202
248
|
"url",
|
|
249
|
+
"Get Play URL",
|
|
203
250
|
"Get playable song url by id.",
|
|
204
251
|
WithCommonInput({
|
|
205
252
|
id: z.string().min(1).describe("Song id."),
|
|
206
|
-
br: z.number().int().positive().optional().describe("Optional bitrate.")
|
|
253
|
+
br: z.number().int().positive().optional().describe("Optional bitrate."),
|
|
207
254
|
}),
|
|
208
|
-
async input => {
|
|
255
|
+
async (input) => {
|
|
209
256
|
const meting = CreateClient(input.platform, input.cookie);
|
|
210
257
|
return ParseResult(await meting.url(input.id, input.br));
|
|
211
258
|
}
|
|
@@ -214,11 +261,12 @@ export function CreateMcpServer() {
|
|
|
214
261
|
RegisterTool(
|
|
215
262
|
server,
|
|
216
263
|
"lyric",
|
|
264
|
+
"Get Lyrics",
|
|
217
265
|
"Get song lyric by id.",
|
|
218
266
|
WithCommonInput({
|
|
219
|
-
id: z.string().min(1).describe("Song id.")
|
|
267
|
+
id: z.string().min(1).describe("Song id."),
|
|
220
268
|
}),
|
|
221
|
-
async input => {
|
|
269
|
+
async (input) => {
|
|
222
270
|
const meting = CreateClient(input.platform, input.cookie);
|
|
223
271
|
return ParseResult(await meting.lyric(input.id));
|
|
224
272
|
}
|
|
@@ -227,12 +275,13 @@ export function CreateMcpServer() {
|
|
|
227
275
|
RegisterTool(
|
|
228
276
|
server,
|
|
229
277
|
"pic",
|
|
278
|
+
"Get Cover Image",
|
|
230
279
|
"Get cover or picture url by id.",
|
|
231
280
|
WithCommonInput({
|
|
232
281
|
id: z.string().min(1).describe("Picture id."),
|
|
233
|
-
size: z.number().int().positive().optional().describe("Optional picture size.")
|
|
282
|
+
size: z.number().int().positive().optional().describe("Optional picture size."),
|
|
234
283
|
}),
|
|
235
|
-
async input => {
|
|
284
|
+
async (input) => {
|
|
236
285
|
const meting = CreateClient(input.platform, input.cookie);
|
|
237
286
|
return ParseResult(await meting.pic(input.id, input.size));
|
|
238
287
|
}
|
package/src/meting.js
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
* Released under the MIT license
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { URLSearchParams } from
|
|
11
|
-
import ProviderFactory from
|
|
10
|
+
import { URLSearchParams } from "url";
|
|
11
|
+
import ProviderFactory from "./providers/index.js";
|
|
12
12
|
|
|
13
13
|
class Meting {
|
|
14
|
-
constructor(server =
|
|
15
|
-
this.VERSION =
|
|
14
|
+
constructor(server = "netease") {
|
|
15
|
+
this.VERSION = "__VERSION__"; // 在构建时由 rollup 替换为实际版本号
|
|
16
16
|
this.raw = null;
|
|
17
17
|
this.info = null;
|
|
18
18
|
this.error = null;
|
|
@@ -30,7 +30,7 @@ class Meting {
|
|
|
30
30
|
// 设置音乐平台
|
|
31
31
|
site(server) {
|
|
32
32
|
if (!ProviderFactory.isSupported(server)) {
|
|
33
|
-
server =
|
|
33
|
+
server = "netease"; // 默认使用网易云音乐
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
this.server = server;
|
|
@@ -42,7 +42,7 @@ class Meting {
|
|
|
42
42
|
|
|
43
43
|
// 设置 Cookie
|
|
44
44
|
cookie(cookie) {
|
|
45
|
-
this.header[
|
|
45
|
+
this.header["Cookie"] = cookie;
|
|
46
46
|
return this;
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -61,15 +61,15 @@ class Meting {
|
|
|
61
61
|
// HTTP 请求方法 - 使用 fetch API
|
|
62
62
|
async _curl(url, payload = null, headerOnly = false) {
|
|
63
63
|
const requestOptions = {
|
|
64
|
-
method: payload ?
|
|
65
|
-
headers: { ...this.header }
|
|
64
|
+
method: payload ? "POST" : "GET",
|
|
65
|
+
headers: { ...this.header },
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
// 处理请求体
|
|
69
69
|
if (payload) {
|
|
70
|
-
if (typeof payload ===
|
|
70
|
+
if (typeof payload === "object" && !Buffer.isBuffer(payload) && typeof payload !== "string") {
|
|
71
71
|
payload = new URLSearchParams(payload).toString();
|
|
72
|
-
requestOptions.headers[
|
|
72
|
+
requestOptions.headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
73
73
|
}
|
|
74
74
|
requestOptions.body = payload;
|
|
75
75
|
}
|
|
@@ -83,38 +83,38 @@ class Meting {
|
|
|
83
83
|
const makeRequest = async () => {
|
|
84
84
|
try {
|
|
85
85
|
const response = await fetch(url, requestOptions);
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
clearTimeout(timeoutId);
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
// 存储响应信息
|
|
90
90
|
this.info = {
|
|
91
91
|
statusCode: response.status,
|
|
92
|
-
headers: Object.fromEntries(response.headers.entries())
|
|
92
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
93
93
|
};
|
|
94
94
|
|
|
95
95
|
// 获取响应数据
|
|
96
96
|
const data = await response.text();
|
|
97
97
|
this.raw = data;
|
|
98
98
|
this.error = null;
|
|
99
|
-
this.status =
|
|
100
|
-
|
|
99
|
+
this.status = "";
|
|
100
|
+
|
|
101
101
|
return this;
|
|
102
102
|
} catch (err) {
|
|
103
103
|
clearTimeout(timeoutId);
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
// 处理错误
|
|
106
|
-
if (err.name ===
|
|
107
|
-
this.error =
|
|
108
|
-
this.status =
|
|
106
|
+
if (err.name === "AbortError") {
|
|
107
|
+
this.error = "TIMEOUT";
|
|
108
|
+
this.status = "Request timeout";
|
|
109
109
|
} else {
|
|
110
110
|
this.error = err.code || err.name;
|
|
111
111
|
this.status = err.message;
|
|
112
112
|
}
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
// 重试机制
|
|
115
115
|
if (retries > 0) {
|
|
116
116
|
retries--;
|
|
117
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
117
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
118
118
|
return makeRequest();
|
|
119
119
|
} else {
|
|
120
120
|
return this;
|
|
@@ -125,7 +125,6 @@ class Meting {
|
|
|
125
125
|
return await makeRequest();
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
|
|
129
128
|
// ========== 公共 API 方法 ==========
|
|
130
129
|
|
|
131
130
|
// 搜索功能
|