一个 MusicFree 插件,把 QQ音乐 / 网易云音乐 / Audiomack 三个平台的歌单导入、搜索、播放聚合在一起, 并在原生源放不了的时候自动跨平台换源。
开发依据:maotoumao/MusicFree 的插件协议与宿主源码
(src/core/pluginManager/plugin.ts、src/pages/searchPage/hooks/useSearch.ts、src/utils/mediaUtils.ts)。
在 MusicFree 里「我的 → 插件 → 从 URL 安装插件」,直接填下面这条:
https://raw.githubusercontent.com/linuxwff789/multi-source.js/main/multi-source.js
国内访问 raw.githubusercontent.com 不稳定时,用 jsDelivr 镜像(内容相同):
https://cdn.jsdelivr.net/gh/linuxwff789/multi-source.js@main/multi-source.js
也可以把
multi-source.js下载到手机后用「从本地安装」选择该文件。
- 搜索:一次查询并行打三个平台,结果按源轮流交错;同一首歌跨平台重复时自动合并成一条
- 导入歌单:粘贴分享文本 / 链接 / 歌单 ID 即可,插件按域名自动分发
- QQ音乐:
y.qq.com歌单地址、分享链接、纯歌单 ID - 网易云:
music.163.com地址、163cn.tv短链、纯歌单 ID(整段分享文本直接粘) - Audiomack:
audiomack.com/<artist>/playlist/<slug>、纯数字歌单 ID
- QQ音乐:
- 播放:原生源拿不到地址时自动换源(优先用搜索时合并进来的备选源,没有再实时搜)
- 歌词:QQ / 网易云(Audiomack 无公开歌词接口)
-
打开 MusicFree → 「我的」→「插件」→「从 URL 安装插件」
-
填入插件文件直链:
https://raw.githubusercontent.com/linuxwff789/multi-source.js/main/multi-source.js -
安装后进入插件设置,按需填写下面的配置项,然后启用。
也可以把 multi-source.js 下载到手机后,用「从本地安装」选择该文件。
| key | 说明 | 默认 |
|---|---|---|
search_source |
搜索源:all / qq / netease / audiomack |
all |
fallback |
跨平台换源开关 on / off |
on |
merge |
搜索结果同曲合并去重 on / off |
on |
strict_match |
严格匹配 on / off:on 时换源拒绝「无专辑字段、只靠时长顶上」的候选(loose 档) |
off |
qq_cookie |
QQ音乐 Cookie(可选,用于 VIP 歌曲) | 空 |
ne_cookie |
网易云 Cookie(可选,用于 VIP 歌曲) | 空 |
npm install
node test-multi-source.js测试会真的访问三个平台的公开接口,需要联网。用例覆盖:宿主沙箱加载、OAuth 签名固定向量、
多源搜索与合并、同一录音判定(三档证据 + 防翻唱/防伴奏/防现场)、三源歌单导入、播放地址、
跨平台换源(含《修炼爱情》回归用例)、请求超时覆盖。
网络不通或平台限制导致的用例会标 SKIP 而非 FAIL。
宿主每次拿到插件返回值都会执行 resetMediaItem(_, this.plugin.name),把 platform 字段强制改写成插件名。
所以一个插件聚合多个平台时,platform 无法用来区分来源,只能自带字段:
id: `qq:0039MnYb0qxYhV` / `ne:407862139` / `am:104577726` // 单主键下全局唯一且可反解
source: "qq" | "netease" | "audiomack" // 分发主依据
songmid / mediaMid / nid / amid // 各平台原生 id,避免每次切字符串宿主侧唯一键是 platform + "@" + id,platform 被统一后,唯一性完全靠 id 前缀。
| 用途 | QQ音乐 | 网易云 | Audiomack |
|---|---|---|---|
| 搜索 | c.y.qq.com/soso/fcgi-bin/client_search_cp |
music.163.com/api/search/get |
/v1/search(OAuth 签名) |
| 歌单详情 | musicu.fcg → music.srfDissInfo.DissInfo/CgiGetDiss |
api/v6/playlist/detail |
/v1/playlist/{id}(OAuth 签名) |
| 播放地址 | musicu.fcg → vkey.GetVkeyServer/CgiGetVkey |
api/song/enhance/player/url/v1 |
/v1/music/play/{id}(OAuth 签名) |
| 歌词 | lyric/fcgi-bin/fcg_query_lyric_new.fcg |
api/song/lyric |
无 |
踩过的坑都写在代码注释里了,主要有:
- 网易云
c/ids参数有长度上限:批量歌曲详情一次传 300 个 id(编码后约 8K 字符)正常, 424 个(约 11.4K)会返回code:400 "请求解析失败!"且 HTTP 仍是 200 —— 不检查code就会静默丢歌。/api/song/detail?ids=更糟:424 个只回 201 个,静默截断。所以批量用 100,并做折半重试。 - 「我喜欢的音乐」(
specialType: 5) 等歌单,tracks只是预览:实测一个 430 首的歌单只内联 6 首, 真实列表要以trackIds为准并按其顺序输出。 - 网易云不登录也能放 VIP 曲:
url/v1带上Cookie: os=pc; appver=8.9.70;, 接口会把 VIP 曲按"客户端免费用户"返回 128k 地址;裸请求是code:-110。 代价是level被忽略、恒定 128k,要更高音质需要自备 cookie。 - 有条目但无 url 时不要退到
outer/url:它会 302 到/404返回 HTML 页面, 等于把网页当音频丢给播放器。应直接返回null。 - QQ音乐旧的歌单接口已废弃:
qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg现在返回{"code":0,"subcode":4000,"msg":"check privacy error!"},改用musicu.fcg的CgiGetDiss。 - Audiomack 官方插件取歌单的方式已失效:它靠首页
script#__NEXT_DATA__取 buildId 再拼/_next/data/...json,而站点已迁移到 Next.js App Router,首页不再有__NEXT_DATA__。 本插件改用播放页 RSC 流里的{"music":{"id":...}}提数字 id,再走开放 API。 - Audiomack 的公开 API 需要 OAuth1(HMAC-SHA1) 签名,consumer key/secret 从其前端 bundle 提取, 实现与原官方插件逐字节一致(测试里有固定向量校验)。
- URL 里的 slug 不唯一,且 URL 的 artist slug 与 API 返回的
artist.url_slug不一定相同, 所以只能用页面里提取的 id,不能拿搜索按 slug 反查。
- 宿主把插件体包成
function(require, require, module, exports, console, env, URL, process){...},env是包装函数的参数而不是global.env,取用户变量要用裸env。 - 宿主在
plugin.ts里设了axios.defaults.timeout = 2000,对跨平台请求太紧。 插件内部包了一层http.get/http.post,只给自己的请求设超时(搜索 7000ms,其余 12000ms), 不修改宿主的全局默认值。 require只能拿到宿主白名单:cheerio / crypto-js / axios / dayjs / big-integer / qs / he / webdav。 本插件只用到axios和crypto-js,无需额外打包。
-
合并:按归一化标题分桶,桶内用下面的同一录音判定,每组只出一条,其余挂到
primary.alts(仅保留其它源、每源最多一条)。主条目优先选非 VIP 且稳定源(netease > qq > audiomack)。 -
同一录音判定(合并与换源共用同一个函数,避免两处规则不一致)分三档身份证据:
档位 条件 用途 album双方专辑名互相包含 + 艺人吻合 最硬的证据,换源排序最优先 master专辑名不同(一方缺失也算),但艺人吻合 + 时长精确吻合(≤2s 或 ≤1%) 海外平台把同一母带挂在合集/精选集下的情况 loose候选完全没有专辑字段,艺人吻合 + 时长精确吻合 最后手段(AM 上大量用户上传件没有专辑信息); strict_match=on时禁用 -
硬淘汰(都是「换了演绎」的证据,不是「换了专辑」):
- 标题归一化后不一致,或双方都有艺人却对不上(防翻唱 / 同曲不同人)
- 候选带
伴奏 / 纯伴奏 / 消音 / instrumental / off vocal / karaoke标记 (标题归一化会剃掉括号内容,如果寂寞了(伴奏)会被剃成如果寂寞了从而满分误命中) - 候选带
cover / 翻唱 / 翻自 / 致敬 / 原唱等翻唱标记 - 候选带现场·综艺标记:
演唱会 / 现场 / live / 巡回 / 音乐会 / 第N期 / 跨年 / 晚会 / 音乐节 / 盛典 / 颁奖 / 我是歌手 / 梦想的声音 / 大歌神 / 我想和你唱 / 好声音等 - 双方时长都已知且差 > 5s 或 5%
-
专辑名不一致不再单独淘汰(v0.1.5 起):实测《修炼爱情》在 QQ/网易云都拿不到原曲, AM 上是合集「8090's 经典」287s,与原专辑「因你而在」287s 逐秒相同;旧规则按「专辑不同」 一票否决,换源整个失效。现在走
master档放行;而范特西 270s ↔ The One演唱会 273s这类被现场标记 + 3s 偏差(只到 close 档)双重拦掉。 -
艺人串分隔符做了兼容:
A / B、A、B、A, B、A&B、A feat. B都能对上。
| 项目 | 结果 |
|---|---|
| 网易云分享文本导入(430 首歌单) | 430 首(= trackCount),无重复,封面/时长齐全 |
| QQ音乐歌单导入 | 66 首 |
| Audiomack 歌单导入 | 24 首 |
| 多源搜索「周杰伦 晴天」 | 45 条 → 合并后 38 条,同曲 8 条重复并成 1 条 |
| 「Taylor Swift Love Story」 | 跨 3 源合并(主 netease + 备选 audiomack,qq) |
| 歌单抽样 30 首播放 | 原生 26 / 换源救回 2 / 仍失败 2(93%) |
| 「修炼爱情」(QQ/网易云都拿不到原曲) | 换源命中 AM 合集条目(master 档),返回地址实测 9.2MB audio/mp4(ftyp) |
| 「体面」(网易云 404 下架) | 换源命中 AM 无专辑上传件(loose 档),实测 4.6MB audio/mp4 |
| 自测 | 47 通过 / 0 失败 / 0 跳过 |
那 2 首失败是正确的拒绝:你懂得(QQ 有满分匹配但是 VIP,匿名拿不到地址)、
如果寂寞了(只有伴奏版,被版本标记拦掉)。放宽匹配能到 100%,但会放出翻唱/伴奏。
- 只支持公开歌单;私密歌单需登录后才有权限
- 不填 cookie 时,网易云 VIP 曲最高 128k;QQ音乐 VIP 曲匿名完全拿不到地址(
result=104003) - Audiomack 有相当比例曲目是 Audiomack+ 独家,返回 403,插件会自动换源
- 换源后 UI 上显示的仍是原平台的标题/封面 ——
musicItem由宿主传入,插件无法修改 - 三源都是非官方公开接口,随时可能变动;本仓库不保证长期可用
- 本插件仅供学习与技术研究使用,请勿用于任何商业用途。
- 插件使用各平台公开可访问的接口,不包含破解、不绕过付费墙、不提供 VIP 内容; 付费/独家曲目在匿名状态下拿不到地址时会如实返回失败或换源。
- 所有音乐版权归各自权利人所有,请在能力范围内支持正版。
- 参考:MusicFree 官方插件仓库因收到告知函,已移除网易云/QQ音乐等国内源插件。 若你要公开分发本插件,请自行评估合规风险。
plugin._internal是调试用的内部函数导出(签名、匹配等),宿主会忽略未知键, 测试脚本依赖它做固定向量校验;不需要可直接删除该行。
MIT