Skip to content

CeruMusic 插件开发指南

概述

CeruMusic 支持两种类型的插件:

  1. CeruMusic 原生插件:基于 CeruMusic API 的插件格式
  2. LX 兼容插件:兼容 LX Music 的事件驱动插件格式

本文档将详细介绍如何开发这两种类型的插件。

文件要求

  • 编码格式:UTF-8
  • 编程语言:JavaScript (支持 ES6+ 语法)
  • 文件扩展名.js

插件信息注释

所有插件文件的开头必须包含以下注释格式:

javascript
/**
 * @name 插件名称
 * @description 插件描述
 * @version 1.0.0
 * @author 作者名称
 * @homepage https://example.com
 */

注释字段说明

  • @name:插件名称,建议不超过 24 个字符
  • @description:插件描述,建议不超过 36 个字符(可选)
  • @version:版本号(可选)
  • @author:作者名称(可选)
  • @homepage:主页地址(可选)

CeruMusic 原生插件开发

首先 澜音 插件是面向 方法的 这意味着你直接导出方法即可为播放器提供音源

基本结构

javascript
/**
 * @name 示例音乐源
 * @description CeruMusic 原生插件示例
 * @version 1.0.0
 * @author CeruMusic Team
 */

// 插件信息
const pluginInfo = {
  name: "示例音乐源",
  version: "1.0.0",
  author: "CeruMusic Team",
  description: "这是一个示例插件"
};

// 支持的音源配置
const sources = {
  kw:{
    name: "酷我音乐",
    qualitys: ['128k', '320k', 'flac', 'flac24bit']
  },
  tx:{
    name: "QQ音乐",
    qualitys: ['128k', '320k', 'flac']
  }
};

// 获取音乐链接的主要方法
async function musicUrl(source, musicInfo, quality) {
  try {
    // 使用 cerumusic API 发送 HTTP 请求
    const result = await cerumusic.request('https://api.example.com/music', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
        ...你的其他参数 可以 是密钥或者其他...
      },
      body: JSON.stringify({
        id: musicInfo.id,
        qualitys: quality
      })
    });

    if (result.statusCode === 200 && result.body.url) {
      return result.body.url;
    } else {
      throw new Error('获取音乐链接失败');
    }
  } catch (error) {
    console.error('获取音乐链接时发生错误:', error);
    throw error;
  }
}

// 获取歌曲封面(可选)
async function getPic(source, musicInfo) {
  try {
    const result = await cerumusic.request(`https://api.example.com/pic/${musicInfo.id}`);
    return result.body.picUrl;
  } catch (error) {
    throw new Error('获取封面失败: ' + error.message);
  }
}

// 获取歌词(可选)
async function getLyric(source, musicInfo) {
  try {
    const result = await cerumusic.request(`https://api.example.com/lyric/${musicInfo.id}`);
    return result.body.lyric;
  } catch (error) {
    throw new Error('获取歌词失败: ' + error.message);
  }
}

// 导出插件
module.exports = {
  pluginInfo,
  sources,
  musicUrl,
  getPic,    // 可选
  getLyric   // 可选
};

PS:

  • sources key 取值

    • wy 网易云音乐 |
    • tx QQ音乐 |
    • kg 酷狗音乐 |
    • mg 咪咕音乐 |
    • kw 酷我音乐
  • 导出

    javascript
    module.exports = {
      sources // 你的音源支持
    }
  • 支持的音质 sources.qualitys: ['128k', '320k', 'flac']

    • 128k: 128kbps
    • 320k: 320kbps
    • flac: FLAC 无损
    • flac24bit: 24bit FLAC
    • hires: Hi-Res 高解析度
    • atmos: 杜比全景声
    • master: 母带音质

CeruMusic API 参考

cerumusic.request(url, options)

HTTP 请求方法,返回 Promise。

参数:

  • url (string): 请求地址
  • options (object): 请求选项
    • method: 请求方法 (GET, POST, PUT, DELETE 等)
    • headers: 请求头对象
    • body: 请求体
    • timeout: 超时时间(毫秒)

返回值:

javascript
{
  statusCode: 200,
  headers: {...},
  body: {...}  // 自动解析的响应体
}

cerumusic.utils

工具方法集合:

javascript
// Buffer 操作
cerumusic.utils.buffer.from(data, encoding)
cerumusic.utils.buffer.bufToString(buffer, encoding)

// 加密工具
cerumusic.utils.crypto.md5(str)
cerumusic.utils.crypto.randomBytes(size)
cerumusic.utils.crypto.aesEncrypt(data, mode, key, iv)
cerumusic.utils.crypto.rsaEncrypt(data, key)

cerumusic.NoticeCenter(type, data)

发送通知到用户界面:

javascript
cerumusic.NoticeCenter('info', {
  title: '通知标题',
  content: '通知内容',
  url: 'https://example.com', // 可选 当通知为update 版本跟新可传
  version: '版本号', // 当通知为update 版本跟新可传
  pluginInfo: {
    name: '插件名称',
    type: 'cr' // 固定唯一标识
  } // 当通知为update 版本跟新可传
})

通知类型:

  • 'info': 信息通知
  • 'success': 成功通知
  • 'warn': 警告通知
  • 'error': 错误通知
  • 'update': 更新通知

LX 兼容插件开发 引用于落雪官网改编

CeruMusic 完全兼容 LX Music 的插件格式,支持事件驱动的开发模式。

基本结构

javascript
/**
 * @name 测试音乐源
 * @description 我只是一个测试音乐源哦
 * @version 1.0.0
 * @author xxx
 * @homepage http://xxx
 */

const { EVENT_NAMES, request, on, send } = globalThis.lx

// 音质配置
const qualitys = {
  kw: {
    '128k': '128',
    '320k': '320',
    flac: 'flac',
    flac24bit: 'flac24bit'
  },
  local: {}
}

// HTTP 请求封装
const httpRequest = (url, options) =>
  new Promise((resolve, reject) => {
    request(url, options, (err, resp) => {
      if (err) return reject(err)
      resolve(resp.body)
    })
  })

// API 实现
const apis = {
  kw: {
    musicUrl({ songmid }, quality) {
      return httpRequest('http://xxx').then((data) => {
        return data.url
      })
    }
  },
  local: {
    musicUrl(info) {
      return httpRequest('http://xxx').then((data) => {
        return data.url
      })
    },
    pic(info) {
      return httpRequest('http://xxx').then((data) => {
        return data.url
      })
    },
    lyric(info) {
      return httpRequest('http://xxx').then((data) => {
        return {
          lyric: '...', // 歌曲歌词
          tlyric: '...', // 翻译歌词,没有可为 null
          rlyric: '...', // 罗马音歌词,没有可为 null
          lxlyric: '...' // lx 逐字歌词,没有可为 null
        }
      })
    }
  }
}

// 注册 API 请求事件
on(EVENT_NAMES.request, ({ source, action, info }) => {
  switch (action) {
    case 'musicUrl':
      return apis[source].musicUrl(info.musicInfo, qualitys[source][info.type])
    case 'lyric':
      return apis[source].lyric(info.musicInfo)
    case 'pic':
      return apis[source].pic(info.musicInfo)
  }
})

// 发送初始化完成事件
send(EVENT_NAMES.inited, {
  openDevTools: false, // 是否打开开发者工具
  sources: {
    kw: {
      name: '酷我音乐',
      type: 'music',
      actions: ['musicUrl'],
      qualitys: ['128k', '320k', 'flac', 'flac24bit']
    },
    local: {
      name: '本地音乐',
      type: 'music',
      actions: ['musicUrl', 'lyric', 'pic'],
      qualitys: []
    }
  }
})

LX API 参考

globalThis.lx.EVENT_NAMES

事件名称常量:

  • inited: 初始化完成事件
  • request: API 请求事件
  • updateAlert: 更新提示事件

globalThis.lx.on(eventName, handler)

注册事件监听器:

javascript
lx.on(lx.EVENT_NAMES.request, ({ source, action, info }) => {
  // 必须返回 Promise
  return Promise.resolve(result)
})

globalThis.lx.send(eventName, data)

发送事件:

javascript
// 发送初始化事件
lx.send(lx.EVENT_NAMES.inited, {
  openDevTools: false,
  sources: {...}
});

// 发送更新提示
lx.send(lx.EVENT_NAMES.updateAlert, {
  log: '更新日志\n修复了一些问题',
  updateUrl: 'https://example.com/update'
});

globalThis.lx.request(url, options, callback)

HTTP 请求方法:

javascript
lx.request(
  'https://api.example.com',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
    timeout: 10000
  },
  (err, resp) => {
    if (err) {
      console.error('请求失败:', err)
      return
    }
    console.log('响应:', resp.body)
  }
)

globalThis.lx.utils

工具方法:

javascript
// Buffer 操作
lx.utils.buffer.from(data, encoding)
lx.utils.buffer.bufToString(buffer, encoding)

// 加密工具
lx.utils.crypto.md5(str)
lx.utils.crypto.aesEncrypt(buffer, mode, key, iv)
lx.utils.crypto.randomBytes(size)
lx.utils.crypto.rsaEncrypt(buffer, key)

音源配置

支持的音源 ID

  • kw: 酷我音乐
  • kg: 酷狗音乐
  • tx: QQ音乐
  • wy: 网易云音乐
  • mg: 咪咕音乐
  • local: 本地音乐

支持的音质

  • 128k: 128kbps
  • 320k: 320kbps
  • flac: FLAC 无损
  • flac24bit: 24bit FLAC
  • hires: Hi-Res 高解析度
  • atmos: 杜比全景声
  • master: 母带音质

错误处理

最佳实践

javascript
async function musicUrl(source, musicInfo, quality) {
  try {
    // 参数验证
    if (!musicInfo || !musicInfo.id) {
      throw new Error('音乐信息不完整')
    }

    // API 调用
    const result = await cerumusic.request(url, options)

    // 结果验证
    if (!result || result.statusCode !== 200) {
      throw new Error(`API 请求失败: ${result?.statusCode || 'Unknown'}`)
    }

    if (!result.body || !result.body.url) {
      throw new Error('返回数据格式错误')
    }

    return result.body.url
  } catch (error) {
    // 记录错误日志
    console.error(`[${source}] 获取音乐链接失败:`, error.message)

    // 重新抛出错误供上层处理
    throw new Error(`获取 ${source} 音乐链接失败: ${error.message}`)
  }
}

常见错误类型

  1. 网络错误: 请求超时、连接失败
  2. API 错误: 接口返回错误状态码
  3. 数据错误: 返回数据格式不正确
  4. 参数错误: 传入参数不完整或格式错误

调试技巧

1. 使用 console.log

javascript
console.log('[插件名] 调试信息:', data)
console.warn('[插件名] 警告信息:', warning)
console.error('[插件名] 错误信息:', error)

2. LX 插件开发者工具

javascript
send(EVENT_NAMES.inited, {
  openDevTools: true, // 开启开发者工具
  sources: {...}
});

3. 错误捕获

javascript
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的 Promise 拒绝:', reason)
})

性能优化

1. 请求缓存

javascript
const cache = new Map()

async function getCachedData(key, fetcher, ttl = 300000) {
  const cached = cache.get(key)
  if (cached && Date.now() - cached.timestamp < ttl) {
    return cached.data
  }

  const data = await fetcher()
  cache.set(key, { data, timestamp: Date.now() })
  return data
}

2. 请求超时控制

javascript
const result = await cerumusic.request(url, {
  timeout: 10000 // 10秒超时
})

3. 并发控制

javascript
// 限制并发请求数量
const semaphore = new Semaphore(3) // 最多3个并发请求

async function limitedRequest(url, options) {
  await semaphore.acquire()
  try {
    return await cerumusic.request(url, options)
  } finally {
    semaphore.release()
  }
}

安全注意事项

1. 输入验证

javascript
function validateMusicInfo(musicInfo) {
  if (!musicInfo || typeof musicInfo !== 'object') {
    throw new Error('音乐信息格式错误')
  }

  if (!musicInfo.id || typeof musicInfo.id !== 'string') {
    throw new Error('音乐 ID 无效')
  }

  return true
}

2. URL 验证

javascript
function isValidUrl(url) {
  try {
    const urlObj = new URL(url)
    return urlObj.protocol === 'http:' || urlObj.protocol === 'https:'
  } catch {
    return false
  }
}

3. 敏感信息保护

javascript
// 不要在日志中输出敏感信息
console.log('请求参数:', {
  ...params,
  token: '***', // 隐藏敏感信息
  password: '***'
})

插件发布

1. 代码检查清单

  • [ ] 插件信息注释完整
  • [ ] 错误处理完善
  • [ ] 性能优化合理
  • [ ] 安全验证到位
  • [ ] 测试覆盖充分

2. 测试建议

javascript
// 单元测试示例
async function testMusicUrl() {
  const testMusicInfo = {
    id: 'test123',
    name: '测试歌曲',
    artist: '测试歌手'
  }

  try {
    const url = await musicUrl('kw', testMusicInfo, '320k')
    console.log('测试通过:', url)
  } catch (error) {
    console.error('测试失败:', error)
  }
}

3. 版本管理

使用语义化版本号:

  • 1.0.0: 主版本.次版本.修订版本
  • 主版本:不兼容的 API 修改
  • 次版本:向下兼容的功能性新增
  • 修订版本:向下兼容的问题修正

常见问题

Q: 插件加载失败怎么办?

A: 检查以下几点:

  1. 文件编码是否为 UTF-8
  2. 插件信息注释格式是否正确
  3. JavaScript 语法是否有错误
  4. 是否正确导出了必需的方法

Q: 如何处理跨域请求?

A: CeruMusic 的请求方法不受浏览器跨域限制,可以直接请求任何域名的 API。

Q: 插件如何更新?

A: 使用 cerumusic.NoticeCenter 事件通知用户更新:

javascript
cerumusic.NoticeCenter('update', {
  title: '新版本更新',
  content: 'xxxx',
  version: 'v1.0.3',
  url: 'https://shiqianjiang.cn',
  pluginInfo: {
    type: 'cr'
  }
})

Q: 如何调试插件?

A:

  1. 使用 console.log 输出调试信息 可在设置—>插件管理—>日志 查看调试
  2. LX 插件可以设置 openDevTools: true 打开开发者工具
  3. 查看 CeruMusic 的插件日志

技术支持

如有问题或建议,请通过以下方式联系:

Released under the Apache License 2.0 License.