树莓派家庭影院(一):Docker 自动化电影下载管线(Radarr + Jackett + qBittorrent + Bazarr)
在树莓派上用 Docker 部署 Radarr、Jackett、qBittorrent、Bazarr 和 ChineseSubFinder,实现指定电影自动下载到 Samba 共享目录,并自动补充中文或英文字幕。
本系列共三篇:第一篇(本文)搭建“搜索 → 下载 → 字幕”的自动化电影下载管线;第二篇接入点播、播放、剧集、密码管理和统一入口;第三篇让电视上的 Kodi 使用 Jellyfin 媒体库与服务端字幕。
⚠️ 安全警告:本文会公开本实验环境的登录地址、账号、密码和 API Key。这些凭证在发布后即视为已泄露,请勿直接用于生产环境或长期暴露的服务。建议读者在复现时替换为自己的强密码,并在公网访问时加 VPN/反向代理 + HTTPS。(第二篇引入 Vaultwarden,正是为了终结这种“凭证写进文档”的管理方式。)
1. 目标
让树莓派变成一个可以通过网页操作的“电影下载站”:
- 打开网页搜索电影。
- 选择想下载的版本(优先 4K)。
- 自动通过 BT 下载到 Samba 共享目录
/share/Movies。 - 自动下载字幕:优先使用字幕源提供的原版中英双语字幕,其次使用单中文或单英文字幕。
2. 最终架构
flowchart LR
User[浏览器] -->|搜索/添加电影| Radarr[Radarr 7878]
Radarr -->|查询种子| Jackett[Jackett 9117]
Jackett -->|Torznab| TPB[The Pirate Bay]
Jackett -->|Torznab| RARBG[TheRARBG]
Jackett -->|Torznab| TP2[TorrentProject2]
Radarr -->|下发任务| qBittorrent[qBittorrent 8085]
qBittorrent -->|下载中| Downloads[(/share/Downloads)]
Radarr -->|硬链接/整理| Movies[(/share/Movies)]
Bazarr[Bazarr 6767] -->|同步片库| Radarr
Bazarr -->|下载字幕| OpenSubtitles[OpenSubtitles.com]
Bazarr -->|中文字幕| Zimuku[字幕库/射手网等]
Bazarr -->|下载原版中文/英文字幕| Movies
Bazarr -->|下载原版中文/英文字幕| Series[(/share/Video/Series)]
CSF[ChineseSubFinder 19035] -->|定时扫描| Movies
CSF -->|定时扫描| Series
CSF -->|下载原版中文/双语字幕| Movies
CSF -->|下载原版中文/双语字幕| Series
subgraph 树莓派
Radarr
Jackett
qBittorrent
Bazarr
CSF
Downloads
Movies
Series
end
2.1 各服务职责
Radarr:电影收藏管理器(*arr 家族中的一员)。它维护一份“想看的电影”列表,自动追踪影片上映信息,决定应该下载哪个版本,并把下载任务发送给下载客户端。下载完成后,它还会把文件整理/重命名到媒体库目录。
Jackett:索引器聚合器。BT 站点(如 The Pirate Bay)通常没有统一、机器可读的 API,Jackett 把它们封装成标准的 Torznab API,让 Radarr 可以用同一种方式查询多个站点的种子。
qBittorrent:BT 下载客户端,负责实际的 P2P 下载。Radarr 通过 qBittorrent 的 WebUI API 添加种子、监控进度;下载完成后把文件落到 /share/Downloads,再由 Radarr 硬链接/移动到 /share/Movies。
Bazarr:字幕管理器。它定期向 Radarr 索取电影库清单,比对哪些影片缺少指定语言的字幕,然后到 OpenSubtitles 等字幕站下载原版字幕。语言 Profile 以中文为 cutoff,找到中文(其中可能本身就是中英双语)后停止;没有中文时保留英文兜底。
ChineseSubFinder(可选补充):专攻中文字幕的工具,会从中文来源匹配原版中文或中英双语字幕。它按计划任务直接扫描电影和剧集目录,和 Bazarr 并行工作;候选中优先选择双语字幕,其次选择中文字幕。当前 latest 镜像带一个轻量 WebUI,但只能查看媒体列表、控制系统状态和任务日志,不能像 Bazarr 那样逐个候选手动挑选字幕。
2.2 工作流时序
sequenceDiagram
actor U as 用户
participant R as Radarr
participant J as Jackett
participant Q as qBittorrent
participant B as Bazarr
participant OS as OpenSubtitles
participant Z as 字幕库/射手网
participant CSF as ChineseSubFinder
participant S as /share/Movies
U->>R: 搜索并添加电影
R->>J: 查询 Torznab: 有这部电影的种子吗?
J-->>R: 返回种子列表
R->>R: 按画质优先级挑选最佳种子
R->>Q: 添加下载任务
Q->>Q: P2P 下载
Q-->>R: 下载完成
R->>S: 硬链接/移动到媒体库
R-->>B: Webhook 通知电影下载/移动完成
B->>R: 同步电影库(兜底轮询)
B->>B: 按语言 Profile 检查字幕(zh 优先、en 兜底)
B->>Z: 优先搜索原版中文字幕
Z-->>B: 返回 .zh(.hi).srt(可能本身是双语)
B->>OS: 找不到中文时搜索英文字幕
OS-->>B: 返回 .en(.hi).srt
B->>S: 原样写入下载到的字幕
CSF->>S: 扫描并补充原版中文/双语字幕
时序说明:
- 用户在 Radarr 搜索并添加电影。
- Radarr 通过 Jackett 的 Torznab 接口查询索引站点。
- Jackett 返回候选种子,Radarr 根据画质配置挑选最优版本。
- Radarr 把种子推给 qBittorrent,qBittorrent 开始 P2P 下载。
- 下载完成后,Radarr 把文件整理到
/share/Movies。 - Radarr 通过 Webhook 主动推送事件给 Bazarr(电影下载/移动完成);同时 Bazarr 也会定期轮询 Radarr 的电影库做兜底同步。
- Bazarr 发现缺字幕后按
zh → en搜索,zh是 cutoff:优先采用字幕站给出的原版中文字幕,找不到时用英文兜底。原版.zh.srt可能是双语,也可能只有中文,Bazarr 不分析正文内容。 - Bazarr 原样保存下载结果,不执行自定义 Post-Processing,也不生成
.zh+en.srt。 - (可选)ChineseSubFinder 每 6 小时扫描一次
/share/Movies与/share/Video/Series,从中文来源补充原版中文或中英双语字幕。
2.3 为什么这些名字都这么奇怪?
这套工具的名字看着像黑话,其实大多是有意为之的双关或谐音梗。
Radarr 来自 Radar(雷达)+ r,寓意“扫描发现电影”。同属 *arr 家族的还有:
| 工具 | 用途 | 名字梗 |
|---|---|---|
| Sonarr | 电视剧 | Sonar(声纳),像雷达一样扫描剧集 |
| Lidarr | 音乐 | Lid(盖子/眼睑),比较冷门的双关 |
| Readarr | 电子书/有声书 | Read(阅读)直接加 r |
| Bazarr | 字幕 | Bazaar(集市),字幕来自五湖四海 |
| Prowlarr | 索引器统一管理 | Prowl( prowling,四处搜寻) |
| Radarr | 电影 | Radar(雷达) |
Jackett 则像是一件 jacket(夹克),给形形色色、接口各异的 BT 站点套上一层统一外套,让它们都能以 Torznab 协议对外服务。
qBittorrent 里的 q 指它基于 Qt 图形框架开发;Bittorrent 就是 P2P 下载协议本身。
Torznab 是 Torrent + Newznab 的拼接。Newznab 是 Usenet 时代的 API 标准,Torznab 把它借用到 BT 世界,所以名字听起来像两种不同技术强行结婚生的孩子。
简单记法:
- 管电影的带“雷达”——Radarr
- 管字幕的像“集市”——Bazarr
- Jackett 是 BT 站的统一“外套”
- qBittorrent 就是实际干下载活的 BT 客户端
3. 环境信息
- 设备:Raspberry Pi,ARM64,8 GB RAM
- OS:Linux 6.12.93(6.12.93+rpt-rpi-2712)
- Docker:29.5.3,Docker Compose v5.1.4
- 服务版本(2026-08-05 升级至最新镜像):Radarr 6.3.0.10514、Jackett v0.24.2327、qBittorrent v5.2.3、Bazarr v1.6.0;ChineseSubFinder 镜像自 2023-12 后无更新
- 已有服务:V2Ray(HTTP 代理
127.0.0.1:10809)、Portainer、AdGuard Home - Samba 共享:
/share,局域网地址192.168.1.7 - Docker 默认网桥网关:
172.18.0.1,容器内通过172.18.0.1:10809走宿主机 V2Ray 代理
4. 部署步骤
4.1 创建目录
1
2
3
4
5
6
mkdir -p /share/Movies /share/Downloads
mkdir -p /home/pi/docker/qbittorrent/config
mkdir -p /home/pi/docker/radarr/config
mkdir -p /home/pi/docker/jackett/config
mkdir -p /home/pi/docker/bazarr/config/scripts
mkdir -p /home/pi/docker/chinesesubfinder/config
4.2 Docker Compose
在 /home/pi/docker/compose.yml 里追加以下服务(与已有的 v2ray 等共存):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
qbittorrent:
image: linuxserver/qbittorrent:latest
container_name: qbittorrent
environment:
- PUID=1000
- PGID=100
- TZ=Asia/Shanghai
- WEBUI_PORT=8085
volumes:
- /home/pi/docker/qbittorrent/config:/config
- /share/Downloads:/downloads
ports:
- "8085:8085"
- "6881:6881"
- "6881:6881/udp"
restart: unless-stopped
radarr:
image: linuxserver/radarr:latest
container_name: radarr
environment:
- PUID=1000
- PGID=100
- TZ=Asia/Shanghai
- HTTP_PROXY=http://172.18.0.1:10809
- HTTPS_PROXY=http://172.18.0.1:10809
- NO_PROXY=localhost,127.0.0.1,qbittorrent,radarr,jackett,bazarr
volumes:
- /home/pi/docker/radarr/config:/config
- /share/Movies:/movies # ⚠️ 错误示范:与下一行是两个独立 bind mount,会导致硬链接失败、空间翻倍,正确写法见第 10 节
- /share/Downloads:/downloads # ⚠️ 错误示范:应改为单一 /share 挂载,见第 10 节
ports:
- "7878:7878"
restart: unless-stopped
jackett:
image: linuxserver/jackett:latest
container_name: jackett
environment:
- PUID=1000
- PGID=100
- TZ=Asia/Shanghai
- HTTP_PROXY=http://172.18.0.1:10809
- HTTPS_PROXY=http://172.18.0.1:10809
- NO_PROXY=localhost,127.0.0.1,qbittorrent,radarr,jackett,bazarr,yts.gg,movies-api.accel.li,yts.mx
volumes:
- /home/pi/docker/jackett/config:/config
ports:
- "9117:9117"
restart: unless-stopped
bazarr:
image: linuxserver/bazarr:latest
container_name: bazarr
environment:
- PUID=1000
- PGID=100
- TZ=Asia/Shanghai
- HTTP_PROXY=http://172.18.0.1:10809
- HTTPS_PROXY=http://172.18.0.1:10809
# 国内字幕站必须直连,走代理会 SSL 超时,见第 11.1 节
- NO_PROXY=localhost,127.0.0.1,qbittorrent,radarr,jackett,bazarr,yts.gg,movies-api.accel.li,yts.mx,zimuku.org,shooter.cn,subf2m.com,subhd.tv,a4k.net,assrt.net,subtitle.best
volumes:
- /home/pi/docker/bazarr/config:/config
- /share/Movies:/movies
- /share/Downloads:/downloads
ports:
- "6767:6767"
restart: unless-stopped
chinesesubfinder:
image: allanpk716/chinesesubfinder:latest
container_name: chinesesubfinder
environment:
- PUID=1000
- PGID=100
- TZ=Asia/Shanghai
volumes:
- /home/pi/docker/chinesesubfinder/config:/config
- /share/Movies:/media
- /share/Video/Series:/series
ports:
- "19035:19035"
restart: unless-stopped
注意:
- qBittorrent 的 WebUI 端口改成
8085,因为宿主机8080已被其他服务占用。 - Radarr/Jackett/Bazarr 不直接用内置代理,而是通过容器环境变量走 V2Ray,这样更稳定。
- 容器下载目录统一挂到
/share/Downloads,电影最终目录是/share/Movies。但 radarr 不能像上面那样把两者挂成两个独立 volume——这会让导入时的硬链接悄悄退化为复制,空间翻倍(2026-07-18 踩坑实录,排查与正确写法见第 10 节)。 - ChineseSubFinder 将电影和剧集分开挂载:容器内
/media对应宿主机/share/Movies,/series对应/share/Video/Series。
4.3 启动
1
2
cd /home/pi/docker
docker compose up -d qbittorrent radarr jackett bazarr chinesesubfinder
5. 各服务配置
5.1 qBittorrent
- 地址:
http://192.168.1.7:8085 - 账号:
admin - 密码:
pi123456
Radarr 里添加下载客户端时,主机填 qbittorrent,端口填 8085(因为容器内 qBittorrent 的 WebUI 监听的是 8085)。
5.2 Jackett
- 地址:
http://192.168.1.7:9117 - API Key:
1gh53xjyx9l1djek69yas386y7wtcjoc
配置步骤:
- 进入 Jackett → Add indexer。
- 添加以下公开索引器(推荐至少加 TPB):
- The Pirate Bay
- TheRARBG
- TorrentProject2
- 在 Jackett 设置里的 Proxy 先留空,靠容器环境变量
HTTP_PROXY/HTTPS_PROXY走代理。 - 对每个 indexer 复制其 Torznab feed URL,例如:
- TPB:
http://192.168.1.7:9117/api/v2.0/indexers/thepiratebay/results/torznab/ - TheRARBG:
http://192.168.1.7:9117/api/v2.0/indexers/therarbg/results/torznab/ - TorrentProject2:
http://192.168.1.7:9117/api/v2.0/indexers/torrentproject2/results/torznab/
- TPB:
踩坑:Jackett 内置代理填
127.0.0.1:12345会失败,因为容器内127.0.0.1不是宿主机。改成容器环境变量代理后正常。
5.3 Radarr
- 地址:
http://192.168.1.7:7878 - API Key:
be67ae6612cc4061a7a2335723893305
配置步骤:
- Settings → Media Management → Root Folders:添加
/movies。 - Settings → Download Clients → Add → qBittorrent:
- Host:
qbittorrent - Port:
8085 - Username:
admin - Password:
pi123456
- Host:
- Settings → Indexers → Add → Torznab:把 Jackett 里每个 indexer 都单独加一次:
- URL:对应 indexer 的 Torznab URL
- API Key:Jackett 的 API Key
1gh53xjyx9l1djek69yas386y7wtcjoc - 当前已添加:TPB、TheRARBG、TorrentProject2
- Profiles → 编辑 Ultra-HD:把画质优先级调整为:
- Remux-2160p
- Bluray-2160p
- WEB-DL-2160p
- 禁用 HDTV-2160p,避免下载到低质量 4K。
Radarr 是怎么决定下载哪个版本的
Radarr 做决策时主要考虑三个维度:可用性、画质 和 索引器来源。
可用性:Minimum Availability
- 路径:添加/编辑电影时的 Minimum Availability,或在 Settings → Profiles 里设置默认值。
- 它决定电影到什么阶段才允许开始搜索:
- Announced:刚加入 Radarr 就搜索,通常没资源;
- In Cinemas:院线上映后搜索,可能下到枪版;
- Released:蓝光/流媒体正式发行后搜索,资源最稳,推荐。
- 建议保持 Released,避免下到预告片或枪版。
画质:Quality Profile
- 路径:Settings → Profiles
- 每个 profile 是一组画质的排序列表,Radarr 会优先选择排在前面的画质。
- 当前预置 profile 有:Any、SD、HD-720p、HD-1080p、Ultra-HD、HD - 720p/1080p。
- 想优先 4K,就给电影指定 Ultra-HD profile。
- 如果 UI 支持设置 Default Quality Profile,可以把它设成 Ultra-HD;否则每次添加电影时手动选。
- 已经下载成 1080p 的电影,再改成 Ultra-HD 后,Radarr 会显示 "Cutoff Unmet",但不会自动重新搜索。你需要手动进入电影页面点 Search,或者等 RSS 监控刷到新的 4K 种子。
停止升级:Upgrade Until / Cutoff
- 在 Quality Profile 里还有一个 Upgrade Until(也叫 Cutoff)设置。
- 它表示“达到这个画质后就不再继续升级”。
- 例如 Ultra-HD profile 里 Upgrade Until 设为
Remux-2160p,那么一旦下载到 Remux-2160p,Radarr 就会停止,不会再下载其他 4K 版本。 - 如果看到
Release Rejected: Existing file meets cutoff: Remux-2160p,说明当前文件已经满足 cutoff,这是正常行为。
同一画质内继续升级:Custom Format Cutoff Score
- 路径:Settings → Custom Formats 定义规则,Settings → Profiles 里设置 Upgrade Until Score。
- Custom Formats 让你给发布组、来源、音轨等属性打分。比如
SPHD+50、Atmos+20、HMAX-30。 - Upgrade Until Score(即 Custom Format Cutoff Score)是“满意分数”。
- Radarr 会升级,直到同时满足:画质达到 Upgrade Until 且 Custom Format Score 达到 Upgrade Until Score。
- 不折腾的话保持
Upgrade Until Score = 0,只按画质 cutoff 停止即可。
索引器来源:Indexer Priority
- 路径:Settings → Indexers
- 每个 indexer 有一个 Priority 数字,越小越优先。
- 当前配置:
| Indexer | Priority |
|---|---|
| TPB | 5 |
| TheRARBG | 10 |
| TorrentProject2 | 22 |
- 同一部电影、同一画质下,Radarr 会优先尝试 TPB,没有结果再 fallback 到 TheRARBG,最后 TorrentProject2。
综合决策顺序
- 电影必须达到 Minimum Availability 才进入搜索池;
- 按 Quality Profile 选最高可用画质,但不超过 Upgrade Until;
- 如果启用了 Custom Formats,同一画质内继续升级直到 Upgrade Until Score 满足;
- 在该画质下按 Indexer Priority 选优先级最高的 indexer;
- 同一 indexer 多个结果中,优先选做种数多的种子。
资源来源类型详解:从枪版到原盘
Radarr 的画质体系是来源类型 × 分辨率的二维组合,比如 WEB-1080p 表示“流媒体源 + 1080p”。Quality 列表里的所有类别按来源的演进顺序可以分成几组,下面逐一说明。
影院流出类(枪版,不推荐)
| 缩写 | 全称 | 含义 | 质量 | 建议 |
|---|---|---|---|---|
| CAM | Camera | 摄像机在影院偷拍,画面抖、常有人头影子和观众笑声 | 最差 | 禁用 |
| TELESYNC(TS) | Telesync | 也是影院偷拍,但接了影院的外接音源(如无障碍音频孔),声音比 CAM 干净 | 差 | 禁用 |
| TELECINE(TC) | Telecine | 把影院放映用的胶片拷贝通过胶转磁设备转成数字文件 | 比 CAM/TS 好,但仍属枪版 | 禁用 |
| WORKPRINT | Workprint | 未完成剪辑的工作样片流出,可能缺特效、音轨未混音、有多余片段 | 不稳定 | 禁用 |
新片刚上映时往往只有这类源,比如《功夫女足》的 TC国语v2 就是 Telecine 源;v2 是发布组修正后的第二版(修音画不同步、补缺失片段等),不代表画质档次提升。这就是 Minimum Availability 推荐保持 Released 的原因——等正式发行再动手,自动避开枪版。
提前泄露 / 样片类(不推荐)
| 缩写 | 全称 | 含义 | 质量 | 建议 |
|---|---|---|---|---|
| DVDSCR(DVD Screener) | DVD Screener | 片方送审、评奖、送媒体用的 DVD 样片流出,画面可能带“仅供评审”水印和时间码 | 接近 DVD 正版 | 禁用 |
| REGIONAL | Regional(常见为 R5) | 某些地区(如俄罗斯 R5 区)DVD 提前于全球发行,流出后被转录 | 接近 DVD | 禁用 |
这两类是在正式零售版之前泄露的“正版样片”,画质尚可,但有水印、缺内容等风险。
DVD / 标清时代(收藏价值有限)
| 缩写 | 全称 | 含义 | 建议 |
|---|---|---|---|
| DVD | DVD | DVD 光盘的直接转录 | 老片没有高清源时可接受 |
| DVD-R | DVD-R | 完整 DVD 光盘镜像(含菜单),体积大、播放麻烦 | 不推荐 |
| SDTV | Standard Definition TV | 标清电视信号采集 | 老片兜底 |
电视采集类(HDTV)
| 缩写 | 全称 | 含义 | 质量 | 建议 |
|---|---|---|---|---|
| HDTV | High Definition TV | 从电视广播信号采集,可能带台标、插广告、码率受限 | 不如 WEB / 蓝光 | 有 WEB / 蓝光源就不勾 |
HDTV 有 720p / 1080p / 2160p 各档。它的唯一价值是时效——电视剧和电视节目的 HDTV 源往往出得最快,对电影来说通常很快被 WEB / 蓝光取代,所以本文 Ultra-HD profile 里禁用了 HDTV-2160p。
流媒体类(WEB,推荐 WEB-DL)
| 缩写 | 全称 | 含义 | 质量 | 建议 |
|---|---|---|---|---|
| WEB-DL | Web Download | 从流媒体平台(Netflix、Disney+、Apple TV 等)服务器直接下载的原始视频流,不重编码 | 和平台用户看到的完全一致 | 推荐 |
| WEBRip | Web Rip | 对 WEB-DL 二次压缩,或用录屏 / 采集方式转录 | 有一次编码损失 | 能选 DL 就不要 Rip |
注意 Radarr 里 WEB 2160p 是一个分组,里面同时包含 WEBRip-2160p 和 WEBDL-2160p 两个子项,组内排上面的优先。只标 WEB、没写 DL 还是 Rip 的资源,一般按 WEB-DL 档处理。
同分辨率下优先级:WEB-DL > WEBRip > HDTV。
蓝光家族(终极收藏)
| 缩写 | 全称 | 含义 | 体积 | 建议 |
|---|---|---|---|---|
| Bluray | Blu-ray Encode | 蓝光盘重编码压缩版,砍掉多余码率 | 适中(1080p 约 2–10 GB) | 推荐,性价比最高 |
| Remux | Remux(重新封装) | 蓝光原盘的视频流不重编码直接抽出,只去掉多余音轨 / 字幕 / 花絮后重新封装成 mkv | 大(1080p 约 20–40 GB,2160p 更大) | 画质党 / 收藏推荐 |
| BR-DISK | Blu-ray Disk | 完整蓝光原盘镜像(ISO 或 BDMV 文件夹),含菜单、花絮、全部音轨 | 最大(25–100 GB) | 一般不用,播放需挂载 |
| Raw-HD | Raw HD | 未经压缩的原始高清采集流 | 极大 | 基本不用 |
同分辨率下:Remux > Bluray > WEB-DL。
无法识别
| 缩写 | 含义 | 建议 |
|---|---|---|
| Unknown | Radarr 无法从文件名解析出来源类型 | 禁用,避免下到乱命名的垃圾源 |
推荐勾选方案
以“4K 优先、1080p 兜底”为例:
- ✅ 勾:
Remux-2160p、Bluray-2160p、WEB 2160p、Remux-1080p、Bluray-1080p、WEB 1080p - ❌ 不勾:CAM / TELESYNC / TELECINE / WORKPRINT(枪版)、DVDSCR / REGIONAL(样片泄露)、HDTV 全系(有更好源)、DVD / DVD-R / SDTV(标清)、BR-DISK / Raw-HD(原盘)、Unknown
资源名常见后缀补充
v2/v3:发布组修正版,修 bug 但不提升画质档次;PROPER:发布组认为别家的版本有问题,自己重发一个“正确版”;REPACK:同组修正自己之前发错的版本;x264/x265(HEVC):视频编码格式,x265 同画质体积更小,但需要播放设备支持解码。
5.4 Bazarr
- 地址:
http://192.168.1.7:6767 - API Key:
db657bd7209430ebc1e25832b24c9d1b
配置步骤:
- Settings → Languages → Add New Profile:
- Name:
原版字幕:中文优先,英文兜底 - Language items 按
zh → en排列,使用 alpha2 code(不要写“中文”“英文”,否则会报ValueError: None is not a valid language)。 - Cutoff 选择
zh。它是整条管线的“毕业线”:找到中文后才算满足,影片彻底退出 Wanted 清单;中文缺席期间会先下载英文兜底,但英文不满足 cutoff——条目会一直留在 Wanted 里,由每 6 小时的自动搜索持续重试中文,哪天中文字幕发布了就会自动补上。中文补上后英文文件保留,两条字幕共存,播放端随意切换。
- Name:
- Settings → Providers:启用以下字幕源,覆盖英文和中文:
- OpenSubtitles.com:英文/多语言字幕较全,需要到 OpenSubtitles.com 注册免费账号并填入用户名/密码。免费账号每天下载配额约 20 条,且默认匹配分门槛会挡掉部分中文字幕,见第 11.3 节。
- subf2m、subx、shooter(射手网):中文字幕源,国内资源较多。注意这些国内站点必须直连,不能走代理,见第 11.1 节。
zimuku(字幕库):因反爬验证码问题已禁用,见第 11.2 节。
- Settings → Languages → Default Settings:
- Movies 和 Series 都启用默认 Profile,选择
原版字幕:中文优先,英文兜底。 - 对已有电影和剧集分别执行 Mass Edit,把同一 Profile 批量套用到全部条目。
- Movies 和 Series 都启用默认 Profile,选择
- Settings → Radarr / Sonarr:
- IP:
radarr - Port:
7878 - API Key:Radarr 的 API Key
be67ae6612cc4061a7a2335723893305 - Sonarr 同理使用
sonarr:8989和 Sonarr 的 API Key;启用后 Bazarr 会同时管理电影与剧集字幕。
- IP:
- Settings → Subtitles → Post-Processing:关闭
Use Custom Post-Processing,Post-Processing Command 留空。
Bazarr 只知道字幕的语言标签,无法判断一个 zh 文件的正文是“中英双语”还是“只有中文”。因此这里不做内容合并:中文站返回原版双语字幕时直接使用;否则接受单中文字幕,实在没有中文时再用英文。.hi 表示 Hearing Impaired(听障版),如果不需要对白之外的音效描述,可在 Profile 中取消 HI。
手动下载与多字幕共存
除了自动搜索,Bazarr 也支持手动干预:
- 手动搜索:在单部电影或单集的页面里使用手动搜索,会列出所有字幕源的候选及各自得分,且不受最低匹配分限制,可以任意挑选下载(适合给某一部单独换更好的版本);也可以直接上传本地字幕文件,Bazarr 会按规范重命名并归档到对应影片目录。
- 多条字幕按文件名共存:外挂字幕按语言标签命名,文件名不冲突就共存——不同语言(
.en.srt+.zh.srt)、同语言不同格式(.zh.srt+.zh.ass)、是否听障版(.zh.srt+.zh.hi.srt)都可以同时存在;只有完全同名才会被新下载的覆盖。播放端(Jellyfin/Kodi)会把这些文件识别为独立字幕轨,观看时可随意切换。
Bazarr 与 Radarr 如何通信
两者同时存在拉取和推送两种机制:
- Bazarr 主动拉取:Bazarr 每隔一段时间(默认 60 分钟)调用 Radarr 的
/api/v3/movie接口,获取完整电影库清单,判断哪些电影缺字幕。 - Radarr 主动推送:在 Radarr 的 Settings → Connect → Bazarr 里配置 Webhook 后,Radarr 会在电影下载完成、重命名、添加/删除等事件发生时,立即通知 Bazarr 去检查该电影的字幕。
webhook 让字幕下载更及时,定期拉取则负责兜底同步。两个都配好是最佳状态。
原版字幕的落盘形态
以电影 Inception (2010).mkv 为例,Bazarr 只保存字幕源返回的原版文件:
1
2
3
Inception (2010).mkv
Inception (2010).zh.srt # 优先;内容可能是原版双语,也可能只有中文
Inception (2010).en.srt # 找不到中文时的英文兜底
媒体目录不再生成 .zh+en.srt。播放器优先选择 zh;如果这份原版中文字幕本身包含中英文,就显示双语,否则显示单中文。没有 zh 时再选择 en。
5.5 ChineseSubFinder(可选,补充原版中文/双语字幕)
如果希望提高字幕源原本就是中英双语的概率,可以额外部署 ChineseSubFinder。它专门从迅雷字幕、射手网等中文来源匹配原版中文或双语字幕,比 Bazarr 更聚焦中文来源,但同样不负责把两份字幕重新合成。Zimuku(字幕库)则作为 Bazarr Provider 接入,不必在 ChineseSubFinder 中重复配置。
Docker Compose 追加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
chinesesubfinder:
image: allanpk716/chinesesubfinder:latest
container_name: chinesesubfinder
environment:
- PUID=1000
- PGID=100
- TZ=Asia/Shanghai
volumes:
- /home/pi/docker/chinesesubfinder/config:/config
- /share/Movies:/media
- /share/Video/Series:/series
ports:
- "19035:19035"
restart: unless-stopped
当前版本把主要设置保存在 /home/pi/docker/chinesesubfinder/config/ChineseSubFinderSettings.json。通常应在 WebUI 中修改;其中与扫描范围直接相关的结构如下:
1
2
3
4
5
6
7
8
9
10
11
{
"common_settings": {
"scan_interval": "@every 6h",
"movie_paths": ["/media"],
"series_paths": ["/series"]
},
"advanced_settings": {
"sub_type_priority": 0,
"save_multi_sub": false
}
}
sub_type_priority: 0 表示字幕文件格式自动选择,不是语言优先级。ChineseSubFinder 的候选选择逻辑本身就会优先中英双语,再退到中文字幕;save_multi_sub: false 则只保留选出的结果,不把每个网站的候选都留在媒体目录。
启动后访问 http://192.168.1.7:19035:
- 账号:
admin - 密码:
admin
关于这个版本的 WebUI
当前 allanpk716/chinesesubfinder:latest 镜像(最后一次更新为 2023-12-01)带的是一个轻量 WebUI,功能有限:
- ✅ 可以查看电影列表和封面;
- ✅ 可以控制系统状态、启动/停止守护进程;
- ✅ 可以查看任务日志;
- ❌ 电影卡片点不开详情页;
- ❌ 不能在里面手动搜索或上传单部电影字幕。
这意味着你不能像 Bazarr 那样在 ChineseSubFinder 的网页里点进电影选字幕。它只能作为一个后台自动扫描下载的兜底工具。
手动指定字幕的方法
既然 WebUI 不能操作,手动指定字幕只能走文件系统:
- 把字幕文件放到电影同目录,文件名和主视频文件同名:
1 2
/share/Movies/Pressure (2026)/Pressure.2026.1080p...mp4 /share/Movies/Pressure (2026)/Pressure.2026.1080p...chs.ass
- 回到 ChineseSubFinder WebUI 刷新媒体库,或等待每 6 小时一次的计划任务;当前配置不会因为重启容器就立刻执行字幕扫描。
- 看日志确认它识别到已有字幕:
1
docker logs -f chinesesubfinder
必须有的 .nfo 元数据
ChineseSubFinder 扫描电影时需要目录里有 .nfo 元数据文件(通常由 Radarr 生成)。如果缺少 .nfo,日志会报:
1
no metadata file, movie.xml or *.nfo
此时 WebUI 里可能连电影封面都显示不出来,或者显示为无法点击的空白卡片。
解决办法:在 Radarr 里开启 metadata 生成:
- Radarr → Settings → Metadata;
- 启用 Kodi (XBMC) 或 Emby,勾选
Movie Metadata/.nfo; - 对已有电影执行 Refresh & Scan 或 Organize,让 Radarr 生成
.nfo; - 回到 ChineseSubFinder WebUI 刷新媒体库,字幕下载则等待下一次计划任务。
版本状态
allanpk716/chinesesubfinder:latest 目前就已经是最新版,不要再指望更新它能获得完整 WebUI。作者已经明确转向 Lite 路线,全功能版本不再维护。如果你确实需要完整的电影详情管理界面,只能换用其他工具(例如主要依赖 Bazarr)。
5.6 字幕从下载到播放的完整链路
Bazarr 与 ChineseSubFinder 都能写字幕,但两者的触发方式不同。Radarr 和 Sonarr 在媒体新增、下载完成、升级或重命名时通过 Webhook 通知 Bazarr;Bazarr 还会定期同步片库并搜索 Wanted 队列。ChineseSubFinder 不接收这类通知,而是每 6 小时直接扫描电影与剧集目录。
sequenceDiagram
participant A as Radarr / Sonarr
participant B as Bazarr
participant C as ChineseSubFinder
participant M as 电影 / 剧集目录
participant J as Jellyfin
A->>M: 导入视频文件
A-->>B: Webhook 通知媒体变化
B->>B: 检查内置与外挂字幕
B->>M: 从 Zimuku 等来源写入原版 zh / en 字幕
C->>M: 每 6 小时扫描媒体目录
C->>M: 优先写入原版中英双语,其次中文字幕
J->>M: 实时扫描视频和同名外挂字幕
J-->>J: 合并展示内置与外挂字幕轨
Bazarr 当前启用了 OpenSubtitles.com、射手网、Subf2m、SubX 和 Embedded Subtitles(Zimuku 因反爬问题已禁用,见第 11.2 节)。统一 Profile 按 zh → en 搜索,并把 zh 设为 cutoff:只要找到中文就视为满足,没有中文时才用英文兜底。由于字幕站通常把中英双语与单中文字幕都标成 zh,Bazarr 无法仅凭语言标签判断正文是不是双语;ChineseSubFinder 则在自己的候选中优先挑选原版双语字幕。
两套工具下载的网络字幕最终都是外挂字幕,与视频放在同一个目录、使用相同主文件名:
1
2
3
4
5
6
7
8
9
/share/Movies/Movie Name (2025)/
├── Movie Name (2025).mkv
├── Movie Name (2025).zh.srt
└── Movie Name (2025).en.srt
/share/Video/Series/Series Name/Season 01/
├── Series Name S01E01.mkv
├── Series Name S01E01.zh.ass
└── Series Name S01E01.en.srt
字幕在播放端分为三类:
| 类型 | 存放位置 | 能否选择或关闭 |
|---|---|---|
| 内置字幕 | MKV、MP4 等视频容器内部的字幕流 | 可以 |
| 外挂字幕 | 视频旁边独立的 .srt、.ass 等文件 | 可以 |
| 硬字幕 | 已经压进视频画面 | 不可以 |
视频自身携带的十几种语言仍然是内置字幕;Bazarr 或 ChineseSubFinder 下载到旁边的文件则是外挂字幕。Jellyfin 会读取视频容器中的字幕流,也会按照官方命名规则识别同名外挂字幕,然后把两者一起交给网页端、手机或 Kodi 选择。Jellyfin 对媒体目录使用只读挂载也不影响这个过程:字幕由前两套工具写入,Jellyfin 只负责扫描和播放。
Bazarr 与 ChineseSubFinder 彼此没有任务协调机制,理论上可能同时处理同一媒体。通常 Bazarr 发现已经存在满足 Profile 的 zh 后便不会继续把它列为缺失;若两者先后写入同一个 .zh.srt,最终保留的是最后一次写入的文件。当前系统不再运行任何自定义合并脚本,也不会生成 .zh+en.srt。
6. 下载测试:《速度与激情 1》4K
- 在 Radarr 搜索
The Fast and the Furious(2001)。 - 选择 Ultra-HD 质量配置。
- Radarr 通过 Jackett/TPB 找到 4K UHD BluRay 版本,约 18.67 GB。
- 发送给 qBittorrent 开始下载。
- 由于种子数只有 1-2,速度较慢,预计需要几天。
- 下载完成后 Radarr 自动硬链接/移动到
/share/Movies。
如果速度太慢,可以随时在 Radarr 里把画质改成 1080p 重新搜索。
7. 访问地址与凭证汇总
| 服务 | URL | 账号 | 密码 / API Key |
|---|---|---|---|
| Radarr | http://192.168.1.7:7878 | 无 | be67ae6612cc4061a7a2335723893305 |
| Jackett | http://192.168.1.7:9117 | 无 | 1gh53xjyx9l1djek69yas386y7wtcjoc |
| qBittorrent | http://192.168.1.7:8085 | admin | pi123456 |
| Bazarr | http://192.168.1.7:6767 | 无 | db657bd7209430ebc1e25832b24c9d1b |
| ChineseSubFinder | http://192.168.1.7:19035 | admin | admin |
8. 踩坑与备注
- 代理问题:Jackett 内置代理在容器里对
127.0.0.1解析错误,改用容器环境变量HTTP_PROXY=http://172.18.0.1:10809解决。 - qBittorrent 端口:默认
8080被占用,改为8085,Radarr 里也要对应填8085。 - Radarr 4K 画质:需手动调整
Ultra-HDprofile 优先级并禁用HDTV-2160p。 - Bazarr 语言 code:语言 profile 里必须用
en/zh,不能用中文名。 - 字幕源:OpenSubtitles.com 需要注册并填入账号密码,否则字幕下载会全部失败;ChineseSubFinder 账号密码为
admin/admin。 - ChineseSubFinder 需要
.nfo元数据:如果日志报no metadata file, movie.xml or *.nfo,WebUI 的电影卡片会点不开或显示异常。需要在 Radarr 的 Settings → Metadata 里启用.nfo生成,然后刷新/整理已有电影。 .hi后缀字幕:Bazarr 下载的字幕可能是.en.hi.srt/.zh.hi.srt(Hearing Impaired,听障版)。如果不需要对白之外的音效描述,可在语言 Profile 中取消勾选Hearing Impaired。- ChineseSubFinder 版本现状:
allanpk716/chinesesubfinder:latest目前(2023-12-01 后未再更新)已经是最新版,且作者已转向 Lite 路线,更新也不会带来能点进电影详情页的完整 WebUI。需要手动管理字幕时,建议主要使用 Bazarr。 - 安全:以上凭证仅用于本实验,发布本文后应视为已泄露,建议尽快修改。
- 硬链接从未生效(重点):
/movies和/downloads两个独立 bind mount 导致跨挂载link(2)返回 EXDEV,Radarr 静默退化为复制,所有电影占双份空间。排查与修复详见第 10 节。
9. 后续可优化(多数已在第二篇落地)
本文发布时列的优化方向,两条主线已经在第二篇落地:
- HTTPS + 反向代理:第二篇第 4 节用 Caddy + Homepage 实现了统一入口,家人只需记住
https://raspberrypi.local/,并为必须 HTTPS 的 Vaultwarden 单独保留了 8443 端口; - Sonarr 扩展电视剧:第二篇 2.5 节接入了 Sonarr,剧集走与电影完全相同的自动化管线,只是终点目录换成
/share/Video/Series。
还有一个方向上的修正值得交代:本文按“优先 4K”配置的 Ultra-HD profile,在实际跑了一个月后收敛了——树莓派不适合实时转码,27 GB 的单文件对存储和播放都不友好,而下载管线本身(索引器、硬链接、字幕)与分辨率无关。第二篇把点播默认画质改为 1080p 起步,4K 只在点播时单部覆盖,具体代价和教训见第二篇 5.3 节。
仍然待办的:
- 给 qBittorrent 设置完成后自动做种限制或分类标签。
- 把 OpenSubtitles / ChineseSubFinder 账号密码改为环境变量注入,避免手动在 UI 填写。
- 4K 下载慢时,可尝试加入更多公共索引器或 PT 站点。
10. 最大的坑:两个 bind mount 让"硬链接"悄悄变成复制(2026-07-18 补记)
本文前面的架构图和流程都写的是"Radarr 硬链接/整理到媒体库"。实际上线一个月后才发现:硬链接从未生效过,所有电影都是完整复制了两份,235G 磁盘被吃到 91%。这是整套方案里最值得单独成章的坑。
10.1 先理清:Downloads 和 Movies 两个目录的分工
理解这个坑之前,得先搞清楚为什么会有两个目录、为什么还要分别挂载。
| 目录 | 谁在用 | 角色 | 里面的文件长什么样 |
|---|---|---|---|
/share/Downloads | qBittorrent | 下载中转站 + 做种田 | 保持种子原始命名(如 The.Shawshank.Redemption.1994.RESTORED.1080p.BluRay.REMUX-DDB.mkv),还混着广告 txt、样图等发布组附带文件 |
/share/Movies | Radarr | 正式片库 | 每片一个目录、规范重命名(如 The Shawshank Redemption (1994)/),附带 movie.nfo、poster.jpg、fanart.jpg 等元数据,供播放器、Bazarr、ChineseSubFinder 消费 |
关键在于:同一部电影需要同时存在于这两个角色里。做种要求原始文件留在 Downloads 里纹丝不动(改名或移走都会破坏种子完整性,没法继续做种);而片库要求规范命名、目录干净。鱼和熊掌要兼得,答案就是硬链接——同一份数据挂在两个路径下,互不干扰:
- Radarr 导入时不是"移动"也不是"复制",而是在 Movies 里建一个指向同一份数据的硬链接,文件名随便改,Downloads 那份原封不动继续做种;
- 以后任何一边删除都不影响另一边:qBittorrent 删种只删一个链接,片库文件还在;删片库文件也不伤害做种;
- 磁盘空间只在所有硬链接都被删除后才真正释放。
所以"两个目录分别挂载"这个设计本身没有错——错的是挂成了两个相互独立的 bind mount,把硬链接这条路悄悄堵死了。接下来就看到这个堵法有多隐蔽。
10.2 现象:磁盘空间翻倍
事发是磁盘告警:235G 的盘用到 91%。du 逐层排查后发现 /share/Downloads 占了 49G,而其中 6 部电影(肖申克 21G REMUX、Toy Story 5 18G 2160p 等)在 /share/Movies 片库里也各有一份。
第一反应是:也许 Radarr 用的是硬链接,两份路径共享同一文件,du 只是重复计数了?用 stat 验证 inode 和链接数:
1
2
3
4
5
stat -c '%i %h %n' \
"/share/Movies/The Shawshank Redemption (1994)/The.Shawshank.Redemption....mkv" \
"/share/Downloads/The.Shawshank.Redemption.../The.Shawshank.Redemption....mkv"
# 5943816 1 /share/Movies/...
# 5438054 1 /share/Downloads/...
两个 inode 不同、链接数都是 1——如果是硬链接,两个路径应该指向同一个 inode 且链接数 ≥ 2。结论是:这是两份真实的拷贝,49G 是实打实多占的空间,"硬链接入库"从未发生过。
10.3 根因:跨 bind mount 的 link(2) 返回 EXDEV
分层验证的结果很有意思:
- 宿主机上:
/share/Movies和/share/Downloads在同一块 ext4 上(stat -c %d设备号相同),手动ln硬链接成功; - radarr 容器内:
ln /downloads/xxx /movies/xxx直接报Cross-device link(EXDEV)。
原因在于:Linux 内核的 link(2) 要求源和目标落在同一个挂载(vfsmount)下。本文第 4.2 节的 compose 把 /share/Movies 和 /share/Downloads 作为两个独立的 bind mount 挂进容器——哪怕底层是同一文件系统,跨 bind mount 做硬链接也会被内核拒绝。而 Radarr 虽然 copyUsingHardlinks: true,硬链接失败后会静默回退为复制,界面上没有任何告警,不用 stat 查 inode 根本发现不了。
这正是 TRaSH Guides 的经典文章 Hardlinks and Instant Moves (Atomic-Moves) 要解决的问题:它建议让下载目录和媒体库落在同一个挂载下(即所谓单一 /data 布局),硬链接和瞬时移动才能正常工作。linuxserver 官方示例 compose 里 /movies、/downloads 两个 volume 的写法历史悠久,照抄就会踩中这个坑。
flowchart TD
subgraph G1["修复前:两个 bind mount"]
EXT4A["/share(同一 ext4)"] --> BA["bind: /share/Movies → /movies"]
EXT4A --> BB["bind: /share/Downloads → /downloads"]
BA -.->|"link() = EXDEV,退化为复制"| BB
end
subgraph G2["修复后:单一挂载 + 软链"]
EXT4B["/share(同一 ext4)"] --> B1["bind: /share → /share"]
B1 --> S1["/movies → /share/Movies(软链)"]
B1 --> S2["/downloads → /share/Downloads(软链)"]
S1 ==>|"link() 成功,零拷贝"| S2
end
style BA fill:#ffe3e3
style BB fill:#ffe3e3
style S1 fill:#e8f5e9
style S2 fill:#e8f5e9
10.4 修复:单一挂载 + 软链,原有路径不变
顺着 10.3 的根因往下推,最直观的修法几乎是自己长出来的:既然病根是"两个独立 bind mount",那就只挂一个 /share:/share,然后把 Radarr 里的路径直接配成挂载下的真实路径 /share/Movies 和 /share/Downloads——这正是 TRaSH Guides 推荐的布局,干净利落,没有任何 trick。
但真要动手时发现这条路被一开始的配置卡死了:这套系统最初就是按 /movies、/downloads 两个路径配的,它们早已固化在至少三处:
- Root folder:Radarr 里登记的媒体库根目录就是
/movies; - 数据库记录:每部电影在 Radarr 数据库里存的完整路径都是
/movies/xxx (年份)/...,几十上百条; - 下游联动:Bazarr 通过 Radarr API 拿到这些
/movies/...路径再去文件系统找字幕——路径一变,Bazarr 的挂载也得跟着改,否则字幕功能整个坏掉。
也就是说,"直接改配置"意味着一整套有风险的迁移手术:批量迁移 root folder、补配 Remote Path Mapping(qBittorrent 上报的路径是 /downloads/...)、同步改 Bazarr 挂载——任何一处漏改都是静默故障。就为了绕开这个,才用软链 trick 一下:
- 挂载改成
/share:/share后,真实路径变成/share/Movies/...,与旧配置对不上; - 那就建个软链
/movies → /share/Movies,让旧地址自动改道到新位置。
一行 ln -s 换掉了整套手术,Radarr 和 Bazarr 的配置一个字都不用动,它们甚至不知道软链的存在。
这里要分清两种"链接",它们完全不是一回事:
- 软链接(symlink):上面这种,只是容器内目录的别名。radarr 访问
/movies/xxx时内核先把它翻译成/share/Movies/xxx再操作。它不连接任何电影数据,唯一作用是把两个路径引到同一个挂载下,为硬链接铺路; - 硬链接(hardlink):真正省空间的那个,由 radarr 之后每部电影导入时自动创建——同一份电影数据同时挂在 Downloads 的种子原名和 Movies 的规范名两个路径下。
一句话:软链是搭桥的,硬链是过桥的。下面脚本里的软链只是把路修通,真正连接电影文件的硬链接不需要手动建。
如果这套系统是从零搭建,根本用不着软链:直接挂
/share:/share,并在 Radarr 里把 root folder 配成/share/Movies、下载目录配成/share/Downloads,就什么桥都不需要。软链纯粹是给"已经存在的配置"打的兼容补丁。
做法:
compose 改为单一挂载,radarr 服务的 volumes 从两个 bind 改成:
1 2 3 4
volumes: - /home/pi/docker/radarr/config:/config - /home/pi/docker/radarr/config/custom-cont-init.d:/custom-cont-init.d:ro - /share:/share
用 linuxserver 镜像的 custom-init 机制建软链,
/home/pi/docker/radarr/config/custom-cont-init.d/10-hardlink-symlinks.sh(记得chmod +x):1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#!/usr/bin/with-contenv bash # 让 radarr 沿用已配置路径 /movies、/downloads, # 但两者软链到单一 /share 挂载下,使导入时可硬链接而非复制。 make_link() { link="$1"; target="$2" if [ -L "$link" ]; then ln -sfn "$target" "$link"; return; fi if [ -d "$link" ]; then if mountpoint -q "$link"; then echo "[hardlink-symlinks] $link 是挂载点,保持不变"; return fi if ! rmdir "$link" 2>/dev/null; then echo "[hardlink-symlinks] $link 非空目录,保持不变"; return fi fi ln -s "$target" "$link" } make_link /movies /share/Movies make_link /downloads /share/Downloads
软链解析后,
/movies和/downloads实际都落在/share这一个挂载点下,link(2)自然成功。Radarr 的 root folder、下载客户端映射、数据库记录全部不用改。这个脚本不是一次性的,必须长期保留:软链建在容器可写层里,容器每次重建(升级镜像、配置变更)都会被丢弃,脚本是每次容器启动时运行、负责把软链重建出来的。它本身幂等,留着没有任何副作用;删掉的话下次重建容器后
/movies、/downloads会变成无效路径,片库直接"消失"。小坑中坑:新版 linuxserver 基础镜像(s6 v3)只在容器根的
/custom-cont-init.d找自定义脚本,不再读旧文档里的/config/custom-cont-init.d。所以 compose 里要显式把脚本目录挂到/custom-cont-init.d,否则日志只会打印[custom-init] No custom files found, skipping...。只重建 radarr 容器,qBittorrent 完全不用动:
1
docker compose up -d radarr进行中的下载不受任何影响——qBittorrent 没重启,已下载的分块有哈希校验,不存在损坏或重下的问题;radarr 停的一两分钟里,下完的任务在 qBittorrent 里排队等它回来再导入。
验证:容器内 ln /downloads/x /movies/x 成功,且 Radarr API GET /api/v3/config/mediamanagement 返回 copyUsingHardlinks: true。
10.5 存量重复文件:字节校验后改硬链接,立省 49G
对于已经重复占空间的存量文件,不用删也不用重下:把 Movies 里的拷贝替换成指向 Downloads 的硬链接即可(Downloads 侧保留为源,qBittorrent 做种完全不受影响)。
但替换前必须先证明"两份文件内容真的相同",否则就是把好数据换成坏数据。证据分两层:
- 尺寸粗筛:
stat -c %s对比字节数。例如肖申克两边都是 21970935446 字节(21G REMUX),Toy Story 5 两边都是 18907976291 字节——字节数完全相等是同一份文件强有力的信号,但理论上仍可能巧合; - 全文比对实锤:
cmp -s逐字节比对两份文件的全部内容(21G 的文件就读 21G × 2),全部一致才动手。
替换本身是原子的,核心逻辑:
1
2
3
cmp -s "$downloads_file" "$movies_file" \
&& ln "$downloads_file" "$movies_file.tmp" \
&& mv "$movies_file.tmp" "$movies_file"
6 部电影全部通过字节级校验并完成替换后,stat 链接数变为 2,磁盘从 91% 降到 69%(空闲 21G → 70G)。之后新下载的电影导入时会自动硬链接,Downloads 做种和 Movies 入库共享同一份数据,不再占双份空间。
后续更新:本节当初判断“风险大于收益”而绕开的迁移手术,后来在第二篇 5.6 节完成了——全链路统一到
/share物理路径后,软链脚本和远程路径映射已全部拆除。本节作为硬链接问题的排障记录保留;新搭建的系统请直接采用统一路径方案,不必再走软链这条兼容路线。
11. 字幕管线的四个坑:中文站代理、反爬、配额门槛与重复下载(2026-08-05 补记)
上线一个半月后暴露出一组字幕问题:剧集《光环》全 8 集一直没有任何中文字幕,Bazarr 的 Wanted 列表里明明挂着"缺中文"却始终下不到;与此同时,电影《Volver》的同一条中文字幕被反复下载了 28 次。逐个排查后定位到四个互相独立的坑。
11.1 坑一:国内字幕站走了出国代理
症状:zimuku 等中文字幕源全部报错,日志里全是 _ssl.c: The handshake operation timed out。
根因:bazarr 容器按第 4.2 节配置了 HTTP_PROXY 走 V2Ray,所有出站流量都被拐到国外。国内字幕站(zimuku、射手、subf2m)本来直连很快,经代理绕一圈后 SSL 握手直接超时。
修法:把国内字幕站域名加进 bazarr 的 NO_PROXY,中文站直连、OpenSubtitles 继续走代理(第 4.2 节的 compose 片段已更新)。
同一个道理的另一个版本:dockerd 拉镜像也不走 shell 里配的代理。树莓派直连 Docker Hub 会超时,需要给守护进程单独配置 /etc/systemd/system/docker.service.d/http-proxy.conf(写入 HTTP_PROXY/HTTPS_PROXY),再 systemctl daemon-reload && systemctl restart docker,否则 docker compose pull 慢到不可用。
11.2 坑二:zimuku 的反爬验证码
zimuku 有 yunsuo 反爬保护,搜索时要求过图形验证码,Bazarr 只能借助付费的 anti-captcha 打码服务来过。没配 key 时每次搜索必然失败:先白等约 30 秒超时,再被 Bazarr 节流 10 分钟。由于字幕源是串行查询的,每一集都要先给 zimuku 陪葬半分钟——这是"搜字幕很慢"的主要原因。
不配打码服务的话,直接在 Settings → Providers 里禁用 zimuku,中文字幕靠射手、subf2m 和 ChineseSubFinder 兜底。
11.3 坑三:OpenSubtitles 的配额与匹配分门槛
OpenSubtitles.com 免费账号每天只能下载约 20 条字幕,配额耗尽后当天剩余搜索全部落空。更隐蔽的是默认的最低匹配分:Bazarr 给每条候选字幕按文件名匹配度打分,剧集默认要求达到满分 360 的 90%(324 分)才下载。《光环》的中文字幕其实一直能在 OpenSubtitles 搜到,但得分只有 312(86.7%),永远被挡在门外——"看得到,下不到"。
修法:Settings → Subtitles 把剧集的 minimum score 降到 85。降门槛后《光环》8 集立刻全部命中,而且下到的就是中英双语字幕。
顺带一个 API 坑:Bazarr 1.6 的设置接口(
POST /api/system/settings)用 JSON body 提交会返回 204 但什么都不保存,必须用表单字段格式(如settings-general-minimum_score=85)。在 WebUI 上操作则没有这个问题。
11.4 坑四:重复下载循环——缺失清单与磁盘脱节
《Volver》的中文字幕从 7 月 18 日到 8 月 4 日被重复下载了 28 次:每次都是同一条 OpenSubtitles 字幕、同样的 85% 得分,覆盖写入同一个 .zh.hi.srt 文件。
关键在于:Bazarr 判断"缺不缺字幕"不是实时看磁盘,而是查数据库里的 missing_subtitles 缺失清单,这张清单由索引任务负责刷新(每天 4:00 全量索引,下载后单部增量更新)。Volver 的清单记录卡在了"缺中文"的状态:字幕文件明明早已落盘、命名也正确,清单却没有被纠正。于是每 6 小时的"搜索缺失字幕"任务都把它当成无字幕处理:搜索 → 命中同一条字幕 → 下载覆盖 → 记一条历史,循环往复。这个循环还顺手把 OpenSubtitles 每天的 20 条配额吃得干干净净,让真正缺字幕的《光环》一直排不上队——四个坑就是这样互相放大的。
修法:System → Tasks 里手动执行一次 Index All Existing Movies Subtitles 和 Index All Existing Episodes Subtitles,全量重算缺失清单。重算后 12 部电影中 11 部状态转为"已满足",重复下载立即停止。
遗留疑问:清单为什么没有被自动刷新(疑似这个版本对
.hi字幕的索引更新存在缺陷)没有彻底定位,需要观察一段时间。如果日后再出现同一字幕被反复下载,先手动重建索引,再考虑升级 Bazarr 或上报 issue。
11.5 修完后的状态
- 《光环》S02 全 8 集补上了中英双语字幕(OpenSubtitles.com 来源);
- 仍缺字幕的只剩真正没有资源的:Rick and Morty 最新几集(中文字幕尚未发布)和老片《Picnic》,由每 6 小时的自动搜索持续盯着;
- 中文站直连后射手、subf2m 恢复可用,zimuku 保持禁用;
- 历史下载记录显示,这套系统里所有字幕实际都由 Bazarr(OpenSubtitles)下载,ChineseSubFinder 暂无贡献记录,其去留观察后再定。