入库自动化:一首歌进曲库要过的几道闸
个人曲库系统 · 整理第 4 篇 · 共 4 篇目录
- 01从文件夹到曲库:音乐文件标签最佳实践2026-10-17
- 04入库自动化:一首歌进曲库要过的几道闸正在读
- 05流派树是怎么长出来的待发布
- 06给五千首歌补标签待发布
《从文件夹到曲库》讲的是一首歌入库后该长什么样。这一篇讲怎么让每一首新歌都稳定地长成那样。
现在我入库只说一句「入库:<歌名>」,剩下的由 Agent 跑完:认歌、查重、取音频、过闸门、写标签、配封面和歌词、算响度、上传。我只在几个分叉上拍板。曲库快五千首了,靠手工一首首做,步骤会漏,口径也会慢慢漂移。
- 流程的次序本身就是规则:先落位、先查重,最后才算响度
- 每道检查只有三种结果:通过、失败、待人定
- 工具会静默出错,完成看回读,不看退出码
- 人只拍板分叉,拍过的板写进文件,不靠记忆
- 已经入库的文件不顺手改
音频从哪来不在本文范围,下面从「已经确定要哪首歌」写起。工具链以我自己的为例,换成别的工具,道理一样。
拓扑
指挥机 → 发指令、做确认
工作机 → 曲库母本;下载、打标签、算响度都在这里
网盘 → 母本的副本
服务器 → Navidrome 挂载网盘,凌晨自动扫描新增
工具分工:
| 工具 | 负责 |
|---|---|
tagify |
我自用的标签工具:写元数据、按流派词表归一化、自动补齐祖先标签1 |
metaflac |
补写 tagify 管不到的字段(语种、作品来源) |
rsgain |
算响度,写 ReplayGain |
ffmpeg / ffprobe |
核验音频:解码、位深、时长、频谱 |
次序本身就是规则
| 步骤 | 为什么排在这里 |
|---|---|
| 1. 认歌 | 先确定是哪一首、哪个版本。有精确 id(收藏、歌单、链接)就直接用,不再按名字搜一遍 |
| 2. 落位 | 目录决定文件名,也决定按专辑还是散曲写标签,所以在下载之前 |
| 3. 查重 | 在下载之前。曲库按批次分目录,同一首歌早年进了一个目录、这次落到另一个,「目标已存在」拦不住 |
| 4. 取音频 | — |
| 5. 闸门 | 在上传之前。传完再发现是错的,上行就白烧了 |
| 6. 写标签 | 身份字段、流派、语种、作品来源 |
| 7. 封面和歌词 | 封面按专辑取一次,歌词逐首取 |
| 8. 响度 | 最后算。前面的标签清洗可能把它清掉 |
| 9. 归位、上传 | 复制,不移动;上传后对数量 |
查重最容易做错的是判据。重复看的是录音,不是曲名:同名翻唱、remix、不同录音都会撞名。命中之后比艺人和时长:
- 同一艺人、时长差 ≤2 秒:同一录音,跳过。专辑名不一样也跳过,合辑、再版里收的常常就是同一个录音
- 差 2–5 秒,专辑也不同:单曲版和专辑版、重制版,交给我定
- 差 >5 秒:另一个录音,照常入库
繁简、全半角、大小写、标点都统一了再比。库里那首是《生物股长 - ブルーバード (青鸟)》,只按一种写法查就会漏。
闸门:通过、失败、待人定
每道检查只有三种结果。证据不够下结论的,一律是「待人定」,交给我,不让 Agent 自己发明豁免。前提不成立的(比如来源没给文件大小)记「不适用」,不能混成「通过」。
| 检查 | 拦的是 |
|---|---|
| 完整解码一遍,比对 FLAC 里存的 MD5 | 坏文件 |
| codec、位深、采样率 | 请求无损却静默降级成了 mp3 |
| 大小 ≈ 来源给的大小 | 下载被截断 |
| 时长 ≈ 平台给的参考时长,差 ≤3 秒 | 下错了版本、挂错了歌 |
| 频谱 | 有损转码再包成 FLAC |
两条容易忽略的纪律:
- 不能拿被检查的文件给自己作证。拿它自己的时长当参考时长,每首都「误差 0 秒」,这道闸就形同虚设
- 频谱只是证据,不是结论。128k 的 MP3 在 16kHz 处截断,320k 的在 19–20kHz,可有些母带本身就贴着上限陡降,和 320k 的转码很难分开。阈值要拿自己库里来源可靠的文件当基线校准;离阈值近的写成「证据弱」,交给人判
「待人定」不等于每次都问。某一类我给过统一规则(比如「疑似转码的一律不收」),就写进规则里,以后照规则办,台账里写明按的是哪条。
静默失败:退出码 0 不代表成功
整条流水线里最危险的不是报错,是不报错。下面这些都是退出码 0、看起来一切正常:
| 症状 | 怎么发生的 | 怎么防 |
|---|---|---|
中文歌词变成一串 # |
metaflac 在 C locale 下写 CJK 字符;非交互 ssh 的 locale 默认就是 C |
整段脚本 export LANG=C.UTF-8;回读核对,不数行数——行数一行不差 |
| 同一个字段出现两条 | metaflac --set-tag 是追加,不是替换 |
先 --remove-tag 再写 |
Ke$ha 写成了 Ke |
$ 被 shell 展开;裸 & 会把命令切成后台任务加半个名字 |
值和路径都不拼进命令字符串,走 JSON 或参数数组 |
三位艺人变成一个 A;B;C |
ffmpeg 重编码 FLAC 时把多值字段合并成一个串,还丢掉封面 |
重编码后用标签库重写,再回读 |
| 没有响度标签 | rsgain custom 默认只扫描,要加 -s i 才写;不带 -a 时还会删掉已有的专辑增益 |
写完回读增益字段 |
| 云盘上少了两首 | 网盘 CLI 目录级上传,回显「上传失败:」后面是空的 | 逐个文件传、逐个确认,传完对文件数 |
多出一首 xxx(1).flac |
同名文件被静默改名上传,扫成重复曲目 | 上传固定带覆盖参数 |
| 一首歌在库里「消失」 | 文件名里有 ;,WebDAV 网关取内容时在这里截断:列得出来、读不出来 |
文件名避开 ; ? # % |
歌词也有自己的一类。网易云的制作人员行要删,但它不一定是 作词 : XXX 的样子:全角冒号、不带空格、英文末尾的 Produced by …、开头的 《曲名》- 艺人 横幅、歌词制作者留下的 By 某人 日期,都出现过。所以按「这一行是不是在唱的内容」判,不按某个冒号的写法判。删完还要核一下时间轴:末尾时间戳该落在音频时长的 85%–100%,而且要用最后一行正文算——末尾的署名行会把比例撑高,掩盖歌词挂错了版本。
有一次我说「歌词还是不对」,文件、网盘、挂载点、Navidrome 数据库四层都已经是对的——是播放器自己缓存了歌词。改完歌词复查,先清客户端缓存。
人在哪里拍板
Agent 做重复劳动,判断留给我。停下来问我的只有这几种:
- 版本有歧义:同名的现场版、Remix、扩展版,或者平台上只有
Expanded Edition - 要为某位艺人新开目录(这是策展判断)
- 两个来源的流派冲突,或者落不进流派树
- 疑似重复里的中间那一档
- 闸门给出「待人定」,又没有现成的规则
拍过的板写进一份决策文件:每项写「是什么、选了什么、为什么、哪天定的」,脚本和 Agent 都从那里读,不凭记忆填。比如粤语要不要从 cmn 里分出来,这种口径以后可能翻转,写死在流程里,翻转时就会写错。
已经入库的文件不顺手改
Navidrome 用曲名、音轨号、碟号、专辑、专辑艺人、年份这些字段算一首歌、一张专辑的身份。改了它们,播放次数、收藏、评分、歌单都会断开。《从文件夹到曲库》末尾提过这一点,落到流水线上就是一条硬规矩:新文件入库之前把字段定好,存量文件一个不碰,哪怕它不符合新口径。往已有专辑里补一首,算专辑增益要用到已有的几首,也是拷贝一份去算,不动原文件——别用硬链接,rsgain 原地改文件,会改到母本。
把流水线交给别人
有朋友想搭类似的东西。我的 skill 绑着我的三台机器和笔记,直接给没用,于是我把它提炼成一份提示词:不让对方照搬我的方案,而是让对方的 Agent 先摸清环境,在关键分叉上问它的用户,再一步步搭出他自己的流水线。
为了检验它,我让三个模型在沙盒里各跑了五轮:拿一份假曲库,埋进重复、假无损、截断、错封面、Ke$ha 这类陷阱,用一份写好的「用户回答」代替真人。几条收获:
- 写成原则,不写成命令。最早的版本把坑写成「
metaflac会怎样」,碰到没装metaflac的机器就失灵。改成「写进去的非 ASCII 字符要回读核对」,再把metaflac作为一种症状,换什么工具都适用 - 规则之间的矛盾会被字面执行放大。「音轨号要连续」和「缺的轨如实留空」各自都对,放在一起,最较真的那个模型一首都不入库
- 每一轮都还能找到新问题,但越来越边缘。前两轮找的是会让整批卡死的矛盾,第五轮找的是「横幅里
&和and要算一回事」。真用的时候旁边有人,这类细节一句话就定了,测到这里就够了
一套流水线有没有价值,最后还是看它能不能让我更省心地听到想听的歌:它负责不出错,我负责做判断。
-
tagify 是我给自己写的工具,没有公开。想搭类似的流程,MusicBrainz Picard 或 beets 写标签,再配 rsgain 算响度,能覆盖大部分环节。 ↩︎