本文档介绍如何为 CeruMusic 开发音乐源插件。CeruMusic 插件是运行在沙箱环境中的 JavaScript 模块,用于从各种音乐平台获取音乐资源。
每个 CeruMusic 插件必须导出以下三个核心组件:
xxxxxxxxxxmodule.exports = { pluginInfo, // 插件信息 sources, // 支持的音源 musicUrl // 获取音乐链接的函数}
xxxxxxxxxx/** * 示例音乐插件 * @author 开发者名称 * @version 1.0.0 */
// 1. 插件信息const pluginInfo = { name: '示例音源插件', version: '1.0.0', author: '开发者名称', description: '这是一个示例音乐源插件'}
// 2. 支持的音源配置const sources = { demo: { name: '示例音源', type: 'music', qualitys: ['128k', '320k', 'flac'] }, demo2: { name: '示例音源2', type: 'music', qualitys: ['128k', '320k'] }}
// 3. 获取音乐URL的核心函数async function musicUrl(source, musicInfo, quality) { // 从 cerumusic 对象获取 API const { request, env, version } = cerumusic
// 构建请求参数 const songId = musicInfo.hash ?? musicInfo.songmid const apiUrl = `https://api.example.com/music/${source}/${songId}/${quality}`
console.log(`[${pluginInfo.name}] 请求音乐链接: ${apiUrl}`)
// 发起网络请求 const { body, statusCode } = await request(apiUrl, { method: 'GET', headers: { 'Content-Type': 'application/json', 'User-Agent': `cerumusic-${env}/${version}` } })
// 处理响应 if (statusCode !== 200 || body.code !== 200) { const errorMessage = body.msg || `接口错误 (HTTP: ${statusCode})` console.error(`[${pluginInfo.name}] Error: ${errorMessage}`) throw new Error(errorMessage) }
console.log(`[${pluginInfo.name}] 获取成功: ${body.url}`) return body.url}
// 4. 可选:获取封面图片async function getPic(source, musicInfo) { const { request } = cerumusic const songId = musicInfo.hash ?? musicInfo.songmid
const { body } = await request(`https://api.example.com/pic/${source}/${songId}`) return body.picUrl}
// 5. 可选:获取歌词async function getLyric(source, musicInfo) { const { request } = cerumusic const songId = musicInfo.hash ?? musicInfo.songmid
const { body } = await request(`https://api.example.com/lyric/${source}/${songId}`) return body.lyric}
// 导出插件module.exports = { pluginInfo, sources, musicUrl, getPic, // 可选 getLyric // 可选}
插件的基本信息,必须包含以下字段:
xxxxxxxxxxconst pluginInfo = { name: '插件名称', // 必需:插件显示名称 version: '1.0.0', // 必需:版本号 author: '作者名', // 必需:作者信息 description: '插件描述' // 必需:功能描述}
定义插件支持的音源,键为音源标识,值为音源配置:
xxxxxxxxxxconst sources = { // 音源标识(用于API调用) source_id: { name: '音源显示名称', // 必需:用户看到的名称 type: 'music', // 必需:固定为 'music' qualitys: [ // 必需:支持的音质列表 '128k', // 标准音质 '320k', // 高音质 'flac', // 无损音质 'flac24bit', // 24位无损 'hires' // 高解析度 ] }}
获取音乐播放链接的核心函数:
xxxxxxxxxxasync function musicUrl(source, musicInfo, quality) { // source: 音源标识(sources 对象的键) // musicInfo: 歌曲信息对象 // quality: 请求的音质 // 返回: Promise<string> - 音乐播放链接}
xxxxxxxxxxconst musicInfo = { songmid: '歌曲ID', // 歌曲标识符 hash: '歌曲哈希', // 备用标识符 title: '歌曲标题', // 歌曲名称 artist: '艺术家', // 演唱者 album: '专辑名' // 专辑信息 // ... 其他可能的字段}
插件运行时可以访问 cerumusic 全局对象:
xxxxxxxxxxconst { request, env, version, utils } = cerumusic
用于发起 HTTP 请求:
xxxxxxxxxx// Promise 模式const response = await request(url, options)
// Callback 模式request(url, options, (error, response) => { if (error) { console.error('请求失败:', error) return } console.log('响应:', response)})
参数说明:
url (string): 请求地址
options (Object): 请求选项
method: HTTP 方法 ('GET', 'POST', 等)
headers: 请求头对象body: 请求体(POST 请求时)响应格式:
xxxxxxxxxx{ body: {}, // 解析后的响应体 statusCode: 200, // HTTP 状态码 headers: {} // 响应头}
提供实用工具函数:
xxxxxxxxxxconst { utils } = cerumusic
// Buffer 操作const buffer = utils.buffer.from('hello', 'utf8')const string = utils.buffer.bufToString(buffer, 'utf8')
总是检查 API 响应状态
xxxxxxxxxxif (statusCode !== 200 || body.code !== 200) { throw new Error(`请求失败: ${body.msg || '未知错误'}`)}
提供有意义的错误信息
xxxxxxxxxxconsole.error(`[${pluginInfo.name}] Error: ${errorMessage}`)throw new Error(errorMessage)
处理网络异常
xxxxxxxxxxtry { const response = await request(url, options) // 处理响应} catch (error) { console.error(`[${pluginInfo.name}] 网络请求失败:`, error.message) throw new Error(`网络错误: ${error.message}`)}
对于使用 lx.on(EVENT_NAMES.request) 模式的插件,可以使用转换器:
xxxxxxxxxx// 使用转换器转换事件驱动插件node converter-event-driven.js input-plugin.js output-plugin.js
转换后的插件将兼容 CeruMusicPluginHost。
xxxxxxxxxxconsole.log(`[${pluginInfo.name}] 调试信息:`, data)console.error(`[${pluginInfo.name}] 错误:`, error)
xxxxxxxxxxconsole.log('请求URL:', url)console.log('请求选项:', options)console.log('响应状态:', statusCode)console.log('响应内容:', body)
创建测试文件:
xxxxxxxxxxconst CeruMusicPluginHost = require('./CeruMusicPluginHost')
async function testPlugin() { const host = new CeruMusicPluginHost() await host.loadPlugin('./my-plugin.js')
const musicInfo = { songmid: 'test123', title: '测试歌曲' }
try { const url = await host.getMusicUrl('demo', musicInfo, '320k') console.log('成功获取URL:', url) } catch (error) { console.error('测试失败:', error.message) }}
testPlugin()
xxxxxxxxxxmy-plugin/├── plugin.js # 主插件文件├── package.json # 包信息(可选)├── README.md # 说明文档└── test.js # 测试文件(可选)
遵循语义化版本规范:
1.0.0 - 主版本.次版本.修订版本查看项目中的示例:
example-plugin.js - 基础插件示例plugin.js - 事件驱动插件示例fm.js - 复杂插件示例Q: 如何处理需要登录的 API?
A: 在请求头中添加认证信息,或使用 Cookie。
Q: 如何处理加密的 API 响应?
A: 在插件中实现解密逻辑,使用 utils 对象提供的工具函数。
Q: 插件可以访问文件系统吗?
A: 不可以,插件运行在受限的沙箱环境中,无法直接访问文件系统。
Q: 如何优化插件性能?
A: 减少不必要的网络请求,使用适当的缓存策略,避免阻塞操作。
欢迎贡献新的音源插件!