← 返回文章列表

飞牛音乐助手,MusicMate发布!

大半个月了,我终于算满意了现在的版本。之前我弄了一个飞牛系统整理工具,里面多有一个去重功能涉及到音乐去重,当时只是一个简单的使用SHA-256去重,这个属于文件去重那一套,类似相同文件算法去重,对于音乐来说可能同一首歌有MP3、FLAC、APE、WAV等多种版本,这样SHA-256去重就失效了。

所以当时就有网友提了一个这样的问题。 网友留言

文件名与编码整理

因为这个也正是我需要的功能,我觉得可以从音乐的频谱开始区分一首歌,然后我就开始用我多年前收集的音乐文件,大概几百首开始边写去重边测试。本来以为是个简单的音乐频谱一分就可以区分的,结果问题就来了:同一首歌乱码文件名、繁体标签、缺封面的专辑、一首歌在几个文件夹里各有一份……有的MP3,有的FLAC,有的就是APE。

其实我最先开始按"歌手 / 专辑 / 歌名"把散落一地的文件重新归位,顺手把古早windows千千静听那个时代下载歌曲中的 GBK 乱码标签修复成 UTF-8,繁体转简体。那时候我觉得这就够了。

但是我的文件有的歌曲,不是所有的文件名都像歌手-歌名.后缀名这样的排列,有的中间还夹杂了当初下载地的音乐网站名在里面。但是在一些播放器中又能正确的识别出歌曲名,甚至有封面,说明歌曲的TAG信息中是正确的,所以我想到从TAG信息中提取歌手-歌名的方式,当我批量提取的时候,发现有部分歌曲是反过来的,文件名是正确的,TAG信息里面是杂乱的。

举例一些碰到的坑:

  • 同一首歌,MP3 320k 一份,FLAC 一份,APE 一份,码率还都不一样;
  • 下载站习惯把水印写进标签,比如《六月飞霜 角落音乐bbs.in-corner》,还有那种"认了吧 搜啦EP - 全球华语Demo音乐网 www.sosolala.com";
  • 有些工具会把 kuwo 这种占位符写进 artist/title,导致完全不相干的两首歌被当成"同名";
  • 更绝的是,有些文件开头是垃圾字节(下载工具失败重试时把 JSON 错误写进了文件头),标签工具直接读不出来。

光这一个"同曲识别",就被水印、占位符、垃圾头坑了三个小版本(0.5.0 → 0.5.2):先是把下载站的广告词从标签和文件名里洗掉再匹配,再修"kuwo 占位符导致误判",再修"垃圾头文件评分归零被误淘汰"。 围绕标签煞费苦心

码率与音频指纹

光一个同名就搞了半天,把名字统一之后,我天真的以为再找码率相同,就可以去掉了吧。但是同一首歌有的音源不一样,码率也不相同,虽然人耳👂听的都是一样的,但是计算机却认为不一样,以至于我在这里疑惑很久,为什么没有自动去重掉。

这个时候我求助了互联网,知道了一种音频指纹的技术。所以改成:先用 SHA-256 做精确去重,再用 Chromaprint 音频指纹(就是给歌曲"按音轨内容"算指纹,同一首歌不管码率格式,指纹能对得上)识别"同曲不同版",最后按音质评分(格式权重 + 码率 + 采样率)自动留下最好的那份。

终于是小有成就!

But……

兜底之战

但实际上标准化歌曲的文件名都没有完全做完了,批量下来总有一些音频文件的文件名弄错了,我回退之后发现之前文件名是对的,经过批量计算还错了,很多都是因为音乐标签的原因,我知道了我上面的方法并不能完美的覆盖所有的音乐文件。

所以我想到了只有彻底先解决音乐标签的正确率的问题,然后用音乐标签再来反过来修改音乐文件名,保证文件名对,就可以让同名不同后缀的对比跑起来,先SHA-256快速去重完全一样的,再用音频指纹找出相同的歌曲不同版本中音质较好的保留,这才是完整的闭环。

所以我找寻了各种标签补全的方案后,顺带想既然能标签补全,多数音乐文件实际上还可以内嵌封面和歌词,但是我需要对于漏网之歌需要单独试听,这个时候再去不同的播放器里来回切换既低效又愚蠢,就顺手弄了个播放器,那播放器的基本功能是要覆盖的吧,所以基础的播放器也有了,只是没有专注解码和提升音质效果,基本的听个响是可以的。于是下面的一系列工作花了一周多才渐渐补齐:

  • 标签补全:先用 MusicBrainz(免费免 key)查文本,后来发现华语歌还是 iTunes 的 Search API 好使(country=CN 直接返回中文标签,晴天的歌手是"周杰伦"而不是"Jay Chou"),就改成 iTunes 为主、MusicBrainz 兜底;
  • AI 兜底:冷门歌数据库里没有,就接了个 OpenAI 兼容接口让它"听"文件名和已有标签猜,结构化输出 + 预览确认,防止幻觉;
  • 封面:没内嵌封面的,按"歌手+专辑"去 iTunes 在线抓 600x600 的图;歌手头像也顺手用代表专辑封面顶上了(本来想用 Deezer 的头像 API,结果这网络根本连不上,白折腾);
  • 歌词:内嵌 LYRICS 字段 + LRCLIB 在线检索,还遇到一个"IPv6 黑洞"——部分网络下请求直接挂起,最后强制 IPv4 才解决;
  • 播放器:本来只想加个试听,后来越加越多——播放队列、切歌、播放模式、全屏界面、悬浮歌词、音量快捷键、系统媒体控制(锁屏能切歌)、播放历史、收藏……

到这里我已经彻底忘记最初"整理工具"的设定了。 简单的播放器 一开始想手动补齐标签

最后一步:听歌识曲

音乐库收拾干净后,总还有几首"漏网之鱼"——标签全错的歌,数据库查不到,AI 也猜不准。

整理还是不完美——因为好多歌的标签是空的、错的。标签不对,整理出来的目录就乱。于是我想到现在在大多数大厂的播放器中流行的“听歌识曲”的技术。我用批量整理之后得到的大部分音乐文件已经把标签、去重都做了,少部分的只有人工单曲自己去听来兜底,但是我听过的歌未必记得住专辑和年代,甚至有的时候歌名都不记得,只是觉得熟悉,所以这个时候听歌识曲,知道正确的歌名再到互联网上搜索歌曲信息就简单的多,这就是我当下的思路。

人听不了,那就直接用机器"听"吧。用 Chromaprint 指纹查 AcoustID 的众包库——结果华语歌覆盖感人,一堆经典中文歌都查不到(众包库对华语不友好是常态,不是 bug)。

于是又接了两条兜底:ShazamIO(逆向 Shazam,免费免 key,华语覆盖好)和 ACRCloud(需要申请 key,但准确率能到 100 分,可惜只有14天的免费试用)。三条路可以自己在设置页勾选,按顺序试,命中即停。实测许嵩的《乌鸦》、周杰伦的《Mojito》都能命中。

听歌识曲之后自动把标签标记出来,你同意就修改。记住标签正确才是整理、去重的基础。

现在单曲编辑页面多了更多识别方式回写标签

半个月,20 多个版本

从 0.1.0 到 0.20.1,中间踩过的坑远不止上面这些:

  • 回收站放应用数据目录里,卸载升级会被清空,导致已清理的文件没法还原——最后迁到音乐库根目录的隐藏目录,卸载也不怕;
  • 后端有一类"global 变量没声明"的隐蔽 bug 踩了两次坑,干脆把配置全部改成对象化,根治;
  • 服务端 800 多行的路由全挤在一个方法里,拆成了 5 组子方法;
  • 前端一个 main.js 3000 多行,环境没 node 没法拆文件自动验证,就做了"分区索引 + 结构测试"……

回头想想,那句"能不能尽量清理,只留一个大的"挺值钱的——没有它,这工具大概永远只是个整理脚本。一个朴素的需求,加上一堆"顺手的事",最后就滚成了一个大雪球。

下载地址

https://atomgit.com/kyeo/musicmate/releases/download/v0.20.1/musicmate_0.20.1_x86.fpk

最后

这个项目刚完成没几天,飞牛NAS就更新了,这次正式发布了飞牛音乐,祝贺🎉