@eldment/meting-mcp 1.6.1 → 1.6.3
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/ACKNOWLEDGEMENTS.md +9 -0
- package/README.md +51 -52
- package/package.json +8 -4
- package/src/index.js +6 -4
- package/src/mcp-server.js +63 -31
- 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,77 +1,76 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Meting-MCP
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
6
|
-
- `tencent`
|
|
7
|
-
- `kugou`
|
|
8
|
-
- `baidu`
|
|
9
|
-
- `kuwo`
|
|
5
|
+
## 提供的 MCP 工具
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
发布后可直接运行:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npx @eldment/meting-mcp
|
|
28
|
-
```
|
|
7
|
+
- `platforms`: 列出当前支持的音乐平台及其平台代号
|
|
8
|
+
- `search`: 按关键字在指定平台搜索歌曲、专辑、歌手或其他资源
|
|
9
|
+
- `song`: 按歌曲 ID 获取歌曲详情
|
|
10
|
+
- `album`: 按专辑 ID 获取专辑详情
|
|
11
|
+
- `artist`: 按歌手 ID 获取歌手信息或作品列表
|
|
12
|
+
- `playlist`: 按歌单 ID 获取歌单内容
|
|
13
|
+
- `url`: 按歌曲 ID 获取可播放链接
|
|
14
|
+
- `lyric`: 按歌曲 ID 获取歌词内容
|
|
15
|
+
- `pic`: 按图片或资源 ID 获取封面图链接
|
|
29
16
|
|
|
30
17
|
## MCP 接入
|
|
31
18
|
|
|
32
|
-
示例配置:
|
|
19
|
+
Claude 示例配置:
|
|
33
20
|
|
|
34
21
|
```json
|
|
35
22
|
{
|
|
36
23
|
"mcpServers": {
|
|
37
24
|
"meting": {
|
|
38
25
|
"command": "npx",
|
|
39
|
-
"args": ["-y", "@eldment/meting-mcp"]
|
|
26
|
+
"args": ["-y", "@eldment/meting-mcp@latest"],
|
|
27
|
+
"env": {
|
|
28
|
+
"METING_NETEASE_COOKIE": "...",
|
|
29
|
+
"METING_TENCENT_COOKIE": "..."
|
|
30
|
+
},
|
|
31
|
+
"timeout": 60000
|
|
40
32
|
}
|
|
41
33
|
}
|
|
42
34
|
}
|
|
43
35
|
```
|
|
44
36
|
|
|
45
|
-
|
|
37
|
+
Codex 示例配置:
|
|
38
|
+
|
|
39
|
+
```toml
|
|
40
|
+
[mcp_servers.meting]
|
|
41
|
+
type = "stdio"
|
|
42
|
+
command = "npx"
|
|
43
|
+
args = [
|
|
44
|
+
"-y",
|
|
45
|
+
"@eldment/meting-mcp@latest",
|
|
46
|
+
]
|
|
47
|
+
env = {
|
|
48
|
+
METING_NETEASE_COOKIE = "...",
|
|
49
|
+
METING_TENCENT_COOKIE = "...",
|
|
50
|
+
}
|
|
51
|
+
tool_timeout_sec = 60
|
|
52
|
+
disabled = false
|
|
53
|
+
```
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
- `search`
|
|
49
|
-
- `song`
|
|
50
|
-
- `album`
|
|
51
|
-
- `artist`
|
|
52
|
-
- `playlist`
|
|
53
|
-
- `url`
|
|
54
|
-
- `lyric`
|
|
55
|
-
- `pic`
|
|
55
|
+
## Cookie 配置
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
MCP 运行时会优先从环境变量读取 cookie,再回退到工具输入参数传入的 cookie,优先级如下:
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
1. `METING_<PLATFORM>_COOKIE`
|
|
60
|
+
2. `METING_COOKIE`
|
|
61
|
+
3. MCP 工具调用时传入的 `cookie`
|
|
60
62
|
|
|
61
|
-
|
|
62
|
-
- `cookie`: 可选,对应平台 Cookie
|
|
63
|
+
当前支持的环境变量:
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
- `METING_NETEASE_COOKIE`
|
|
66
|
+
- `METING_TENCENT_COOKIE`
|
|
67
|
+
- `METING_KUGOU_COOKIE`
|
|
68
|
+
- `METING_BAIDU_COOKIE`
|
|
69
|
+
- `METING_KUWO_COOKIE`
|
|
70
|
+
- `METING_COOKIE`(兜底变量)
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
- `song`: `id`
|
|
68
|
-
- `album`: `id`
|
|
69
|
-
- `artist`: `id`,可选 `limit`
|
|
70
|
-
- `playlist`: `id`
|
|
71
|
-
- `url`: `id`,可选 `br`
|
|
72
|
-
- `lyric`: `id`
|
|
73
|
-
- `pic`: `id`,可选 `size`
|
|
72
|
+
如果只需要给某一个平台带 cookie,优先使用对应的平台变量;如果想统一兜底,可以只设置 `METING_COOKIE`
|
|
74
73
|
|
|
75
|
-
|
|
74
|
+
---
|
|
76
75
|
|
|
77
|
-
|
|
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,23 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eldment/meting-mcp",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
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",
|
|
7
|
-
"bin":
|
|
8
|
-
"meting-mcp": "./src/index.js"
|
|
9
|
-
},
|
|
7
|
+
"bin": "./src/index.js",
|
|
10
8
|
"exports": {
|
|
11
9
|
".": "./src/mcp-server.js"
|
|
12
10
|
},
|
|
13
11
|
"files": [
|
|
14
12
|
"src",
|
|
15
13
|
"README.md",
|
|
14
|
+
"ACKNOWLEDGEMENTS.md",
|
|
16
15
|
"LICENSE"
|
|
17
16
|
],
|
|
18
17
|
"scripts": {
|
|
19
18
|
"start": "node src/index.js",
|
|
20
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 .",
|
|
21
22
|
"test": "node test/test.js",
|
|
22
23
|
"example": "node test/example.js",
|
|
23
24
|
"build": "npm pack --dry-run",
|
|
@@ -60,5 +61,8 @@
|
|
|
60
61
|
"dependencies": {
|
|
61
62
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
62
63
|
"zod": "^4.3.6"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"prettier": "^3.6.2"
|
|
63
67
|
}
|
|
64
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
|
@@ -4,7 +4,7 @@ import Meting from "./meting.js";
|
|
|
4
4
|
|
|
5
5
|
export const serviceMetadata = Object.freeze({
|
|
6
6
|
name: "meting-mcp",
|
|
7
|
-
version: "1.6.
|
|
7
|
+
version: "1.6.2",
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
const platformCatalog = Object.freeze([
|
|
@@ -12,15 +12,36 @@ const platformCatalog = Object.freeze([
|
|
|
12
12
|
{ name: "Tencent Music", code: "tencent" },
|
|
13
13
|
{ name: "KuGou Music", code: "kugou" },
|
|
14
14
|
{ name: "Baidu Music", code: "baidu" },
|
|
15
|
-
{ name: "Kuwo Music", code: "kuwo" }
|
|
15
|
+
{ name: "Kuwo Music", code: "kuwo" },
|
|
16
16
|
]);
|
|
17
17
|
|
|
18
18
|
const platformSchema = z.enum(Meting.getSupportedPlatforms());
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
const cookieEnvNames = Object.freeze({
|
|
21
|
+
netease: "METING_NETEASE_COOKIE",
|
|
22
|
+
tencent: "METING_TENCENT_COOKIE",
|
|
23
|
+
kugou: "METING_KUGOU_COOKIE",
|
|
24
|
+
baidu: "METING_BAIDU_COOKIE",
|
|
25
|
+
kuwo: "METING_KUWO_COOKIE",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
function ReadEnvValue(name) {
|
|
29
|
+
const value = process.env[name];
|
|
30
|
+
return typeof value === "string" && value.trim() !== "" ? value : undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function ResolveCookie(platform, inputCookie) {
|
|
34
|
+
const platformCookie = ReadEnvValue(cookieEnvNames[platform]);
|
|
35
|
+
const fallbackCookie = ReadEnvValue("METING_COOKIE");
|
|
36
|
+
return platformCookie ?? fallbackCookie ?? inputCookie;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function CreateClient(platform, inputCookie) {
|
|
21
40
|
const meting = new Meting(platform);
|
|
22
41
|
meting.format(true);
|
|
23
42
|
|
|
43
|
+
const cookie = ResolveCookie(platform, inputCookie);
|
|
44
|
+
|
|
24
45
|
if (cookie) {
|
|
25
46
|
meting.cookie(cookie);
|
|
26
47
|
}
|
|
@@ -46,9 +67,9 @@ function CreateTextResult(result, isError = false) {
|
|
|
46
67
|
content: [
|
|
47
68
|
{
|
|
48
69
|
type: "text",
|
|
49
|
-
text: JSON.stringify(result, null, 2)
|
|
50
|
-
}
|
|
51
|
-
]
|
|
70
|
+
text: JSON.stringify(result, null, 2),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
52
73
|
};
|
|
53
74
|
}
|
|
54
75
|
|
|
@@ -57,7 +78,7 @@ function CreateOperationResult(operation, platform, data) {
|
|
|
57
78
|
ok: true,
|
|
58
79
|
operation,
|
|
59
80
|
platform,
|
|
60
|
-
data
|
|
81
|
+
data,
|
|
61
82
|
};
|
|
62
83
|
}
|
|
63
84
|
|
|
@@ -66,15 +87,20 @@ function CreateOperationError(operation, platform, error) {
|
|
|
66
87
|
ok: false,
|
|
67
88
|
operation,
|
|
68
89
|
platform,
|
|
69
|
-
message: error instanceof Error ? error.message : String(error)
|
|
90
|
+
message: error instanceof Error ? error.message : String(error),
|
|
70
91
|
};
|
|
71
92
|
}
|
|
72
93
|
|
|
73
94
|
function WithCommonInput(extraSchema) {
|
|
74
95
|
return {
|
|
75
96
|
platform: platformSchema.describe("Music platform code."),
|
|
76
|
-
cookie: z
|
|
77
|
-
|
|
97
|
+
cookie: z
|
|
98
|
+
.string()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe(
|
|
101
|
+
"Optional platform cookie. Lower priority than METING_<PLATFORM>_COOKIE and METING_COOKIE."
|
|
102
|
+
),
|
|
103
|
+
...extraSchema,
|
|
78
104
|
};
|
|
79
105
|
}
|
|
80
106
|
|
|
@@ -84,9 +110,9 @@ function RegisterTool(server, toolName, description, inputSchema, handler) {
|
|
|
84
110
|
{
|
|
85
111
|
title: toolName,
|
|
86
112
|
description,
|
|
87
|
-
inputSchema
|
|
113
|
+
inputSchema,
|
|
88
114
|
},
|
|
89
|
-
async input => {
|
|
115
|
+
async (input) => {
|
|
90
116
|
try {
|
|
91
117
|
const data = await handler(input);
|
|
92
118
|
return CreateTextResult(CreateOperationResult(toolName, input.platform, data));
|
|
@@ -104,12 +130,12 @@ export function CreateMcpServer() {
|
|
|
104
130
|
"platforms",
|
|
105
131
|
{
|
|
106
132
|
title: "platforms",
|
|
107
|
-
description: "List supported music platforms."
|
|
133
|
+
description: "List supported music platforms.",
|
|
108
134
|
},
|
|
109
135
|
async () => {
|
|
110
136
|
return CreateTextResult({
|
|
111
137
|
ok: true,
|
|
112
|
-
data: platformCatalog
|
|
138
|
+
data: platformCatalog,
|
|
113
139
|
});
|
|
114
140
|
}
|
|
115
141
|
);
|
|
@@ -120,11 +146,16 @@ export function CreateMcpServer() {
|
|
|
120
146
|
"Search songs, albums or artists on a specific platform.",
|
|
121
147
|
WithCommonInput({
|
|
122
148
|
keyword: z.string().min(1).describe("Search keyword."),
|
|
123
|
-
type: z
|
|
149
|
+
type: z
|
|
150
|
+
.number()
|
|
151
|
+
.int()
|
|
152
|
+
.positive()
|
|
153
|
+
.optional()
|
|
154
|
+
.describe("Optional platform-specific search type."),
|
|
124
155
|
page: z.number().int().positive().optional().describe("Optional page number."),
|
|
125
|
-
limit: z.number().int().positive().max(100).optional().describe("Optional page size.")
|
|
156
|
+
limit: z.number().int().positive().max(100).optional().describe("Optional page size."),
|
|
126
157
|
}),
|
|
127
|
-
async input => {
|
|
158
|
+
async (input) => {
|
|
128
159
|
const meting = CreateClient(input.platform, input.cookie);
|
|
129
160
|
const options = {};
|
|
130
161
|
|
|
@@ -149,9 +180,9 @@ export function CreateMcpServer() {
|
|
|
149
180
|
"song",
|
|
150
181
|
"Get song detail by id.",
|
|
151
182
|
WithCommonInput({
|
|
152
|
-
id: z.string().min(1).describe("Song id.")
|
|
183
|
+
id: z.string().min(1).describe("Song id."),
|
|
153
184
|
}),
|
|
154
|
-
async input => {
|
|
185
|
+
async (input) => {
|
|
155
186
|
const meting = CreateClient(input.platform, input.cookie);
|
|
156
187
|
return ParseResult(await meting.song(input.id));
|
|
157
188
|
}
|
|
@@ -162,9 +193,9 @@ export function CreateMcpServer() {
|
|
|
162
193
|
"album",
|
|
163
194
|
"Get album detail by id.",
|
|
164
195
|
WithCommonInput({
|
|
165
|
-
id: z.string().min(1).describe("Album id.")
|
|
196
|
+
id: z.string().min(1).describe("Album id."),
|
|
166
197
|
}),
|
|
167
|
-
async input => {
|
|
198
|
+
async (input) => {
|
|
168
199
|
const meting = CreateClient(input.platform, input.cookie);
|
|
169
200
|
return ParseResult(await meting.album(input.id));
|
|
170
201
|
}
|
|
@@ -176,9 +207,9 @@ export function CreateMcpServer() {
|
|
|
176
207
|
"Get artist songs by id.",
|
|
177
208
|
WithCommonInput({
|
|
178
209
|
id: z.string().min(1).describe("Artist id."),
|
|
179
|
-
limit: z.number().int().positive().max(200).optional().describe("Optional result size.")
|
|
210
|
+
limit: z.number().int().positive().max(200).optional().describe("Optional result size."),
|
|
180
211
|
}),
|
|
181
|
-
async input => {
|
|
212
|
+
async (input) => {
|
|
182
213
|
const meting = CreateClient(input.platform, input.cookie);
|
|
183
214
|
return ParseResult(await meting.artist(input.id, input.limit));
|
|
184
215
|
}
|
|
@@ -189,9 +220,9 @@ export function CreateMcpServer() {
|
|
|
189
220
|
"playlist",
|
|
190
221
|
"Get playlist detail by id.",
|
|
191
222
|
WithCommonInput({
|
|
192
|
-
id: z.string().min(1).describe("Playlist id.")
|
|
223
|
+
id: z.string().min(1).describe("Playlist id."),
|
|
193
224
|
}),
|
|
194
|
-
async input => {
|
|
225
|
+
async (input) => {
|
|
195
226
|
const meting = CreateClient(input.platform, input.cookie);
|
|
196
227
|
return ParseResult(await meting.playlist(input.id));
|
|
197
228
|
}
|
|
@@ -203,10 +234,11 @@ export function CreateMcpServer() {
|
|
|
203
234
|
"Get playable song url by id.",
|
|
204
235
|
WithCommonInput({
|
|
205
236
|
id: z.string().min(1).describe("Song id."),
|
|
206
|
-
br: z.number().int().positive().optional().describe("Optional bitrate.")
|
|
237
|
+
br: z.number().int().positive().optional().describe("Optional bitrate."),
|
|
207
238
|
}),
|
|
208
|
-
async input => {
|
|
239
|
+
async (input) => {
|
|
209
240
|
const meting = CreateClient(input.platform, input.cookie);
|
|
241
|
+
WithCommonInput;
|
|
210
242
|
return ParseResult(await meting.url(input.id, input.br));
|
|
211
243
|
}
|
|
212
244
|
);
|
|
@@ -216,9 +248,9 @@ export function CreateMcpServer() {
|
|
|
216
248
|
"lyric",
|
|
217
249
|
"Get song lyric by id.",
|
|
218
250
|
WithCommonInput({
|
|
219
|
-
id: z.string().min(1).describe("Song id.")
|
|
251
|
+
id: z.string().min(1).describe("Song id."),
|
|
220
252
|
}),
|
|
221
|
-
async input => {
|
|
253
|
+
async (input) => {
|
|
222
254
|
const meting = CreateClient(input.platform, input.cookie);
|
|
223
255
|
return ParseResult(await meting.lyric(input.id));
|
|
224
256
|
}
|
|
@@ -230,9 +262,9 @@ export function CreateMcpServer() {
|
|
|
230
262
|
"Get cover or picture url by id.",
|
|
231
263
|
WithCommonInput({
|
|
232
264
|
id: z.string().min(1).describe("Picture id."),
|
|
233
|
-
size: z.number().int().positive().optional().describe("Optional picture size.")
|
|
265
|
+
size: z.number().int().positive().optional().describe("Optional picture size."),
|
|
234
266
|
}),
|
|
235
|
-
async input => {
|
|
267
|
+
async (input) => {
|
|
236
268
|
const meting = CreateClient(input.platform, input.cookie);
|
|
237
269
|
return ParseResult(await meting.pic(input.id, input.size));
|
|
238
270
|
}
|
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
|
// 搜索功能
|