侧边栏壁纸
博主头像
human@localhost:~

行动起来,活在当下

  • 累计撰写 2 篇文章
  • 累计创建 4 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

音乐平台爱下架,那我自己当平台好了

Solar
2025-12-10 / 0 评论 / 0 点赞 / 52 阅读 / 0 字

一、初衷 / 背景

  • 现在大多数音乐平台:

要充会员

音质一般,有损压缩普遍在 320k 或更低

  • 无损音频体积大:

一首歌(FLAC / ALAC)约 20–30 MB

2 TB 空间大约可存 6 万首左右

  • 歌曲会下架、版权乱七八糟:

平台说没就没了

想系统地保存自己的收藏,只能自己存。

目标:

  • 用网盘(比如 Dropbox)当音乐仓库
  • VPS 作为中枢:

挂载网盘

清洗、统一管理音乐文件

提供 Web/客户端播放接口

  • 效果类似“自建 Spotify”,完全自己掌控库、音质、访问方式。

二、总体架构

1. 逻辑架构

云端存储(Dropbox / 其它网盘 / 本地磁盘)
          ↑
     rclone mount  →  /mnt/dropbox (或其它挂载点)
          ↑
          └── /mnt/dropbox/Music/library   ← beets 清洗后得到的“干净音乐库”
                  ↑
                  └── Docker 容器中的 /music
                          ↑
                          └── Navidrome 扫描 /music,提供 Web / API 播放

如果你本地磁盘足够大,也可以跳过 rclone,直接用本地路径当 Music/library,整体逻辑不变。

三、基础环境与前提

1. 硬件与系统

  • 一台 VPS / 服务器,示例配置(你目前实际用的是类似的):

CPU:4 vCPU

内存:16 GB

磁盘:200 GB NVMe

每月流量:16 TB

  • 操作系统:

推荐:Debian / Ubuntu 系(本文命令以 Debian / Ubuntu 为例)

注意:宿主机需要支持 FUSE(大部分 KVM VPS 没问题,OpenVZ/LXC 有的会被云服务商阉割)。

2. 以 root 用户操作

为了少扯权限问题,本文默认所有命令都在 root 下执行:

# 如果你目前不是 root,可以先切换:
sudo -i

生产环境建议用普通用户 + sudo,这里为了“新手跟着抄就能跑”直接用 root。

3. 需要安装的软件

后面会一一展开,这里先整体列一下:

  • rclone(挂载网盘)
  • fuse3(FUSE 支持,让 rclone 能挂载)
  • beets(音乐库管理)
  • ffmpeg(给 beets 的 replaygain 等插件用)
  • python3-pylast(beets 的 lastgenre 插件依赖)
  • Docker + docker compose(跑 Navidrome)

四、部分一:挂载网盘(以 Dropbox + rclone 为例)

1. 安装 rclone

apt update
apt install -y rclone

确认安装成功:

rclone version

2. 配置 Dropbox 远程(remote)

执行:

rclone config

交互步骤:

  1. 输入 n → 新建一个 remote
  2. 起名(例):dropbox_music
  3. 选择存储类型:在列表中选择 Dropbox 对应的编号(例如 13,以实际界面为准)
  4. client_id / client_secret
  • 默认回车即可(不自建 app 的话)
  1. Edit advanced config? → 输入 n
  2. Use auto config?
  • 有桌面浏览器在当前机器上 → y
  • 纯 SSH 服务器(常见)→ n

无浏览器环境(VPS)下授权方法

在 VPS 上选择 Use auto config? = n 后,rclone 会提示你在另一台机器运行:

rclone authorize "dropbox"

操作步骤:

  1. 在你自己电脑上也安装 rclone
  2. 在“有浏览器”的那台电脑上执行:
rclone authorize "dropbox"

  1. 浏览器会打开 Dropbox 登录/授权页面,按提示完成
  2. 授权成功后,终端会输出一段 JSON,例如:
{"access_token":"xxxx","token_type":"bearer", ...}

  1. 把整段 JSON 复制粘贴回 VPS 上 rclone config 的提示中,回车
  2. 在菜单中确认 remote dropbox_music 已存在 → 输入 q 退出

3. 测试 remote 是否可用

rclone lsd dropbox_music:

正常情况会列出 Dropbox 顶层目录,例如:

          -1 2025-xx-xx xx:xx:xx        Obsidian
          -1 2025-xx-xx xx:xx:xx        文件
          -1 2025-xx-xx xx:xx:xx        未归档
          ...

如果这里就报错,说明 Dropbox 授权 / 网络 / remote 名有问题,先修这个再往下走。

4. 安装 FUSE3(解决 fusermount3 报错)

如果直接 mount,会遇到类似错误:

Fatal error: failed to mount FUSE fs: fusermount: exec: "fusermount3": executable file not found in $PATH

原因:系统没装 FUSE3,rclone 找不到 fusermount3

安装:

apt install -y fuse3

检查:

which fusermount3

有路径输出即可。

5. 创建挂载点

mkdir -p /mnt/dropbox

6. 创建 systemd 服务,开机自动挂载

新建服务文件:

nano /etc/systemd/system/rclone-dropbox.service

内容:

[Unit]
Description=Rclone Mount Dropbox (Music)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/rclone mount dropbox_music: /mnt/dropbox --dir-cache-time=72h --vfs-cache-mode=full --vfs-cache-max-size=50G --vfs-cache-max-age=336h --tpslimit=10 --buffer-size=16M --umask=000 --log-file=/var/log/rclone-dropbox.log --log-level=INFO
ExecStop=/bin/fusermount3 -u /mnt/dropbox
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

注意:

  • ExecStart 必须是一行,systemd 不认 \ 换行。
  • 如果你的 fusermount3 不在 /bin,用 which fusermount3 找到路径后改掉。

加载并启动服务:

systemctl daemon-reload
systemctl enable rclone-dropbox
systemctl start rclone-dropbox
systemctl status rclone-dropbox

7. 验证挂载是否成功

df -h | grep dropbox
ls /mnt/dropbox

如果可以看到 Dropbox 顶层目录,例如:

Obsidian  docFile  dysk  mac  project  应用  文件  未归档

说明挂载成功,此时对上层软件来说,/mnt/dropbox 就是一个“本地盘”。

五、部分二:规划音乐目录 & 使用 beets 清洗音乐库

1. 规划音乐目录结构

基于已挂载的 /mnt/dropbox,规划音乐相关目录:

mkdir -p /mnt/dropbox/Music/{incoming,library,trash}
mkdir -p /mnt/dropbox/Music/incoming/{albums,singles}

约定:

  • incoming/:新音乐临时区

incoming/albums:专辑(每个文件夹一张专辑)

incoming/singles:散单曲 / live / remix 等

  • library/beets 整理好的正式音乐库(Navidrome 将指向这里)
  • trash/:丢弃但暂不物理删除的文件(可选)

2. 安装 beets 及依赖

apt install -y beets ffmpeg python3-pylast

确认:

beet version

正常输出类似:

beets version 1.6.0
Python version 3.11.x
plugins: embedart, fetchart, lastgenre, lyrics, replaygain, scrub

如果之前没装 python3-pylast,会看到:
ModuleNotFoundError: No module named 'pylast',装上就好。

3. 配置 beets

创建配置文件:

mkdir -p /root/.config/beets
nano /root/.config/beets/config.yaml

推荐配置:

directory: /mnt/dropbox/Music/library
library: /root/.config/beets/music.db

import:
  move: yes        # 导入后移动文件到 library
  copy: no
  write: yes       # 写回标签到音频文件
  from_scratch: no
  incremental: yes
  quiet_fallback: asis
  timid: no        # 尽量少问,多自己决定
  languages: zh en

paths:
  default: $albumartist/$album%aunique{}/$track - $title
  singleton: Singles/$artist/$title
  comp: Compilations/$album%aunique{}/$track - $title

plugins:
  - fetchart
  - embedart
  - lastgenre
  - lyrics
  - scrub
  - replaygain

fetchart:
  auto: yes

embedart:
  auto: yes

lastgenre:
  auto: yes
  canonical: yes

lyrics:
  auto: yes

replaygain:
  backend: ffmpeg

4. 专辑导入(批量)

把专辑按“一个专辑一文件夹”的形式放到:

/mnt/dropbox/Music/incoming/albums/
  BTS - Agust D - D-2 (2020)/
  ...

标准交互导入

beet import /mnt/dropbox/Music/incoming/albums

beets 会:

  • 按目录分专辑
  • 在线匹配(MusicBrainz)
  • 对每张专辑给出候选:

典型交互示例(你实际遇到过的):

No matching release found for 10 tracks.
[S]kip, Use as-is, as Tracks, Group albums, Enter search, enter Id, aBort?

  • Enter search (e):自己输入搜索词(如 Agust D D-2
  • 匹配到后:
Artist: Agust D - D-2
Album: BTS
...
(A)pply, More candidates, Skip, Use as-is...

A 接受匹配。

导入完成后,目录会变成类似:

/mnt/dropbox/Music/library/Agust D/D-2/01 - 저 달.m4a
...

确认:

tree -L 3 /mnt/dropbox/Music/library | head -n 50
beet ls Agust D

更自动的导入(专辑一锅炖)

标签质量还可以、懒得每张确认时:

beet import -q -A /mnt/dropbox/Music/incoming/albums

  • -q:少说话
  • -A:自动接受匹配

5. 单曲导入(singletons)

散单曲、Soundcloud 下载、非正式 live 等,建议全部放到:

/mnt/dropbox/Music/incoming/singles/

单曲导入命令(整目录):

beet import -s /mnt/dropbox/Music/incoming/singles

  • -s / --singletons:告诉 beets「这些是散曲,不要按专辑处理」

导入过程中:

  • 匹配不到专辑时,常用选项 → Use as-is
  • 最终路径会按 singleton 规则生成,比如你现有的:
/mnt/dropbox/Music/library/Singles/NewJeans/Ditto.flac
/mnt/dropbox/Music/library/Singles/NewJeans/New Jeans.flac
/mnt/dropbox/Music/library/Singles/NewJeans/Super Shy.flac

单首导入示例:

beet import -s /mnt/dropbox/Music/incoming/singles/JENNIE_Live_2025_second_week.mp3

建议:导入前,用本地标签工具(mp3tag/kid3 等)至少补好 ArtistTitle,避免出现类似
__/00 -.mp3 这种抽象命名(你已经见识过一次了)。

6. 导入后的日常操作流程

以后推荐日常习惯是:

  1. 下载/同步音乐 → 丢进 incoming:
  • 专辑 → incoming/albums/某专辑目录/
  • 单曲 → incoming/singles/
  1. 定期跑两条命令:
# 批量导入专辑
beet import -q -A /mnt/dropbox/Music/incoming/albums

# 导入单曲
beet import -s -q /mnt/dropbox/Music/incoming/singles

  1. 导入完后,/mnt/dropbox/Music/library 就是干净、可被 Navidrome 直接使用的音乐库。

六、部分三:Docker 方式部署 Navidrome

1. 安装 Docker & docker compose 插件(Debian/Ubuntu 示例)

apt install -y docker.io docker-compose-plugin
systemctl enable docker
systemctl start docker

确认:

docker version
docker compose version

2. 准备 Navidrome 目录与 docker-compose

创建目录:

mkdir -p /srv/navidrome
cd /srv/navidrome
mkdir -p /srv/navidrome/data

创建 docker-compose.yml

nano /srv/navidrome/docker-compose.yml

内容:

version: "3.8"

services:
  navidrome:
    image: deluan/navidrome:latest
    container_name: navidrome
    restart: unless-stopped
    ports:
      - "4533:4533"
    environment:
      ND_MUSICFOLDER: "/music"
      ND_DATAFOLDER: "/data"
      ND_ADDRESS: "0.0.0.0"
      ND_PORT: "4533"
      ND_LOGLEVEL: "info"
      TZ: "Asia/Shanghai"    # 或你自己的时区
    volumes:
      # beets 清洗后的音乐库(rclone 挂载的 Dropbox 目录)
      - /mnt/dropbox/Music/library:/music:ro
      # Navidrome 自己的数据
      - /srv/navidrome/data:/data

注意:

  • MusicFolder 映射的是 beets 整理后的库
  • /music:ro 只读挂载,避免 Navidrome 改你文件内容

3. 启动 Navidrome

cd /srv/navidrome
docker compose up -d
docker compose ps

浏览器访问:

http://你的VPSIP:4533/

第一次打开会让你创建管理员账号,按照页面提示完成。

Navidrome 会自动扫描 /music,即 /mnt/dropbox/Music/library
此时你应该能看到:

  • Agust D / D-2
  • JENNIE / Live 2025 second week
  • Singles / NewJeans / Ditto ...

这些都已经在你的库里出现。

前提:rclone 的挂载服务已启动,即 /mnt/dropbox 已经挂好。
如果 Navidrome 启动时 /mnt/dropbox 是空的,它就只会扫描空气。

七、使用 Navidrome 客户端

1. Web 端

  • 直接浏览器访问:http://你的VPSIP:4533/
  • 或将 Navidrome 放在 Nginx/Caddy 反代后,用 https://music.你的域名/

Web 界面支持:

  • 按专辑 / 艺人 / 歌曲浏览
  • 搜索
  • 歌单
  • 随机播放等

2. 其他客户端(手机/桌面)

Navidrome 兼容 Subsonic API,可以用很多第三方客户端,例如:

  • 桌面:Feishin(跨平台)
  • Android:Substreamer / Symfonium / Ultrasonic
  • iOS:iSub 等(具体按你喜好选)

一般配置方式:

  • 服务器地址:http://你的VPSIP:4533https://你的域名
  • 用户名 / 密码:Navidrome 中创建的账号
  • 协议类型:Subsonic/Navidrome(视客户端选项)

八、常见坑与踩坑记录(你实际遇到过的)

1. fusermount3 找不到,rclone 挂载失败

报错:

Fatal error: failed to mount FUSE fs: fusermount: exec: "fusermount3": executable file not found in $PATH

解决:

apt install -y fuse3

然后重启 rclone-dropbox 服务。

2. /etc/fuse.conf 不存在

你一开始用了:

sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf

结果系统回答:

sed: can't read /etc/fuse.conf: No such file or directory

原因:很多系统默认没有这个文件。

在你当前方案中:

  • 使用 root 运行 rclone
  • 没用 --allow-other

所以可以完全忽略 fuse.conf
若未来要用 --allow-other,手动创建 /etc/fuse.conf 并写入:

user_allow_other

即可。

3. systemd 里的 ExecStart 写成多行,挂载一直失败但服务显示 running

你一开始写成:

ExecStart=/usr/bin/rclone mount dropbox_music: /mnt/dropbox \
  --dir-cache-time=72h \
  ...

systemd 不会像 shell 那样识别反斜杠换行,结果 rclone 收到一堆乱七八糟的参数,挂载失败但服务状态还是 active

解决:
ExecStart 改成完整的一行:

ExecStart=/usr/bin/rclone mount dropbox_music: /mnt/dropbox --dir-cache-time=72h --vfs-cache-mode=full --vfs-cache-max-size=50G --vfs-cache-max-age=336h --tpslimit=10 --buffer-size=16M --umask=000 --log-file=/var/log/rclone-dropbox.log --log-level=INFO

然后:

systemctl daemon-reload
systemctl restart rclone-dropbox

4. beets 插件 lastgenre 报 pylast 缺失

报错:

** error loading plugin lastgenre:
ModuleNotFoundError: No module named 'pylast'

解决:

apt install -y python3-pylast
# 或 pip install pylast

然后再 beet version 验证插件加载正常。

5. beets 导入时出现 __/00 -.mp3 这种奇怪路径

你遇到的例子:

/mnt/dropbox/Music/library/__/00 -.mp3

原因:

  • 文件本身几乎没有标签(artist/album/title 为空)
  • beets 按 paths.default 规则尝试拼路径
  • 空字符串被降级成 __ / 00 / - 之类占位

解决办法:

  • 导入前用标签工具至少补上 artist/title,或者
  • 导入后用 beets 修改:
beet modify path:/mnt/dropbox/Music/library/__/00\ -.mp3 artist=JENNIE albumartist=JENNIE album="Live 2025" title="Live 2025 second week" track=1
beet move path:/mnt/dropbox/Music/library/__/00\ -.mp3

这样文件就会被重新移动到正常路径下。

6. SoundCloud / 非官方来源的专辑/单曲匹配不上

你遇到 BTS - Agust D - D-2 (2020) 这样的目录,来自 SoundCloud。

beets 提示:

No matching release found for 10 tracks.
[S]kip, Use as-is, as Tracks, Group albums, Enter search, enter Id, aBort?

正确姿势就是:

  1. e(Enter search),输入 Agust D D-2
  2. 选中正确的 MusicBrainz release
  3. A(Apply)接受匹配

最终得到的就是现在这样:

Agust D/D-2/01 - 저 달.m4a
...

九、总结:整条链路的日常使用流程

  1. 网盘挂载
  • rclone + fuse3 → /mnt/dropbox
  • systemd 管理,开机自动挂载
  1. 音乐放入
  • 专辑:/mnt/dropbox/Music/incoming/albums/...
  • 单曲:/mnt/dropbox/Music/incoming/singles/...
  1. beets 清洗
# 专辑批量导入
beet import -q -A /mnt/dropbox/Music/incoming/albums

# 单曲导入
beet import -s -q /mnt/dropbox/Music/incoming/singles

  1. Navidrome 播放
  • Docker 映射 /mnt/dropbox/Music/library:/music:ro
  • 浏览器 / 客户端访问 Navidrome
  1. 长远维护
  • 偶尔查看:

/var/log/rclone-dropbox.log(挂载情况)

docker compose logs navidrome(播放服务情况)

  • 如需升级:

rclone / beets 用 apt 升级

Navidrome:

cd /srv/navidrome
docker compose pull
docker compose up -d

这份文档已经把你一路折腾过的东西、所有关键命令和坑基本都装进去了,一个“什么都不懂的新手”只要照着从上往下抄,正常是能搭起来一套跟你现在一样的环境的。

你后面要再补「安全 / HTTPS / 反代」之类的章节,可以在这个基础上继续加一节“对外发布与安全加固”。

0

评论区