2026-07-05 09:10:16 +00:00
|
|
|
|
var https = require('https');
|
|
|
|
|
|
var http = require('http');
|
|
|
|
|
|
var crypto = require('crypto');
|
|
|
|
|
|
var querystring = require('querystring');
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 通用HTTP请求 =====
|
|
|
|
|
|
function doRequest(protocol, options, postData) {
|
|
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
|
|
var client = protocol === 'https' ? https : http;
|
|
|
|
|
|
var req = client.request(options, function(res) {
|
|
|
|
|
|
var chunks = [];
|
|
|
|
|
|
res.on('data', function(chunk) { chunks.push(chunk); });
|
|
|
|
|
|
res.on('end', function() {
|
|
|
|
|
|
var buf = Buffer.concat(chunks);
|
|
|
|
|
|
var body;
|
|
|
|
|
|
try {
|
|
|
|
|
|
body = JSON.parse(buf.toString('utf8'));
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
body = buf.toString('utf8');
|
|
|
|
|
|
}
|
|
|
|
|
|
resolve({ body: body, statusCode: res.statusCode, headers: res.headers });
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
req.on('error', function(err) { reject(err); });
|
|
|
|
|
|
req.setTimeout(15000, function() { req.destroy(); reject(new Error('timeout')); });
|
|
|
|
|
|
if (postData) req.write(postData);
|
|
|
|
|
|
req.end();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function requestUrl(urlStr, method, headers, body) {
|
|
|
|
|
|
var parsed = new URL(urlStr);
|
|
|
|
|
|
var protocol = parsed.protocol.replace(':', '');
|
|
|
|
|
|
var options = {
|
|
|
|
|
|
hostname: parsed.hostname,
|
|
|
|
|
|
port: parsed.port || (protocol === 'https' ? 443 : 80),
|
|
|
|
|
|
path: parsed.pathname + parsed.search,
|
|
|
|
|
|
method: method || 'GET',
|
|
|
|
|
|
headers: headers || {}
|
|
|
|
|
|
};
|
|
|
|
|
|
var postData = null;
|
|
|
|
|
|
if (body) {
|
|
|
|
|
|
if (typeof body === 'string') {
|
|
|
|
|
|
postData = Buffer.from(body, 'utf8');
|
|
|
|
|
|
} else if (Buffer.isBuffer(body)) {
|
|
|
|
|
|
postData = body;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
postData = Buffer.from(JSON.stringify(body), 'utf8');
|
|
|
|
|
|
if (!options.headers['Content-Type']) options.headers['Content-Type'] = 'application/json';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (postData) options.headers['Content-Length'] = postData.length;
|
|
|
|
|
|
}
|
|
|
|
|
|
return doRequest(protocol, options, postData);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 网易云eapi加密 =====
|
|
|
|
|
|
var EAPI_KEY = 'e82ckenh8dichen8';
|
|
|
|
|
|
function aesEncryptEapi(text) {
|
|
|
|
|
|
var cipher = crypto.createCipheriv('aes-128-ecb', EAPI_KEY, '');
|
|
|
|
|
|
var encrypted = cipher.update(text, 'utf8', 'base64');
|
|
|
|
|
|
encrypted += cipher.final('base64');
|
|
|
|
|
|
return encrypted;
|
|
|
|
|
|
}
|
|
|
|
|
|
function eapi(url, params) {
|
|
|
|
|
|
var payload = JSON.stringify({
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
url: url,
|
|
|
|
|
|
params: params
|
|
|
|
|
|
});
|
|
|
|
|
|
return { params: aesEncryptEapi(payload) };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== weapi加密(简化版,用于歌词等) =====
|
|
|
|
|
|
var WEAPI_IV = '0102030405060708';
|
|
|
|
|
|
var WEAPI_PRESET_KEY = '0CoJUm6Qyw8W8jud';
|
|
|
|
|
|
var WEAPI_RSA_PUBKEY = '010001';
|
|
|
|
|
|
var WEAPI_RSA_MODULUS = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7';
|
|
|
|
|
|
function aesEncryptWeapi(text, key) {
|
|
|
|
|
|
var cipher = crypto.createCipheriv('aes-128-cbc', key, WEAPI_IV);
|
|
|
|
|
|
var encrypted = cipher.update(text, 'utf8', 'base64');
|
|
|
|
|
|
encrypted += cipher.final('base64');
|
|
|
|
|
|
return encrypted;
|
|
|
|
|
|
}
|
|
|
|
|
|
function rsaEncryptWeapi(text) {
|
|
|
|
|
|
var reversed = text.split('').reverse().join('');
|
|
|
|
|
|
var input = Buffer.from(reversed, 'utf8').toString('hex');
|
|
|
|
|
|
var bigInput = BigInt('0x' + input);
|
|
|
|
|
|
var bigExp = BigInt('0x' + WEAPI_RSA_PUBKEY);
|
|
|
|
|
|
var bigMod = BigInt('0x' + WEAPI_RSA_MODULUS);
|
|
|
|
|
|
var bigResult = 1n;
|
|
|
|
|
|
var e = bigExp;
|
|
|
|
|
|
var b = bigInput;
|
|
|
|
|
|
while (e > 0n) {
|
|
|
|
|
|
if (e % 2n === 1n) bigResult = (bigResult * b) % bigMod;
|
|
|
|
|
|
b = (b * b) % bigMod;
|
|
|
|
|
|
e = e / 2n;
|
|
|
|
|
|
}
|
|
|
|
|
|
var result = bigResult.toString(16).padStart(256, '0');
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
function weapi(params) {
|
|
|
|
|
|
var text = JSON.stringify(params);
|
|
|
|
|
|
var secretKey = '';
|
|
|
|
|
|
for (var i = 0; i < 16; i++) secretKey += String.fromCharCode(97 + Math.floor(Math.random() * 25));
|
|
|
|
|
|
var encrypted = aesEncryptWeapi(aesEncryptWeapi(text, WEAPI_PRESET_KEY), secretKey);
|
|
|
|
|
|
var encSecKey = rsaEncryptWeapi(secretKey);
|
|
|
|
|
|
return { params: encrypted, encSecKey: encSecKey };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 格式化辅助 =====
|
|
|
|
|
|
function formatPlayTime(seconds) {
|
|
|
|
|
|
var m = Math.floor(seconds / 60);
|
|
|
|
|
|
var s = Math.floor(seconds % 60);
|
|
|
|
|
|
return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function formatSingerName(arr, key) {
|
|
|
|
|
|
if (!arr || !arr.length) return '';
|
|
|
|
|
|
var names = [];
|
|
|
|
|
|
for (var i = 0; i < arr.length; i++) names.push(arr[i][key] || arr[i]);
|
|
|
|
|
|
return names.join('、');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 搜索实现 =====
|
|
|
|
|
|
function musicSearch(str, page, limit) {
|
|
|
|
|
|
var form = eapi('/api/search/song/list/page', {
|
|
|
|
|
|
keyword: str,
|
|
|
|
|
|
needCorrect: '1',
|
|
|
|
|
|
channel: 'typing',
|
|
|
|
|
|
offset: limit * (page - 1),
|
|
|
|
|
|
scene: 'normal',
|
|
|
|
|
|
total: page == 1,
|
|
|
|
|
|
limit: limit
|
|
|
|
|
|
});
|
|
|
|
|
|
return requestUrl('http://interface3.music.163.com/eapi/search/song/list/page', 'POST', {
|
|
|
|
|
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',
|
|
|
|
|
|
'Origin': 'https://music.163.com',
|
|
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
|
|
}, querystring.stringify(form)).then(function(res) {
|
|
|
|
|
|
return res.body;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleSearchResult(rawList) {
|
|
|
|
|
|
if (!rawList) return [];
|
|
|
|
|
|
var list = [];
|
|
|
|
|
|
for (var i = 0; i < rawList.length; i++) {
|
|
|
|
|
|
var item = rawList[i];
|
|
|
|
|
|
if (!item.baseInfo || !item.baseInfo.simpleSongData) continue;
|
|
|
|
|
|
var s = item.baseInfo.simpleSongData;
|
2026-07-05 11:55:58 +00:00
|
|
|
|
var qualities = {};
|
|
|
|
|
|
if (s.l && s.l.size) qualities.standard = String(s.l.size);
|
|
|
|
|
|
if (s.m && s.m.size) qualities.standard = String(s.m.size);
|
|
|
|
|
|
if (s.h && s.h.size) qualities.exhigh = String(s.h.size);
|
|
|
|
|
|
if (s.sq && s.sq.size) qualities.lossless = String(s.sq.size);
|
|
|
|
|
|
if (s.hr && s.hr.size) qualities.hires = String(s.hr.size);
|
|
|
|
|
|
var picUrl = s.al && s.al.picUrl ? s.al.picUrl : '';
|
2026-07-05 09:10:16 +00:00
|
|
|
|
list.push({
|
2026-07-05 11:55:58 +00:00
|
|
|
|
id: s.id,
|
2026-07-05 09:10:16 +00:00
|
|
|
|
name: s.name,
|
2026-07-05 11:55:58 +00:00
|
|
|
|
artists: formatSingerName(s.ar, 'name'),
|
|
|
|
|
|
source: 'wy',
|
|
|
|
|
|
pic: picUrl,
|
|
|
|
|
|
mPic: picUrl,
|
|
|
|
|
|
sPic: picUrl,
|
2026-07-05 09:10:16 +00:00
|
|
|
|
albumName: s.al && s.al.name ? s.al.name : '',
|
|
|
|
|
|
albumId: s.al && s.al.id ? s.al.id : '',
|
|
|
|
|
|
interval: formatPlayTime((s.dt || 0) / 1000),
|
2026-07-05 11:55:58 +00:00
|
|
|
|
qualities: qualities
|
2026-07-05 09:10:16 +00:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function search(str, page, limit, retryNum) {
|
|
|
|
|
|
if (retryNum === undefined) retryNum = 0;
|
|
|
|
|
|
if (++retryNum > 3) return Promise.reject(new Error('try max num'));
|
|
|
|
|
|
if (!limit) limit = 30;
|
|
|
|
|
|
return musicSearch(str, page, limit).then(function(result) {
|
|
|
|
|
|
if (!result || result.code !== 200) return search(str, page, limit, retryNum);
|
|
|
|
|
|
var list = handleSearchResult(result.data && result.data.resources ? result.data.resources : []);
|
|
|
|
|
|
if (!list || list.length === 0) return search(str, page, limit, retryNum);
|
|
|
|
|
|
var total = result.data && result.data.totalCount ? result.data.totalCount : 0;
|
|
|
|
|
|
return {
|
|
|
|
|
|
list: list,
|
|
|
|
|
|
allPage: Math.ceil(total / limit),
|
|
|
|
|
|
limit: limit,
|
|
|
|
|
|
total: total,
|
|
|
|
|
|
source: 'wy'
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 播放链接 =====
|
|
|
|
|
|
function getUrl(songInfo, type) {
|
|
|
|
|
|
var q = type || '128k';
|
2026-07-05 11:35:16 +00:00
|
|
|
|
var songId = songInfo.id || '';
|
2026-07-05 09:10:16 +00:00
|
|
|
|
var ceruKey = process.env.ceru_key || '';
|
|
|
|
|
|
var headers = { 'User-Agent': 'QZMusic/2.0' };
|
|
|
|
|
|
if (ceruKey) headers['X-API-Key'] = ceruKey;
|
|
|
|
|
|
return requestUrl('https://source.shiqianjiang.cn/api/music/url?source=wy&songId=' + encodeURIComponent(songId) + '&quality=' + encodeURIComponent(q), 'GET', headers)
|
|
|
|
|
|
.then(function(res) {
|
|
|
|
|
|
if (res.body && typeof res.body === 'object' && res.body.url) return res.body.url;
|
|
|
|
|
|
if (res.body && typeof res.body === 'object' && res.body.data && res.body.data.url) return res.body.data.url;
|
|
|
|
|
|
if (typeof res.body === 'string' && res.body.indexOf('http') === 0) return res.body;
|
|
|
|
|
|
return '';
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(function() { return ''; });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 封面图 =====
|
|
|
|
|
|
function getPic(songInfo) {
|
2026-07-05 11:55:58 +00:00
|
|
|
|
if (songInfo.pic) return Promise.resolve(songInfo.pic);
|
2026-07-05 09:10:16 +00:00
|
|
|
|
return requestUrl('https://music.163.com/weapi/v3/song/detail', 'POST', {
|
|
|
|
|
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
|
2026-07-05 11:35:16 +00:00
|
|
|
|
'Referer': 'https://music.163.com/song?id=' + songInfo.id,
|
2026-07-05 09:10:16 +00:00
|
|
|
|
'Origin': 'https://music.163.com',
|
|
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
2026-07-05 11:35:16 +00:00
|
|
|
|
}, querystring.stringify(weapi({ c: '[{"id":' + songInfo.id + '}]', ids: '[' + songInfo.id + ']' })))
|
2026-07-05 09:10:16 +00:00
|
|
|
|
.then(function(res) {
|
|
|
|
|
|
if (res.body && res.body.songs && res.body.songs.length) return res.body.songs[0].al.picUrl;
|
|
|
|
|
|
return '';
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(function() { return ''; });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 歌词 =====
|
|
|
|
|
|
function getLyric(songInfo) {
|
2026-07-05 11:35:16 +00:00
|
|
|
|
var songmid = songInfo.id || '';
|
2026-07-05 09:10:16 +00:00
|
|
|
|
return requestUrl('https://music.163.com/api/song/lyric?id=' + songmid + '&lv=1&kv=1&tv=-1', 'GET', {
|
|
|
|
|
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
|
|
|
|
|
|
'Referer': 'https://music.163.com/song?id=' + songmid
|
|
|
|
|
|
}).then(function(res) {
|
|
|
|
|
|
if (res.body && res.body.lrc && res.body.lrc.lyric) return res.body.lrc.lyric;
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}).catch(function() { return ''; });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 音乐详情 =====
|
|
|
|
|
|
function musicDetail(songmid) {
|
|
|
|
|
|
return requestUrl('https://music.163.com/weapi/v3/song/detail', 'POST', {
|
|
|
|
|
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
|
|
|
|
|
|
'Origin': 'https://music.163.com',
|
|
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
|
|
}, querystring.stringify(weapi({ c: '[{"id":' + songmid + '}]', ids: '[' + songmid + ']' })))
|
|
|
|
|
|
.then(function(res) {
|
|
|
|
|
|
if (res.body && res.body.songs && res.body.songs.length) {
|
|
|
|
|
|
var s = res.body.songs[0];
|
2026-07-05 11:55:58 +00:00
|
|
|
|
var picUrl = s.al && s.al.picUrl ? s.al.picUrl : '';
|
2026-07-05 09:10:16 +00:00
|
|
|
|
return {
|
2026-07-05 11:55:58 +00:00
|
|
|
|
id: s.id,
|
2026-07-05 09:10:16 +00:00
|
|
|
|
name: s.name,
|
2026-07-05 11:55:58 +00:00
|
|
|
|
artists: formatSingerName(s.ar, 'name'),
|
|
|
|
|
|
source: 'wy',
|
|
|
|
|
|
pic: picUrl,
|
|
|
|
|
|
mPic: picUrl,
|
|
|
|
|
|
sPic: picUrl,
|
2026-07-05 09:10:16 +00:00
|
|
|
|
albumName: s.al && s.al.name ? s.al.name : '',
|
|
|
|
|
|
albumId: s.al && s.al.id ? s.al.id : '',
|
|
|
|
|
|
interval: formatPlayTime((s.dt || 0) / 1000),
|
2026-07-05 11:55:58 +00:00
|
|
|
|
qualities: {}
|
2026-07-05 09:10:16 +00:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(function() { return null; });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function musicInfo(songmid) {
|
|
|
|
|
|
return musicDetail(songmid);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 热搜 =====
|
|
|
|
|
|
function hotSearch() {
|
|
|
|
|
|
return requestUrl('https://music.163.com/weapi/search/hot', 'POST', {
|
|
|
|
|
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
|
|
|
|
|
|
'Origin': 'https://music.163.com',
|
|
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
|
|
}, querystring.stringify(weapi({ type: 1111 })))
|
|
|
|
|
|
.then(function(res) {
|
|
|
|
|
|
var list = [];
|
|
|
|
|
|
if (res.body && res.body.result && res.body.result.hots) {
|
|
|
|
|
|
for (var i = 0; i < res.body.result.hots.length; i++) list.push(res.body.result.hots[i].first);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { source: 'wy', list: list };
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(function() { return { source: 'wy', list: [] }; });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 搜索建议 =====
|
|
|
|
|
|
function tipSearch(str) {
|
|
|
|
|
|
return requestUrl('https://music.163.com/weapi/search/suggest/web', 'POST', {
|
|
|
|
|
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36',
|
|
|
|
|
|
'Origin': 'https://music.163.com',
|
|
|
|
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
|
|
|
|
}, querystring.stringify(weapi({ s: str, limit: 10 })))
|
|
|
|
|
|
.then(function(res) {
|
|
|
|
|
|
var result = { order: [], songs: [], artists: [], albums: [], playlists: [] };
|
|
|
|
|
|
if (res.body && res.body.result) {
|
|
|
|
|
|
var r = res.body.result;
|
|
|
|
|
|
if (r.songs) { result.order.push('songs'); result.songs = r.songs.map(function(s) { return { name: s.name, id: s.id, source: 'wy' }; }); }
|
|
|
|
|
|
if (r.artists) { result.order.push('artists'); result.artists = r.artists.map(function(a) { return { name: a.name, id: a.id, source: 'wy' }; }); }
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(function() { return { order: [], songs: [], artists: [], albums: [], playlists: [] }; });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 榜单 =====
|
|
|
|
|
|
function leaderboard() {
|
|
|
|
|
|
return Promise.resolve([]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 歌单 =====
|
|
|
|
|
|
function songList() {
|
|
|
|
|
|
return Promise.resolve({ list: [], total: 0, page: 1, source: 'wy' });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 歌手 =====
|
|
|
|
|
|
function singer() {
|
|
|
|
|
|
return Promise.resolve({ source: 'wy', list: [], total: 0 });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 专辑 =====
|
|
|
|
|
|
function album() {
|
|
|
|
|
|
return Promise.resolve({ source: 'wy', list: [], total: 0 });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ===== 插件信息 =====
|
2026-07-05 10:51:00 +00:00
|
|
|
|
var pluginInfo = {
|
|
|
|
|
|
info: {
|
|
|
|
|
|
id: 'koneko_ceru_wy',
|
|
|
|
|
|
name: '网易云音乐 - Koneko 聆澜',
|
|
|
|
|
|
version: '0.0.3',
|
|
|
|
|
|
source: 'wy',
|
|
|
|
|
|
description: '网易云音乐音源,基于 CeruMusic musicSdk 搜索 + Ceru 播放接口'
|
|
|
|
|
|
},
|
2026-07-05 10:39:47 +00:00
|
|
|
|
ext: [],
|
|
|
|
|
|
env: [{ key: 'ceru_key', name: 'Ceru API Key', description: '聆澜播放接口密钥' }],
|
|
|
|
|
|
quality: [
|
|
|
|
|
|
{ name: '标准', ui: '标', id: '128k' },
|
|
|
|
|
|
{ name: '高品', ui: 'HQ', id: '320k' },
|
|
|
|
|
|
{ name: '无损', ui: 'SQ', id: 'flac' }
|
|
|
|
|
|
],
|
2026-07-05 10:51:00 +00:00
|
|
|
|
supportFunc: []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
module.exports = {
|
2026-07-05 09:10:16 +00:00
|
|
|
|
musicSearch: { search: search },
|
|
|
|
|
|
tipSearch: { search: tipSearch },
|
|
|
|
|
|
hotSearch: { getList: hotSearch },
|
|
|
|
|
|
leaderboard: { getBoards: leaderboard },
|
2026-07-05 10:51:00 +00:00
|
|
|
|
songList: songList,
|
2026-07-05 11:35:16 +00:00
|
|
|
|
artists: singer,
|
2026-07-05 10:51:00 +00:00
|
|
|
|
album: album,
|
2026-07-05 09:10:16 +00:00
|
|
|
|
getLyric: getLyric,
|
|
|
|
|
|
getPic: getPic,
|
|
|
|
|
|
getUrl: getUrl,
|
|
|
|
|
|
musicDetail: musicDetail,
|
2026-07-05 10:51:00 +00:00
|
|
|
|
musicInfo: musicInfo,
|
|
|
|
|
|
pluginInfo: pluginInfo
|
2026-07-05 09:10:16 +00:00
|
|
|
|
};
|