musicfree 中文文档 下载 App

插件化架构原理——播放器壳和音源插件如何协作

为什么要讲架构

理解 MusicFree 的插件化原理,有两个实际好处:一是装插件遇到问题时能快速定位是宿主问题还是插件问题;二是有能力自己写插件的开发者,可以知道该从哪里下手。

宿主负责什么

宿主(也就是 MusicFree 软件本体)是稳定的,它不关心具体音源,只负责:

插件负责什么

插件是可替换的模块,每个插件对接一个或多个音源接口。插件需要实现的核心接口:

接口功能示例
搜索音乐按关键词返回歌曲列表搜"周杰伦"返回歌曲数组
搜索专辑按关键词返回专辑列表搜"七里香"返回专辑信息
搜索作者按关键词返回歌手列表搜"周杰伦"返回歌手档案
获取播放链接输入歌曲信息,返回可播放的音频 URL拼接音源实际播放地址
获取歌词输入歌曲信息,返回歌词文本返回 LRC 格式歌词
查看专辑详情输入专辑 ID,返回专辑内歌曲列表展开专辑曲目
查看作者详情输入歌手 ID,返回歌手信息和热门歌曲歌手主页
导入单曲输入单曲链接,返回标准化歌曲信息从外部链接解析歌曲
导入歌单输入歌单链接,返回歌单内全部歌曲批量导入歌单

通信模型

宿主发起调用 → 插件执行 → 插件返回结构化数据 → 宿主渲染。宿主控制分页、缓存策略、错误处理等通用逻辑,插件只关心"给定输入、返回正确数据"。

这种设计让双方解耦得比较干净:宿主不依赖任何特定音源(换一个插件播放器不会崩),插件可以独立迭代(新功能不用等宿主更新)。

插件的技术形态

插件本质是 CommonJS 模块,导出一个包含上述接口函数的对象。宿主通过 Node.js 的模块加载机制动态载入插件。

// 插件的基本骨架(示意)
module.exports = {
  name: '示例音源插件',
  version: '1.0.0',
  // 核心接口
  search: async (keyword, type, page) => { ... },
  getMediaUrl: async (musicItem, quality) => { ... },
  getLyric: async (musicItem) => { ... },
  // ... 其他接口
}

实际开发中,插件还需要处理登录态(某些音源需要 Cookie)、接口签名、加密参数等细节,这些都封装在插件内部,宿主不可见。