再见,所有的音乐订阅

我厌倦了音乐订阅:每月付钱从残缺的曲库里借歌听,即使点击了“添加到库中”的歌曲也可能会没法再次收听。音乐不同于游戏,是要被反复使用的,所以最好还是放在自己的电脑里由自己掌控。正巧前段时间看上了可以自托管的音乐服务器Navidrome,告别音乐订阅的念头再一次出现了。

获取音乐文件

以前

第一次想要整理自己的曲库时谷歌尚在国内运营谷歌音乐。我发现在谷歌音乐上下载的MP3在播放时会显示专辑封面,而百度音乐上下载的不会显示。当时不知道这是为什么,只觉得谷歌音乐更好,因此在谷歌音乐上下载了常听的音乐——现在回想起来,大概有《News of the World我对那张专辑的封面印象深刻

谷歌音乐不行后,网易云音乐站起来了。自然,切换到网易云音乐后,我就用它来下载MP3了。不过我现在找不到当时下的资源,甚至不能用网易云音乐了。而且即使能用网易云音乐,现在也不能直接下载平台自由的音乐文件。所以,我又得重新获取音乐文件了。

现在

抛弃网易云后我转向了苹果音乐,并且一直用到现在。因此目前最理想的收集音乐方法就是从苹果音乐里下载——只是,苹果不让用户这么做。

网上有付费软件让你从苹果音乐“下载”MP3,但实质上是在后台给苹果音乐录音。我对这种做法的音频质量有所怀疑。况且掏钱买盗版怎么想怎么奇怪。所以这种方法被我否了。

最直接的方法当然是破解苹果的DRM。GitHub上有个仓库貌似是做这个的,但缺少一些代码所以没法运行。遗憾,看来音频收藏社区不像书籍收藏社区那么流行DeDRM。

再然后我又找到了读取苹果音乐元数据后从YouTube上下载相似歌曲的工具。这是一个好思路,因为YouTube上有好多唱片公司提供的音频,而且YouTube Music据说也是用那些音频处理后做成的服务。所以YouTube上那些官方音频音质大概不会太差。不过,那工具是用JS写的——我讨厌JS,所以不想用那个工具。

既然决定了要从YouTube上下载资源,那什么工具也比不上yt-dlp。下载质量最佳的音频,只要用下面的命令(其实它不止能下YouTube,还能下BiliBili

yt-dlp -f bestaudio --extract-audio --add-metadata \
       --sleep-interval 10 --max-sleep-interval 90 \
       --download-archive downloaded.txt \
       "$url"

如果只下一首歌,可以把sleep的选项去掉。我经常下好几首,害怕YouTube把我当机器人,所以在每次下载之间等1090秒,假装在回味音乐。

如果想把视频缩略图当成专辑封面嵌入音频文件,可以加上--embed-thumbnail。不过YouTube的缩略图不是正方形的,要想用yt-dlp得到正方形的缩略图,需要用FFmpeg裁剪。我感觉裁剪命令太复杂了,况且可以用待会提到的beets自动下载封面,所以我就不用--embed-thumbnail了。

另外,指定bestaudio而不指定扩展名的话下载下来的音频大概率是128 Kb/s码率、48000 Hz采样率、Opus编码的文件。从码率和编码的角度来看(假定YouTube是用无损文件转的Opus,128 Kb/sOpus已经听不出和无损的差距了当然,评判波的好坏不能只看参数,最重要的是人的感觉——这是我学完《数字图像处理》后唯一记得的话。

悔不当初

去年的这个时候,我的朋友住在一个音乐爱好者的房子里。那房子的几个储物柜堆满了CD和黑胶随便租客用。我要是那时动了整理音乐收藏的念头,就不用从YouTube上下歌然后纠结音质问题了——直接从CD里把整张专辑抓取下来就好了。

我打算等以后有自己的房子了再买CD自己抓。

整理

还是因为Navidrome,我得知了音乐管理器Beets的存在。Beets可以根据AcousticIDMusicBrainzCover Art Archive补全歌曲的元数据和封面——当然,它还有很多别的功能,但这几个是最吸引我的

甜菜根

Beets的功能很强大,但是得先在配置文件里开启各个插件才行。我只用它补充元数据、下封面,所以配置文件也很简单:

directory: 我放音乐的文件夹
plugins: fromfilename chroma lastgenre fetchart
import:
  move: yes

然后对着下载好的Opus文件使用Beets导入即可。不过Beets的设计思路其实是一口气导入整张专辑。这让我这种一张专辑只听其中一两首的人感到怪异:在导入某张专辑的第二歌后需要两首一起重新匹配专辑数据。

其他功能我不多说了,还请各位阅读Beets的文档另外关于Beets、MusicBrainzthe Cover Art Archive,这有篇博客讲得不错见下一小节。

编辑MusicBrainz

本来我以为MusicBrainz的数据够全——毕竟是全世界的志愿者在维护,而且连新番《孤独摇滚》的曲子都有记录好几个版本。结果刚写完这篇博客第二天,就发现頭脳警察的条目少好几张专辑。无奈,帮他们补了两张专辑。

MusicBrainz同样以专辑为核心整理音乐,而且他们区别了概念上的专辑和实际发行的专辑:当歌手说他发了新专辑时,是概念上的专辑;某个发行商发行专辑时,就会产生实际发行的专辑。前者在MusicBrainz中被称为Release group,与地区、介质无关;后者被称为Release,包含地区、介质等信息。真不愧是全世界的数据库。

不过在添加数据库中缺失的专辑时可以直接添加Release,系统会自动添加包含那个ReleaseRelease group。所以在添加时不用想太多,把所需信息填完就好了。添加完后有一种为人类做出贡献的感觉——虽然理论上来讲我每天都在为社会创造价值,但主要是以帮公司赚钱的形式完成的,不够透明。

关于封面的插曲

Beetsfetchart插件会把专辑封面下载到专辑目录里的cover.jpg里,而不是嵌入到音乐文件里。最开始我以为Navidrome只能读取嵌入到音乐里的封面,所以我使用Beetsembedart插件把cover.jpg再嵌到音乐里。

结果嵌完了发现本来3MBOpus文件直接变11MB了——合着封面比音乐本身还大。发现这一点后我浑身都不舒服了。Beetsembedart插件可以调整封面尺寸,然后我开始纠结合适的封面大小。后来发现Navidrome可以调整ND_COVERARTPRIORITY来优先读取cover.jpg后,又想把嵌入的封面再抠出来节省空间(其实并不缺空间,只是一种洁癖

嵌好嵌,因为这是大众需求;抠难抠,因为这是小众需求——更何况不是抠MP3,而是抠Opus。晚上查了一圈后盯上了Beets、yt-dlppicard都依赖的元数据修改库mutagen。好爽,又学了一招。

from mutagen import File
from glob import glob

for path in glob('**/*.opus', recursive=True):
    f = File(path)
    if 'metadata_block_picture' in f.keys():
         _ = f.pop('metadata_block_picture')
         f.save()

播放

这次整理音乐收藏的念头是由Navidrome而起的,所以当然会用Navidrome来做播放器了。

选中Navidrome的原因之一是听说它可以在内存只有512MB的树莓派零上运行。我其实对各种程序需要多少内存没什么概念——因为现在连手机内存都以GB为单位了,所以以为它真要用几百MB内存。实际使用时发现Navidrome只要44MB内存,回想起自己那台512MB内存的VPS还有270MB内存处在空闲状态,不禁开始后悔黑五时新租的两GB内存VPS了。要知道,用各种程序填满价格低廉的VPS也是有快感的——其爽点类似生存游戏的背包管理。

不过,总归是尝试了离开音乐订阅的方法。只不过收集和整理音乐实属麻烦,说不准几天后我还会再写一篇《音乐订阅,我又回来了

Bonus Track:今年的苹果音乐统计

年底了,经常和我聊音乐的朋友突然告诉我苹果音乐也有个人年度统计。我发现结果挺有趣——正好刚写完一篇关于听音乐的博客,就把年度统计的结果补充进去吧。

去年我总共在苹果音乐上听了1,753首歌,共19,786分钟——相当于13.7天,或者一年的3.8%(可能在YouTube上听歌的时间要比在苹果音乐上长,因为YouTube上曲目更多

歌曲回放数前十名:

  1. 明天会更好,110次;
  2. Enjoy the Silence,51次;
  3. Hand in Hand,49次;
  4. Teenage Color,41次;
  5. 国际歌,36次;
  6. The Model,32次;
  7. Made of Stone,31次;
  8. Genesis,29次;
  9. I Say Love,27次;
  10. Weekender Girl,25次。

假设一首歌四分钟,那这十首歌总计回放1,724分钟,占我总播放数的8.7%——虽然不知道平均值,但我感觉这个占比较小。给我这种感觉的原因是上榜歌曲里第2、3、7、9、10名都是最近几个月才开始听的(尤其是初音的歌,我以前很讨厌,最近才开始喜欢。这些歌曲能上榜,应该是险胜上半年常听但之后再也没听的歌曲——为什么会再也没听?因为苹果音乐的用户体验就是一坨屎!它家客户端只显示最新加入库中的六十张专辑,而我一张专辑只选其中一两首歌入库(很少有两首的。这导致我只能在最新的六十首歌里面选要听什么,否则就要用麻烦的搜索功能输名字找我想听的歌。我想要的是随机展示一页歌曲的功能:苹果没有,Navidrome有。

骂完了接着说艺人排名(共603

  1. Kraftwerk,955分钟;
  2. The Stone Roses,666分钟;
  3. Justice,659分钟;
  4. livetune,610分钟;
  5. 蔡琴,545分钟;
  6. 林慧萍,545分钟;
  7. 齐豫,545分钟;
  8. 费玉清,545分钟;
  9. 郑怡,545分钟;
  10. 江蕙,545分钟。

这个排名就有趣了。Kraftwerk我确实常听,他们排第一可以理解。第二名的The Stone Roses我绝对是八月底才开始听的——当时我有个同学要回国,告别那天我才知道这个乐队的存在第三名Justice是玩电音的,我只有拉屎的时候听他们:因为够带劲所以可以通便。看起来我这一年在马桶上蹲了11个小时,平均一天1.8分钟——嗯,还好,还算健康。第四名livetune是谁?我不认识。后五名全部是回放榜上第一名《明天会更好》的演唱者。估计艺人排名后面几位也得是那首歌的其他演唱者吧。

专辑排行可以说是出乎意料了:

  1. The Soft Machine,102次;
  2. 明天会更好,80次;
  3. Eye In the Sky,76次;
  4. I Say Love,56次;
  5. The Stone Roses,40次;
  6. Turn A Gundam,31次;
  7. Californication,28次;
  8. The Very Best of Rainbow,26次;
  9. The Harvest Albums 1975-1978,26次;
  10. Who’s Next,22次。

告诉我苹果也有年度总结的同学,总播放时间比我少10,033分钟,但排第一的专辑循环数比我排第一的多一倍多。而且我的榜上后几位只播放了三十次左右,原因大概是——前面说过的——苹果音乐的设计让我只播放最新加入库中的专辑。

另外今年总共播放133张专辑,这个数差不多是苹果音乐显示专辑上限的两倍。所以能从排名中看出很强烈的后半年风格(前73张看不见了,就再也不听了

年度总结中还有歌单和电台的排名,不过这两个功能对我来说形同虚设,所以没有记录的意义。最后列一下我的最爱类型吧:

  1. 摇滚
  2. 硬摇滚
  3. Adult Alternative
  4. 金属
  5. 流行摇滚乐

其实看到这个结果我完全不知道如何解读:这排名里面有仨摇滚,而我不知道摇滚是什么。以及,我也不很清楚Adult Alternative和金属的定义。可是如果统计报告说我喜欢它们,那我确实应该能说出一些它们的共性并尝试定义它们——否则无法解释我的收听偏好。回想一下,我所爱的歌曲共性是都有吉他和架子鼓。鉴于世纪烂曲《成都》中也有吉他,所以我将摇滚、Adult Alternative和金属定义为有架子鼓的音乐。

每年年底看报告挺有趣的,告别订阅服务后可以把Navidrome连接到ListenBrainz来记录听歌数据。理论上随时可以查看各种排名——我刚创建账户,所以还没有任何值得分析的数据。