Navidrome + StreamMusic——你的下一个网易云

需求
原本我是一直使用iPod听歌的,然后通过iTunes + FreeFileSync经由NAS在两台电脑之间管理、同步曲库。随着高中毕业,iPod也到了退休的时候。
我一直有存歌的习惯,不只是因为iPod,还有对流媒体平台的会员制与版权争夺的厌倦。但iPod退休,我也就没有理由继续使用iTunes或者AppleMusic。纯粹使用文件夹管理歌曲是困难的,而市面上跨平台媒体播放器的曲库管理也一言难尽。
于是我找到了Navidrome。
环境
- 有一台服务器;
- 服务器有Docker;
- 通过Zerotier虚拟专用网连接;
- 有公网IP可以忽略。除Zerotier外,还可以使用FRP等内网穿透服务;
- 在国内使用Zerotier,对于网络带宽有比较高的要求,部署moon服务器往往会有更好的体验;
- 可以用iPerf测试,如果需要流畅播放320Kbps MP3音频建议iPerf测试结果达到10Mbps;
- 如果只是听歌最好不要部署ZeroNSD。
部署
- 如果在国内没有可用的Dockerhub镜像,设置好代理;
修改/etc/docker/daemon.json
1 | { |
- 创建
/opt/navidrome
并在该目录下编辑docker-compose.yml
。
其中,volumes
需要根据提示编辑。
1 | services: |
- 部署运行
1 | docker-compose up -d |
浏览器访问服务器的4533端口,根据提示一步步设置,就可以进入web主界面。
曲库
iTunes导入
如果是从零开始存歌本章可以忽略。
下面以iTunes为例。对于其他不同的播放器,一般需要导出为m3u格式的播放列表,再存入navidrome的音频文件目录。
这是我一年前的操作方法,仅供参考。
在曲库目录下创建
plist
目录便于管理播放列表(可选);在iTunes中,于工具栏->“偏好设置”->“高级”选项卡,勾选“与其他应用共享iTunes资料库XML”选项;
安装Python3与pip,通过
itunesLibrary
导出为m3u播放列表。基于Python3交互式客户端进行操作,一些方法如下:- 初始化:
1
2
3
4
5import os
from itunesLibrary import library
path = os.path.join("PathTo/iTunes/iTunes Music Library.xml")
lib = library.parse(path) - 查询已有播放列表:
1
2for playlist in lib.playlists:
print(playlist.title) - 选择播放列表并查询当前播放列表下的所有项目:
1
2playlist=lib.getPlaylist("PlaylistName") # playlist title
print(playlist.items) # 所有项目 playlist.items
字典的一些键:Key Comment Track ID 音轨的唯一标识符 Size 音轨文件的大小(通常以字节为单位) Total Time 音轨的总时长(通常以毫秒为单位) Track Number 音轨在专辑中的编号 Year 音轨发布的年份 Date Modified 音轨文件最后一次修改的日期 Date Added 音轨被添加到播放列表的日期 Bit Rate 音轨的比特率(通常以kbps为单位),表示音质 Sample Rate 音轨的采样率(通常以Hz为单位),表示音频的清晰度 Play Count 音轨被播放的次数 Play Date 音轨最后一次播放的日期 Play Date UTC 音轨最后一次播放的日期(UTC时间) Skip Count 音轨被跳过的次数 Skip Date 音轨最后一次被跳过的日期 Artwork Count 音轨关联的封面艺术数量 Persistent ID 音轨的持久化唯一标识符,即使文件移动或重命名也不会改变 Track Type 音轨的类型(如音乐、播客等) File Folder Count 音轨文件所在的文件夹数量 Library Folder Count 音轨在音乐库中的文件夹数量 Name 音轨的名称 Artist 音轨的艺术家或表演者 Album 音轨所属的专辑名称 Kind 音轨的文件类型(如MP3、AAC等) Location 音轨文件的存储位置。
使用的是URI的格式,需要用urllib.parse.unquote
转码。- 举例:
1
2
3
4
5
6
7
8
9
10
11>>> playlist.items[0].keys()
dict_keys(['Track ID', 'Size', 'Total Time', 'Track Number', 'Year', 'Date Modified', 'Date Added', 'Bit Rate', 'Sample Rate', 'Play Count', 'Play Date', 'Play Date UTC', 'Skip Count', 'Skip Date', 'Artwork Count', 'Persistent ID', 'Track Type', 'File Folder Count', 'Library Folder Count', 'Name', 'Artist', 'Album', 'Kind', 'Location'])
>>> playlist.items[0].getItunesAttribute('Name')
'運命 (はるまきごはん×煮ル果実)'
>>> playlist.items[0].getItunesAttribute('Artist')
'はるまきごはん/煮ル果実'
>>> playlist.items[0].getItunesAttribute('Location')
'file://localhost/C:/Users/bkryofu/Music/PlaylistA/%E3%81%AF%E3%82%8B%E3%81%BE%E3%81%8D%E3%81%94%E3%81%AF%E3%82%93%3B%E7%85%AE%E3%83%AB%E6%9E%9C%E5%AE%9F%20-%20%E9%81%8B%E5%91%BD%20(%E3%81%AF%E3%82%8B%E3%81%BE%E3%81%8D%E3%81%94%E3%81%AF%E3%82%93%C3%97%E7%85%AE%E3%83%AB%E6%9E%9C%E5%AE%9F).mp3'
- 初始化:
在读取资料库并选取好要导出的播放列表后,就可以通过以下方法从控制台得到m3u播放列表:
1
2
3
4
5
6
7
8def export(playlist):
from urllib.parse import unquote
print('#EXTM3U\n#PLAYLIST:' + playlist.title)
for n in range(len(playlist.items)):
print("#EXTINF:" + str(n) + "," + playlist.items[n].getItunesAttribute('Artist') + ' - '+playlist.items[n].getItunesAttribute('Name'))
print('/music/'+unquote(playlist.items[n].getItunesAttribute('Location')).split('/')[-1])
export(playlist)控制台输出的格式应该像是这样的:
1
2
3
4
5
6
7
8#EXTM3U
#PLAYLIST:[S]はるまきごはん
#EXTINF:0,はるまきごはん - 約束 (はるまきごはんVocal ver)
/music/はるまきごはん - 約束 (はるまきごはんVocal ver).mp3
#EXTINF:1,はるまきごはん - 再会 (はるまきごはんVocal ver)
/music/はるまきごはん - 再会 (はるまきごはんVocal ver).mp3
#EXTINF:2,はるまきごはん/初音ミク - メルティランドナイトメア
/music/はるまきごはん;初音ミク - メルティランドナイトメア.mp3将输出的字符串拷贝至一个文本文档,以m3u为后缀命名。进入navidrome走一遍资料库完全扫描,就能出现刚导入的播放列表。
管理
增删歌曲可以在webUI中操作,修改播放顺序在webUI中通过拖拽实现,但对于一条100+的歌单而言,拖拽管理显然低效。
目前似乎没有更好的解决方法。我的做法是:
- 在WebUI的播放列表页,导出m3u播放列表;
- 修改m3u播放列表的文本;
- 将新修改的播放列表替换掉旧的播放列表。
智能播放列表
Navidrome支持智能播放列表。保存为以snp为后缀的json文本文件。
比如,我想要在我的所有歌曲中,筛选出ずっと真夜中でいいのに。的歌曲,artist
元数据要包含ずっと真夜中でいいのに。
和ACAね
,智能播放列表JSON就应该是这样的:
1 | { |
参见How to Use Smart Playlists in Navidrome (Beta)
播放
除了可以在网页端播放,还可以使用音流 - Stream Music客户端。
音流是目前唯一跨Windows、Apple、Android的navidrome客户端。不开源,可以长期免费使用,也可以内购永久买断解锁更多功能。
音流由国人开发,在交互界面上也符合国人的使用习惯。
但在一些方面,仍有一些小问题。比如:
- v1.3+ 只能联网读取播放列表;
- 本地存储的元数据不包括封面逼死强迫症;
- 早先某个版本出现过播放时卡顿的问题(现已修正);
- etc.
简评
不得不承认,即使有极其友好的用户界面,Navidrome也不适合一般的消费者。
一年的使用下来,我的评价是,Navidrome与StreamMusic的方案作为iTunes+iPod的替代品,是合格的。但并不是所有人都有技术和资源去折腾。
从去年到今年,我的服务器也经历了几次软硬件更新。旧的H110M主机替换掉了原本的酷睿2小电脑,作为我的土豆服务器;双网卡链路聚合的网络方案一定程度上拓展了网络带宽;通过natfrp部署zerotier-moon服务器曲线救国,解决公网peer不到的问题。也因此,navidrome听歌的体验也随着软硬件更新迭代而不断变好。
虽然我还是有网易云的学生黑胶VIP,但网易云对于我来讲已经是可有可无的存在了。