@eldment/meting-mcp 1.6.1
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/LICENSE +21 -0
- package/README.md +77 -0
- package/package.json +64 -0
- package/src/index.js +53 -0
- package/src/mcp-server.js +242 -0
- package/src/meting.js +192 -0
- package/src/providers/baidu.js +280 -0
- package/src/providers/base.js +247 -0
- package/src/providers/index.js +49 -0
- package/src/providers/kugou.js +417 -0
- package/src/providers/kuwo.js +226 -0
- package/src/providers/netease.js +363 -0
- package/src/providers/tencent.js +328 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import BaseProvider from './base.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 百度音乐平台提供者
|
|
6
|
+
*/
|
|
7
|
+
export default class BaiduProvider extends BaseProvider {
|
|
8
|
+
constructor(meting) {
|
|
9
|
+
super(meting);
|
|
10
|
+
this.name = 'baidu';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 获取百度音乐的请求头配置
|
|
15
|
+
*/
|
|
16
|
+
getHeaders() {
|
|
17
|
+
return {
|
|
18
|
+
'Cookie': `BAIDUID=${this._getRandomHex(32)}:FG=1`,
|
|
19
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) baidu-music/1.2.1 Chrome/66.0.3359.181 Electron/3.0.5 Safari/537.36',
|
|
20
|
+
'Accept': '*/*',
|
|
21
|
+
'Content-Type': 'application/json;charset=UTF-8',
|
|
22
|
+
'Accept-Language': 'zh-CN'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 搜索歌曲
|
|
28
|
+
*/
|
|
29
|
+
search(keyword, option = {}) {
|
|
30
|
+
return {
|
|
31
|
+
method: 'GET',
|
|
32
|
+
url: 'http://musicapi.taihe.com/v1/restserver/ting',
|
|
33
|
+
body: {
|
|
34
|
+
from: 'qianqianmini',
|
|
35
|
+
method: 'baidu.ting.search.merge',
|
|
36
|
+
isNew: 1,
|
|
37
|
+
platform: 'darwin',
|
|
38
|
+
page_no: option.page || 1,
|
|
39
|
+
query: keyword,
|
|
40
|
+
version: '11.2.1',
|
|
41
|
+
page_size: option.limit || 30
|
|
42
|
+
},
|
|
43
|
+
format: 'result.song_info.song_list'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 获取歌曲详情
|
|
49
|
+
*/
|
|
50
|
+
song(id) {
|
|
51
|
+
return {
|
|
52
|
+
method: 'GET',
|
|
53
|
+
url: 'http://musicapi.taihe.com/v1/restserver/ting',
|
|
54
|
+
body: {
|
|
55
|
+
from: 'qianqianmini',
|
|
56
|
+
method: 'baidu.ting.song.getInfos',
|
|
57
|
+
songid: id,
|
|
58
|
+
res: 1,
|
|
59
|
+
platform: 'darwin',
|
|
60
|
+
version: '1.0.0'
|
|
61
|
+
},
|
|
62
|
+
encode: 'baidu_AESCBC',
|
|
63
|
+
format: 'songinfo'
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 获取专辑信息
|
|
69
|
+
*/
|
|
70
|
+
album(id) {
|
|
71
|
+
return {
|
|
72
|
+
method: 'GET',
|
|
73
|
+
url: 'http://musicapi.taihe.com/v1/restserver/ting',
|
|
74
|
+
body: {
|
|
75
|
+
from: 'qianqianmini',
|
|
76
|
+
method: 'baidu.ting.album.getAlbumInfo',
|
|
77
|
+
album_id: id,
|
|
78
|
+
platform: 'darwin',
|
|
79
|
+
version: '11.2.1'
|
|
80
|
+
},
|
|
81
|
+
format: 'songlist'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 获取艺术家作品
|
|
87
|
+
*/
|
|
88
|
+
artist(id, limit = 50) {
|
|
89
|
+
return {
|
|
90
|
+
method: 'GET',
|
|
91
|
+
url: 'http://musicapi.taihe.com/v1/restserver/ting',
|
|
92
|
+
body: {
|
|
93
|
+
from: 'qianqianmini',
|
|
94
|
+
method: 'baidu.ting.artist.getSongList',
|
|
95
|
+
artistid: id,
|
|
96
|
+
limits: limit,
|
|
97
|
+
platform: 'darwin',
|
|
98
|
+
offset: 0,
|
|
99
|
+
tinguid: 0,
|
|
100
|
+
version: '11.2.1'
|
|
101
|
+
},
|
|
102
|
+
format: 'songlist'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 获取播放列表
|
|
108
|
+
*/
|
|
109
|
+
playlist(id) {
|
|
110
|
+
return {
|
|
111
|
+
method: 'GET',
|
|
112
|
+
url: 'http://musicapi.taihe.com/v1/restserver/ting',
|
|
113
|
+
body: {
|
|
114
|
+
from: 'qianqianmini',
|
|
115
|
+
method: 'baidu.ting.diy.gedanInfo',
|
|
116
|
+
listid: id,
|
|
117
|
+
platform: 'darwin',
|
|
118
|
+
version: '11.2.1'
|
|
119
|
+
},
|
|
120
|
+
format: 'content'
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 获取音频播放链接
|
|
126
|
+
*/
|
|
127
|
+
url(id, br = 320) {
|
|
128
|
+
return {
|
|
129
|
+
method: 'GET',
|
|
130
|
+
url: 'http://musicapi.taihe.com/v1/restserver/ting',
|
|
131
|
+
body: {
|
|
132
|
+
from: 'qianqianmini',
|
|
133
|
+
method: 'baidu.ting.song.getInfos',
|
|
134
|
+
songid: id,
|
|
135
|
+
res: 1,
|
|
136
|
+
platform: 'darwin',
|
|
137
|
+
version: '1.0.0'
|
|
138
|
+
},
|
|
139
|
+
encode: 'baidu_AESCBC',
|
|
140
|
+
decode: 'baidu_url'
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 获取歌词
|
|
146
|
+
*/
|
|
147
|
+
lyric(id) {
|
|
148
|
+
return {
|
|
149
|
+
method: 'GET',
|
|
150
|
+
url: 'http://musicapi.taihe.com/v1/restserver/ting',
|
|
151
|
+
body: {
|
|
152
|
+
from: 'qianqianmini',
|
|
153
|
+
method: 'baidu.ting.song.lry',
|
|
154
|
+
songid: id,
|
|
155
|
+
platform: 'darwin',
|
|
156
|
+
version: '1.0.0'
|
|
157
|
+
},
|
|
158
|
+
decode: 'baidu_lyric'
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 获取封面图片
|
|
164
|
+
*/
|
|
165
|
+
async pic(id, size = 300) {
|
|
166
|
+
const format = this.meting.isFormat;
|
|
167
|
+
const data = await this.meting.format(false).song(id);
|
|
168
|
+
this.meting.isFormat = format;
|
|
169
|
+
const songData = JSON.parse(data);
|
|
170
|
+
const url = songData.songinfo.pic_radio || songData.songinfo.pic_small;
|
|
171
|
+
return JSON.stringify({ url: url });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 格式化百度音乐数据
|
|
176
|
+
*/
|
|
177
|
+
format(data) {
|
|
178
|
+
return {
|
|
179
|
+
id: data.song_id,
|
|
180
|
+
name: data.title,
|
|
181
|
+
artist: data.author ? data.author.split(',') : [],
|
|
182
|
+
album: data.album_title || '',
|
|
183
|
+
pic_id: data.song_id,
|
|
184
|
+
url_id: data.song_id,
|
|
185
|
+
lyric_id: data.song_id,
|
|
186
|
+
source: 'baidu'
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 处理百度音乐的编码/解码逻辑
|
|
192
|
+
*/
|
|
193
|
+
async handleEncode(api) {
|
|
194
|
+
if (api.encode === 'baidu_AESCBC') {
|
|
195
|
+
return this.aesEncrypt(api);
|
|
196
|
+
}
|
|
197
|
+
return api;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async handleDecode(decodeType, data) {
|
|
201
|
+
if (decodeType === 'baidu_url') {
|
|
202
|
+
return this.urlDecode(data);
|
|
203
|
+
} else if (decodeType === 'baidu_lyric') {
|
|
204
|
+
return this.lyricDecode(data);
|
|
205
|
+
}
|
|
206
|
+
return data;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 百度音乐 AES 加密
|
|
211
|
+
*/
|
|
212
|
+
async aesEncrypt(api) {
|
|
213
|
+
const key = 'DBEECF8C50FD160E';
|
|
214
|
+
const vi = '1231021386755796';
|
|
215
|
+
|
|
216
|
+
const data = `songid=${api.body.songid}&ts=${Date.now()}`;
|
|
217
|
+
|
|
218
|
+
const cipher = crypto.createCipheriv('aes-128-cbc', key, vi);
|
|
219
|
+
cipher.setAutoPadding(true);
|
|
220
|
+
let encrypted = cipher.update(data, 'utf8', 'base64');
|
|
221
|
+
encrypted += cipher.final('base64');
|
|
222
|
+
|
|
223
|
+
api.body.e = encrypted;
|
|
224
|
+
|
|
225
|
+
return api;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 百度音乐 URL 解码
|
|
230
|
+
*/
|
|
231
|
+
urlDecode(result) {
|
|
232
|
+
const data = JSON.parse(result);
|
|
233
|
+
|
|
234
|
+
let maxBr = 0;
|
|
235
|
+
let url;
|
|
236
|
+
|
|
237
|
+
data.songurl.url.forEach(item => {
|
|
238
|
+
if (item.file_bitrate <= this.meting.temp.br && item.file_bitrate > maxBr) {
|
|
239
|
+
maxBr = item.file_bitrate;
|
|
240
|
+
url = {
|
|
241
|
+
url: item.file_link,
|
|
242
|
+
br: item.file_bitrate
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (!url) {
|
|
248
|
+
url = {
|
|
249
|
+
url: '',
|
|
250
|
+
br: -1
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return JSON.stringify(url);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* 百度音乐歌词解码
|
|
259
|
+
*/
|
|
260
|
+
lyricDecode(result) {
|
|
261
|
+
const data = JSON.parse(result);
|
|
262
|
+
const lyricData = {
|
|
263
|
+
lyric: data.lrcContent || '',
|
|
264
|
+
tlyric: ''
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
return JSON.stringify(lyricData);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ========== 私有工具方法 ==========
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* 生成随机十六进制字符串
|
|
274
|
+
*/
|
|
275
|
+
_getRandomHex(length) {
|
|
276
|
+
return crypto.randomBytes(Math.ceil(length / 2))
|
|
277
|
+
.toString('hex')
|
|
278
|
+
.slice(0, length);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 音乐平台提供者基础类
|
|
3
|
+
* 定义所有音乐平台提供者需要实现的接口
|
|
4
|
+
*/
|
|
5
|
+
export default class BaseProvider {
|
|
6
|
+
constructor(meting) {
|
|
7
|
+
this.meting = meting;
|
|
8
|
+
this.name = 'base';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 获取平台的请求头配置
|
|
13
|
+
* @returns {Object} 请求头对象
|
|
14
|
+
*/
|
|
15
|
+
getHeaders() {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 搜索歌曲
|
|
21
|
+
* @param {string} keyword 搜索关键词
|
|
22
|
+
* @param {Object} [option={}] 搜索选项
|
|
23
|
+
* @returns {Object} API 配置对象
|
|
24
|
+
*/
|
|
25
|
+
search(keyword, option = {}) {
|
|
26
|
+
throw new Error(`${this.name} provider must implement search method`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 获取歌曲详情
|
|
31
|
+
* @param {string} id 歌曲ID
|
|
32
|
+
* @returns {Object} API 配置对象
|
|
33
|
+
*/
|
|
34
|
+
song(id) {
|
|
35
|
+
throw new Error(`${this.name} provider must implement song method`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 获取专辑信息
|
|
40
|
+
* @param {string} id 专辑ID
|
|
41
|
+
* @returns {Object} API 配置对象
|
|
42
|
+
*/
|
|
43
|
+
album(id) {
|
|
44
|
+
throw new Error(`${this.name} provider must implement album method`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 获取艺术家作品
|
|
49
|
+
* @param {string} id 艺术家ID
|
|
50
|
+
* @param {number} limit 限制数量
|
|
51
|
+
* @returns {Object} API 配置对象
|
|
52
|
+
*/
|
|
53
|
+
artist(id, limit = 50) {
|
|
54
|
+
throw new Error(`${this.name} provider must implement artist method`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 获取播放列表
|
|
59
|
+
* @param {string} id 播放列表ID
|
|
60
|
+
* @returns {Object} API 配置对象
|
|
61
|
+
*/
|
|
62
|
+
playlist(id) {
|
|
63
|
+
throw new Error(`${this.name} provider must implement playlist method`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 获取音频播放链接
|
|
68
|
+
* @param {string} id 歌曲ID
|
|
69
|
+
* @param {number} br 比特率
|
|
70
|
+
* @returns {Object} API 配置对象
|
|
71
|
+
*/
|
|
72
|
+
url(id, br = 320) {
|
|
73
|
+
throw new Error(`${this.name} provider must implement url method`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 获取歌词
|
|
78
|
+
* @param {string} id 歌曲ID
|
|
79
|
+
* @returns {Object} API 配置对象
|
|
80
|
+
*/
|
|
81
|
+
lyric(id) {
|
|
82
|
+
throw new Error(`${this.name} provider must implement lyric method`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 获取封面图片
|
|
87
|
+
* @param {string} id 图片ID
|
|
88
|
+
* @param {number} size 图片尺寸
|
|
89
|
+
* @returns {Promise<string>} 图片URL的JSON字符串
|
|
90
|
+
*/
|
|
91
|
+
async pic(id, size = 300) {
|
|
92
|
+
throw new Error(`${this.name} provider must implement pic method`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 格式化数据
|
|
97
|
+
* @param {Object} data 原始数据
|
|
98
|
+
* @returns {Object} 格式化后的数据
|
|
99
|
+
*/
|
|
100
|
+
format(data) {
|
|
101
|
+
throw new Error(`${this.name} provider must implement format method`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* URL 解码方法(如果需要)
|
|
106
|
+
* @param {string} result 原始结果
|
|
107
|
+
* @returns {string} 解码后的结果
|
|
108
|
+
*/
|
|
109
|
+
urlDecode(result) {
|
|
110
|
+
// 默认实现,子类可以覆盖
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 歌词解码方法(如果需要)
|
|
116
|
+
* @param {string} result 原始结果
|
|
117
|
+
* @returns {string} 解码后的结果
|
|
118
|
+
*/
|
|
119
|
+
lyricDecode(result) {
|
|
120
|
+
// 默认实现,子类可以覆盖
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 执行完整的 API 请求流程
|
|
126
|
+
* @param {Object} api API 配置对象
|
|
127
|
+
* @param {Object} meting Meting 实例
|
|
128
|
+
* @returns {string} 处理后的结果
|
|
129
|
+
*/
|
|
130
|
+
async executeRequest(api, meting) {
|
|
131
|
+
// 如果有编码方法,先进行编码
|
|
132
|
+
if (api.encode) {
|
|
133
|
+
api = await this.handleEncode(api);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 处理 GET 请求的参数
|
|
137
|
+
if (api.method === 'GET' && api.body) {
|
|
138
|
+
const params = new URLSearchParams(api.body);
|
|
139
|
+
api.url += '?' + params.toString();
|
|
140
|
+
api.body = null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 发送 HTTP 请求
|
|
144
|
+
await meting._curl(api.url, api.body);
|
|
145
|
+
|
|
146
|
+
// 如果不需要格式化,直接返回原始数据
|
|
147
|
+
if (!meting.isFormat) {
|
|
148
|
+
return meting.raw;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let data = meting.raw;
|
|
152
|
+
|
|
153
|
+
// 如果有解码方法,进行解码
|
|
154
|
+
if (api.decode) {
|
|
155
|
+
data = await this.handleDecode(api.decode, data);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 如果有格式化规则,进行数据清理
|
|
159
|
+
if ('format' in api) {
|
|
160
|
+
data = this.cleanData(data, api.format, meting);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return data;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 处理编码逻辑
|
|
168
|
+
* @param {Object} api API 配置对象
|
|
169
|
+
* @returns {Object} 编码后的 API 配置
|
|
170
|
+
*/
|
|
171
|
+
async handleEncode(api) {
|
|
172
|
+
// 子类可以覆盖此方法来处理特定的编码逻辑
|
|
173
|
+
return api;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* 处理解码逻辑
|
|
178
|
+
* @param {string} decodeType 解码类型
|
|
179
|
+
* @param {string} data 原始数据
|
|
180
|
+
* @returns {string} 解码后的数据
|
|
181
|
+
*/
|
|
182
|
+
async handleDecode(decodeType, data) {
|
|
183
|
+
// 根据解码类型调用相应的方法
|
|
184
|
+
if (decodeType.includes('url')) {
|
|
185
|
+
return this.urlDecode(data);
|
|
186
|
+
} else if (decodeType.includes('lyric')) {
|
|
187
|
+
return this.lyricDecode(data);
|
|
188
|
+
}
|
|
189
|
+
return data;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 数据清理方法
|
|
194
|
+
* @param {string} raw 原始数据
|
|
195
|
+
* @param {string} rule 提取规则
|
|
196
|
+
* @param {Object} meting Meting 实例
|
|
197
|
+
* @returns {string} 清理后的数据
|
|
198
|
+
*/
|
|
199
|
+
cleanData(raw, rule, meting) {
|
|
200
|
+
let data;
|
|
201
|
+
try {
|
|
202
|
+
data = JSON.parse(raw);
|
|
203
|
+
} catch (e) {
|
|
204
|
+
return JSON.stringify([]);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (rule) {
|
|
208
|
+
data = this.pickupData(data, rule);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!Array.isArray(data) && typeof data === 'object' && data !== null) {
|
|
212
|
+
data = [data];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!Array.isArray(data)) {
|
|
216
|
+
return JSON.stringify([]);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 使用当前 provider 的格式化方法
|
|
220
|
+
if (typeof this.format === 'function') {
|
|
221
|
+
const result = data.map(item => this.format(item));
|
|
222
|
+
return JSON.stringify(result);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return JSON.stringify(data);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* 数据提取方法
|
|
230
|
+
* @param {Object} array 数据对象
|
|
231
|
+
* @param {string} rule 提取规则
|
|
232
|
+
* @returns {Object} 提取后的数据
|
|
233
|
+
*/
|
|
234
|
+
pickupData(array, rule) {
|
|
235
|
+
const parts = rule.split('.');
|
|
236
|
+
let result = array;
|
|
237
|
+
|
|
238
|
+
for (const part of parts) {
|
|
239
|
+
if (!result || typeof result !== 'object' || !(part in result)) {
|
|
240
|
+
return {};
|
|
241
|
+
}
|
|
242
|
+
result = result[part];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return result;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import NeteaseProvider from './netease.js';
|
|
2
|
+
import TencentProvider from './tencent.js';
|
|
3
|
+
import KugouProvider from './kugou.js';
|
|
4
|
+
import BaiduProvider from './baidu.js';
|
|
5
|
+
import KuwoProvider from './kuwo.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 音乐平台提供者工厂
|
|
9
|
+
*/
|
|
10
|
+
export default class ProviderFactory {
|
|
11
|
+
static providers = {
|
|
12
|
+
netease: NeteaseProvider,
|
|
13
|
+
tencent: TencentProvider,
|
|
14
|
+
kugou: KugouProvider,
|
|
15
|
+
baidu: BaiduProvider,
|
|
16
|
+
kuwo: KuwoProvider
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 创建指定平台的提供者实例
|
|
21
|
+
* @param {string} platform 平台名称
|
|
22
|
+
* @param {Object} meting Meting 实例
|
|
23
|
+
* @returns {BaseProvider} 平台提供者实例
|
|
24
|
+
*/
|
|
25
|
+
static create(platform, meting) {
|
|
26
|
+
const ProviderClass = this.providers[platform];
|
|
27
|
+
if (!ProviderClass) {
|
|
28
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
29
|
+
}
|
|
30
|
+
return new ProviderClass(meting);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 获取支持的平台列表
|
|
35
|
+
* @returns {string[]} 支持的平台名称数组
|
|
36
|
+
*/
|
|
37
|
+
static getSupportedPlatforms() {
|
|
38
|
+
return Object.keys(this.providers);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 检查平台是否支持
|
|
43
|
+
* @param {string} platform 平台名称
|
|
44
|
+
* @returns {boolean} 是否支持
|
|
45
|
+
*/
|
|
46
|
+
static isSupported(platform) {
|
|
47
|
+
return platform in this.providers;
|
|
48
|
+
}
|
|
49
|
+
}
|