上个月音乐 App 会员又涨价,一年两百多。涨就涨吧,关键是歌单里灰了一片——好几首听了十几年的歌,突然"因版权问题暂时下架"。

我坐在客厅地板上发了会儿呆,想起硬盘里还躺着从大学攒到现在的音乐文件夹。最早是 2008 年在网吧用 U 盘拷的 mp3,后来是 ape、flac,再后来是各种无损资源。二十年,差不多 60 个 G。

这些歌在硬盘里躺了这么多年,一个能听的入口都没有。

那就自己搭一个。

为什么是 Navidrome

自建音乐服务器可选的不多,主流是这几个:

方案特点我的判断
NavidromeGo 写的单文件,资源占用小,兼容 Subsonic API选它
Plex / Emby功能全,但音乐是附属功能,还要会员太重
Ampache老牌 PHP 方案,配置繁琐折腾成本高
Koel界面好看,但更新慢生态一般

选 Navidrome 的核心理由是它兼容 Subsonic API。这意味着市面上几十个音乐客户端都能直接连它,iOS、Android、桌面、甚至车机,不用等官方出 App。

而且它真的很轻。一个 Go 编译的单文件容器,60G 的库跑起来内存占用一百多兆。

部署

services:
  navidrome:
    image: deluan/navidrome:latest
    container_name: navidrome
    restart: unless-stopped
    ports:
      - "4533:4533"
    environment:
      ND_SCANSCHEDULE: 1h
      ND_LOGLEVEL: info
      ND_SESSIONTIMEOUT: 24h
      ND_BASEURL: ""
    volumes:
      - ./navidrome/data:/data
      - /mnt/music:/music:ro

ND_SCANSCHEDULE: 1h 是每小时扫一次新歌,加了歌不用手动触发。

/music:ro 挂只读,避免误删——这一点很重要,我第一次跑的时候差点把源目录搞乱。

起来之后访问 http://IP:4533,第一次进去建管理员账号,然后指向 /music 目录开始扫描。

目录结构决定刮削质量

Navidrome 没有复杂的元数据抓取服务,它主要靠文件名和 ID3 标签来识别歌。

官方推荐的目录结构:

/music
  /周杰伦
    /范特西
      01-爱在西元前.flac
      02-爸我回来了.flac

歌手 / 专辑 / 曲目 三层,文件名带序号和歌名。这个结构它认得最准。

我一开始把歌全平铺在一个文件夹里,文件名是"周杰伦-范特西-01-爱在西元前.mp3"这种。扫出来专辑全乱了,同一张专辑被拆成好几个。

如果库里已经乱了,别硬扫,先整理。 我花了一个晚上写了个脚本按文件名正则重排目录,比手动快得多。

标签:中文乱码这一关

整理完目录,扫出来发现一半歌名是乱码:"鍠滄浣犵殑"这种。

原因不复杂:早年 mp3 的 ID3v2 标签用的是 GBK 编码,Navidrome 按 UTF-8 读,就对不上了。

处理办法是批量转码。我用 mp3tag(Windows/macOS 都有):

  1. 全选文件
  2. 工具 → 选项 → 标签 → 编码设成"读取 GBK"
  3. 再执行"保存",写入时用 UTF-8

macOS 上也可以用命令行:

# 需要安装 eyeD3 或 mutagen
pip3 install mutagen

写个小脚本扫一遍,把有非 ASCII 乱码的标签重写。不过对大多数人来说,mp3tag 图形界面更快。

封面缺失是第二个问题。Navidrome 会找专辑目录下的 cover.jpg 或 folder.jpg,没有就显示占位图。

我给每个专辑目录补了 cover.jpg,用 MusicBrainz Picard 批量匹配封面。这个工具能按专辑名、艺人名去数据库匹配,命中率挺高,中文歌差一些,得手动挑。

扫描:第一次会很慢

60G 的库,第一次扫描跑了四十多分钟。

不是 Navidrome 慢,是要读每个文件的标签、算资源指纹。之后的增量扫描就快了,只扫新文件。

扫描期间后台能看到进度,也能在「活动」页面看日志。如果卡住不动,通常是某个文件损坏,日志里会有具体路径。

我遇到过一个 flac 文件损坏,扫描到那个专辑就停住,删掉那个文件就好了。

客户端

这是 Navidrome 最爽的地方——Subsonic 协议,客户端随便挑。

iOS:

Android:

桌面:

我手机用 Symfonium,电脑上直接开网页。两边的播放进度会同步——同一首歌在手机上听到一半,回到电脑上打开,接着放。

这个体验跟商业平台已经没区别了,而且歌是自己的。

外网访问

局域网内直接用 IP 就行。出门在外想听,得做外网访问。

我这边是用 Nginx Proxy Manager 反代(之前写过那篇),把 music.xxx.com 指到 192.168.1.200:4533。

需要注意两点:

一、Subsonic 客户端要填完整地址,包括协议和端口。有的客户端对反代后的路径很挑,ND_BASEURL 要跟实际访问路径一致,不然封面、流媒体地址会错。

二、流媒体走反代,带宽要够。 一首 flac 几十兆,外网听会卡。Navidrome 支持转码——在设置里可以配"外网播放时降码率",比如转成 128kbps 的 mp3 流。我配了 192kbps,手机流量听不心疼,音质也够。

四个坑

坑一:flac + cue 不分轨

早年下的无损很多是一整个 flac 加一个 cue 文件。Navidrome 不认 cue,会把它当成一首几十兆的"超长歌曲"。

处理:用 foobar2000 或 shntool 按 cue 分轨,分完把 cue 删掉。

shnsplit -f album.cue -o flac album.flac

坑二:同一张专辑多个版本

比如《范特西》有普通版和一个"十周年纪念版",标签里专辑名不一样,扫出来就是两张专辑,封面打架。

处理:统一专辑名,版本信息写进备注或者放不同目录。

坑三:中文搜索搜不到

Navidrome 的搜索是按标签匹配的,如果标签里歌名是繁体,你搜简体就搜不到。

处理:统一成简体,或者客户端里用拼音首字母碰运气。

坑四:外网播放卡顿

前面提过,flac 直传带宽不够。配转码,或者把常用歌单提前下到手机上离线。

这套东西的真实用处

搭完两周,我基本没再打开过音乐 App。

最舒服的是不用再担心下架。歌在硬盘里,服务器在自己家,谁也拿不走。

缺点也有:

最后

这件事做完,我才意识到"音乐会员"卖的不是歌,是入口。入口自己搭一个,歌本来就在你硬盘里。

如果你硬盘里也躺着几百首歌,又不想再交年费,Navidrome 是最省事的方案——一个容器,一个网页,剩下就是整理标签的耐心。


如果你也在折腾这套东西,碰到卡住的地方,可以加我微信 lige0552 聊聊。白天要上班,消息回得慢,看到都会回。