惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
WordPress大学
WordPress大学
博客园_首页
罗磊的独立博客
D
Docker
N
Netflix TechBlog - Medium
博客园 - Franky
Hugging Face - Blog
Hugging Face - Blog
D
DataBreaches.Net
I
InfoQ
L
LangChain Blog
GbyAI
GbyAI
V
V2EX
博客园 - 聂微东
P
Proofpoint News Feed
博客园 - 【当耐特】
腾讯CDC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
Martin Fowler
Martin Fowler
有赞技术团队
有赞技术团队
U
Unit 42
博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏

atpX

自建 S3 兼容对象存储服务 Garage 听风的歌 偶尔是深夜就好了 新玩具 AirPods Pro 3 公交车上的时间 从 WHOIS 到 RDAP 通过 WireGuard 访问 NFS 共享文件 我停止了探索 Fediverse 互联网背景噪音 我的数字生活降级 小城与确定性的墙 一只特立独行的猪 Fediverse 与社交 承认的勇气 mediaX - 轻量书影音记录管理工具 我的博客写作流程 网站新增 Misc 页面 擅长对线的鲍勃 在 Chroot 环境下使用 Rsync 同步 再见 JavaScript 当我玩博客时我在玩什么 为什么我的博客没有友链页面 小熊猫与大熊猫 (HDR 照片测试) 是时候为网站开启 HTTP/3 支持了吗 使用 AdGuard Home 搭建自用 DoH 服务 谈谈读书与消遣 2023 年终总结 西安两日游 从 AirPods「升级」到 EarPods Docker 搭建去中心化的微博客平台 Mastodon
自建音乐串流服务探索
ATP · 2025-03-28 · via atpX
selfhosted-music-streaming-server

听歌这件事似乎变得越来越麻烦。

2014 年之前,我主要用 QQ 音乐听歌,那时随便一个平台都有着丰富的曲库。2014 年,我转到了眉清目秀的网易云音乐,那时的网易云音乐还很纯粹,后来国内音乐进入了「版权时代」,看着歌曲一天天变灰也坚持用着,直到开始不务正业引入短视频等各种臃肿功能,2018 年的下架周董歌曲「打包收费」事件,让我直接卸载了网易云音乐,即使还有很长时间的会员没到期。此时国内音乐进入了「独家版权时代」,不同时开几个平台的会员很难有好的体验。好在及时醒悟过来放弃了国内音乐平台,之后一直用着 Apple Music 搭配 Spotify,算是比较省心。不过为了给消费降级趋势出一份力,去年底也取消订阅了使用 8 年的 Apple Music。

其实也是发现自己对音乐曲库的需求越来越小了,平时基本在听老歌,听歌更多时候是为了作为 BGM 增加点氛围感。我对华语音乐的记忆似乎还停留在 10 年前,对外语音乐的记忆停留在 5 年前,可能一代人有一代人的歌,新一代的歌我也很难去欣赏。现在只是偶尔去听下自己关注歌手的新曲,或者 Spotify 推荐歌单。既然如此,不如自建音乐串流服务,整理出自己的专属曲库,体验应该也差不了太多。

自建音乐服务项目有不少,我主要是听个响,有损 MP3 320 Kbps / AAC 256kbps 足以,还省空间,所以 Roon 这类很贵专业的方案是直接跳过的。同时我的音乐文件都习惯先通过 MusicBrainz Picard 整理标记,所以对服务端功能也没太多要求。过去一年里陆续尝试过 Emby/Jellyfin, Navidrome, Gonic, LMS (Lightweight Music Server) 等服务,网上能搜到很多介绍文章,这里不再多说。同时也把 iOS App Store 里能搜索到的对应客户端几乎试了个遍。

就结论来说,过去大半年里我都用着 Navidrome 服务端搭配 Amperfy 客户端。整体比较满意,美中不足的是 Navidrome 还不支持读取外挂歌词文件(等了快一年的 PR应该也快了 已合并)。因为这个问题有段时间换到过 Jellyfin 搭配 Manet/AmpFin,但体验下来还是不如 Navidrome + Amperfy 简单顺滑,加上 Amperfy 后来新增了 macOS 原生客户端支持,毫不犹豫的换了回来并使用到现在。

amperfy
Amperfy

当然,我也知道还有一个热门的组合没尝试,经常看到网友对 Plex 的音乐软件 Plexamp 赞美有加,但很多特性需要开通 Plex Pass 会员才支持,而我对 Plex 的印象一直不太好。以前搭建过 PMS (Plex Media Server),必须用 Plex 账号联网登录,各种隐私数据收集拉满,后来还禁止托管在 Hetzner 上。加上 Plex 一直在向流媒体服务转型,混乱的社交名流主页,对自建用户的体验越来越不重视,所以一直没尝试。但前几天看到 Plex Pass 即将涨价和阿根廷区低价 Lifetime Plan 的消息后,还是按耐不住,顺手搭上了末班车,可以说这次购买几乎是冲着 Plexamp 去的。

plexamp
Plexamp

几天体验下来,先说服务端 PMS,抛开我对 Plex 的「恶意」不谈,Plex 确实比 Emby/Jellyfin 更加好看和流畅,使用上也更省心,音乐库的管理功能上倒是都差不多。在歌词这一块,Plex 目前和 Navidrome 相反,不支持内嵌歌词,只支持外挂歌词,不过如果没有本地歌词 Plex 会自动通过 LyricFind 寻找(需要 Plex Pass),可惜对于中文歌曲支持一般。

再说客户端 Plexamp,基础功能大家都一样,Plexamp 的亮点在于 UI 设计、音乐无缝切换和基于音乐(库)分析的推荐/电台功能。手机端上的体验比较满意,但不多做夸奖。桌面端上就比较失望了,Electron 应用在我这里向来是扣分的,但也不是不能接受,除非太敷衍,Plexamp 桌面端几乎就是移动端的放大版,没做过多的适配。同时也遇到了不少 bug,比如左上角关闭窗口后,后台仍在运行,但无法恢复窗口显示,只能退出进程重新打开 怪不得默认隐藏窗口控件。也发现即使你下载了整个歌单,仍然只有从下载分栏进入歌单播放才会使用本地文件,如果从其他入口播放该歌单还是会再次下载缓存到硬盘(已在设置中开启始终优先选择下载的媒体),把缓存和下载功能分开看待的逻辑有点难以理解,于是我选择了直接把缓存拉满。更可惜的是我发现的不少 bug 都能在一些多年前的反馈帖子中找到,却不了了之或无人问津。

不过如果再次抛开我对 Plex 的「恶意」不谈,Plexamp 整体体验是不错的,对于多数想自建的用户来说算的上是比较出色的方案,无论是音乐库管理,UI 界面,还是功能性相比其他几个平台都有一定的优势。但 Plex Pass 会员现在并不便宜,如果只是为了音乐串流服务的话就不太值了。

总的来说,目前我应该会继续主力使用 Navidrome + Amperfy,等哪天 Plexamp macOS 客户端的体验更好了可能会全面切过去。其实对于自建音乐串流服务来说,选择平台往往是最简单的部分,最麻烦的还是资源获取与整理,无论是自购转录还是网上找都很花时间。好在我喜欢的歌不算太多,一年下来零零散散着整理也差不多了,不然还是建议直接订阅音乐流媒体更加舒畅。

小剧场:消失的 Plex 外挂字幕与 Plexamp 歌词

既然买了会员,也顺便再次试下 Plex 的影视媒体库,相比 Emby/Jellyfin 确实有独特的优点,但也有糟心的问题。测试网页播放时,发现 Plex 对于外挂 ASS 字幕的支持有个老问题,我的 PMS 搭建在 VPS 上,所以关闭了转码,直接通过串流播放,但 Plex 的逻辑是只要字幕包含不支持的特效就会强制转码烧录,在设置中修改 Plex Web 播放器的固化字幕选项为「仅图像模式」可以解决部分问题,但其他情况下还是会遇到错误提示「该服务器没有足够性能用于转化视频」,不加载字幕则可以正常播放,经测试同一个视频和字幕在 Jellyfin 网页播放没有问题 当然 Jellyfin 有他自己的祖传方块问题

那我放弃网页播放,改用第三方客户端(Infuse/Vidhub)播放。但这时发现连字幕的选项都没有了,直接无法获取。搜索半天在 Plex 论坛上发现有人提到可能是 Nginx 反代问题,试着添加下面配置后终于可以获取字幕了。

location /library/streams/ {
    proxy_pass_request_headers off;
    proxy_pass http://127.0.0.1:32400;
}

解决问题后,满意的打开 Plexamp 准备听音乐放松下,却发现所有歌曲都无法显示歌词了… 一开始还以为是客户端的 bug,重启重装研究了好一会才想到可能是修改 Nginx 配置导致的问题,注释掉后果然又可以正常获取歌词了。

于是猜测可能是某个 header 导致了无法获取字幕,测试以下配置:

location /library/streams/ {
    # 默认关闭转发 header
    proxy_pass_request_headers off;
    # 转发 Plex 自定义 header
    proxy_set_header X-Plex-Client-Identifier $http_x_plex_client_identifier;
    proxy_set_header X-Plex-Device $http_x_plex_device;
    proxy_set_header X-Plex-Device-Name $http_x_plex_device_name;
    proxy_set_header X-Plex-Platform $http_x_plex_platform;
    proxy_set_header X-Plex-Platform-Version $http_x_plex_platform_version;
    proxy_set_header X-Plex-Product $http_x_plex_product;
    proxy_set_header X-Plex-Token $http_x_plex_token;
    proxy_set_header X-Plex-Version $http_x_plex_version;
    proxy_set_header X-Plex-Nocache $http_x_plex_nocache;
    proxy_set_header X-Plex-Provides $http_x_plex_provides;
    proxy_set_header X-Plex-Device-Vendor $http_x_plex_device_vendor;
    proxy_set_header X-Plex-Model $http_x_plex_model;
    proxy_pass http://127.0.0.1:32400;
}

默认关闭 header 转发,只转发 Plex 自定义的 header,终于同时解决了两个问题。