折腾记录 | 04 Windows + Docker 配置 NAStool + Jellyfin 影视库 踩坑记录

Windows + Docker 配置 NAStool + Jellyfin 影视库 踩坑记录

最近笔者突然有了组建 NAS 的想法,不过并不想立刻就组装硬件,而是先在自己的 Windows 机器上尝试一下 NAS 的软件。花了两天时间调研和搭建,最后得到一个勉强能半自动化的“系统”。

本文中所使用的全部软件(除了 Windows)都是免费、开源的。本文将不涉及搭建这一系统的各种细节(包括会在常见的教程中出现的部分),而将仅仅提供整体的思路,以及笔者遇到的问题和对应的解决方案。需要注意的是这些方案都只在 Windows 下测试过,无法保证在 Linux 下也有效,并且 Linux 下往往并不会遇到这些问题。本文最后有附上全部的 docker-compose 配置,用于参考。

环境

笔者的环境如下:

  • Windows 10 Pro 22H2;
  • WSL2 作为后端的 Docker Desktop, 所有 NAS 软件都跑在 Docker 中;
  • 一块 Nvidia 显卡用于视频转码(非必须);
  • 良好且可靠的网络环境。

除了网络以外的要求,应该都是非常容易达到的。如果您的网络条件不佳(这通常会反映在 Docker 容器的日志中),网上也有很多文章能帮您解决。

管线

介绍一下笔者搭建的这套系统的完整管线。简要地说,我们需要做的事有以下几件:

  • 从 BT 或 PT 站下载媒体资源
  • 从 TheMovieDatabase 等网站获取元数据(这一过程被称为刮削);
  • 用元数据创建美观的 UI,并提供播放的功能。

我们可以使用 qBittorrent 下载资源,使用 Jellyfin 刮削元数据、提供 UI 和播放。但这样做会遇到这样几个问题:

  • BT 或 PT 站都是 “我为人人,人人为我” 的形式,也就是说下载完成后,仍然要保持文件的结构和命名不变,以为他人做种;
  • Jellyfin 内置的刮削依赖于文件的结构和命名,如果种子内的结构和命名不好,会导致元数据刮削失败;
  • 解决以上两点之间的矛盾的通常办法是创建硬链接,但这又引出了以下的两个问题:
    • Windows 和 Docker (或者说 WSL2)的文件系统不一样,因此在 Docker 内创建硬链接会失败;
    • 在 Windows 上可用的自动的硬链接 + 重命名工具 tinyMediaManager 是订阅制的付费软件;
  • 最后是 Jellyfin 内置的刮削并不是特别好用,尤其是出错时会比较难以纠正(尤其在是动画或电视剧的情形下)。

查了一些资料之后,笔者发现开源的 NAStool 和其后继者 MoviePilot 也能做到自动的硬链接 + 重命名,同时还有一些其它的方便功能。在尝试之后,发现用软链接也可以一定程度上替代硬链接。

于是我们就得到了完整的管线:

  • NAStool 用于检索资源站,添加下载任务,在任务完成后为媒体库创建软链接;
  • qBittorrent 用于下载资源,完全由 NAStool 管理;
  • Jellyfin 从 NAStool 重命名好的文件刮削元数据,并提供 UI 和播放服务。

(由于 NAStool 3.x 和 MoviePilot 都需要某些特定 PT 站的认证,笔者作为替代,使用的是 NAStool 2.9.2)

问题

笔者在配置过程中遇到的一些问题,以及解决方案。

容器间通信

qBittorrent 和 Jellyfin 都会提供一个端口用于与它们通信,如果是在宿主机上,只要使用 http://localhost:端口 就可以了。但容器内的网络并不相同,我们需要使用 http://host.docker.internal:端口.

软链接

首先介绍一下硬链接和软连接的区别。我们可以把一般的 “文件” 理解为类似指针的概念,它保存了磁盘上一块数据的地址。创建一个硬链接意味着创建了另一个指向同一地址的指针。而软链接则是保存原文件的路径,也就是说它是指针的指针。

因此,硬链接只能在同一文件系统内生效,并且创建了硬链接后,两个 “文件” 删除其中任何一个都不会导致数据被删除。软链接则可以跨越文件系统(因为它实际上就是以文本形式存储了目标文件的路径字符串),删除软链接不会导致什么,但删除原文件会导致数据和软链接都消失。此外,硬链接不能链接目录,而软链接可以,但这一点在这里并不重要。

有了以上的知识后,我们就知道如何能用软链接代替硬链接。首先在 NAStool 的基础设置中,将默认文件转移方式改为软链接。然后我们修改 docker 的映射设置,将下载目录(也就是媒体文件实际保存的位置)也暴露给 Jellyfin,这样 Jellyfin 读取了媒体目录下的软链接文件,就可以在下载目录下找到实际的文件,并用于提供播放服务了。具体的配置可以参考文后的 docker-compose 配置文件。

文件转移

我们利用 NAStool 的自动文件转移功能,来实现软链接和自动重命名。

将 NAStool 的 “设置 - 基础设置 - 媒体 - 默认文件转移方式” 设置为软链接,再勾选 “设置 - 基础设置 - 服务 - 下载软件监控”,即可让 NAStool 自动在下载完成后自动进行软链接和重命名。

NAStool 未能识别成功的文件会出现在 “媒体整理 - 手动识别” 中,同时也可以在历史记录中检查是否存在识别错误。

转码

笔者使用 Nvidia 的显卡进行转码。根据 Using NVIDIA GPUs with WSL2, 我们只需要达成以下条件:

  • 最新的显卡驱动
  • 最新版本的 WSL2
  • 在 Docker Desktop 中启用 WSL2 后端

即可在容器中调用显卡。

文档中提到可以用这个镜像进行测试:

1
$ docker run --rm -it --gpus=all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark

于是知道我们只需要加上 --gpus=all 这个参数即可。但这在 docker-compose 中要更复杂一点,需要加上:

1
2
3
4
5
6
7
8
runtime: nvidia
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]

添加 WebDAV 网盘

Jellyfin 本身并不支持添加 WebDAV 网盘,我们必须用 rclone 将网盘(其它协议当然也可以)映射到本地,再添加到 Jellyfin 的媒体库。

由于笔者并不希望直接添加网盘中的所有内容,而且网盘中的内容并不一定有方便刮削的结构和命名,实际上还使用了 NAStool 创建了自动目录同步的任务,也就是软链接 + 重命名,来方便 Jellyfin 进行刮削。

docker-compose 文件

NAStool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
services:
nas-tools:
image: nastools/nas-tools:2.9.1
container_name: nas-tools
environment:
- PUID=0
- PGID=0
- UMASK=000
- NASTOOL_AUTO_UPDATE=false
- NASTOOL_CN_UPDATE=false
volumes:
- ./config:/config
- D:/media:/media
- D:/downloads:/downloads:ro
- D:/cloud/:/cloud:ro
ports:
- 3000:3000
restart: unless-stopped

qBittorrent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
services:
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
container_name: qbittorrent
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- WEBUI_PORT=8080
- TORRENTING_PORT=16881
volumes:
- ./appdata:/config
- D:/downloads:/downloads
ports:
- 8080:8080
- 16881:16881
- 16881:16881/udp

Jellyfin

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
services:
jellyfin:
image: docker.io/jellyfin/jellyfin:latest
container_name: jellyfin
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
- NVIDIA_VISIBLE_DEVICES=all
volumes:
- ./config:/config
- D:/media:/media
- D:/downloads:/downloads:ro
- D:/cloud/:/cloud:ro
ports:
- 8096:8096
runtime: nvidia
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
restart: unless-stopped

Rclone

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
services:
rclone:
image: rclone/rclone
container_name: rclone
privileged: true
security_opt:
- apparmor:unconfined
cap_add:
- SYS_ADMIN
devices:
- /dev/fuse
restart: unless-stopped
volumes:
- ./config:/config/rclone
- D:/cloud:/cloud:shared
entrypoint: >-
sh -c "rclone mount webdav: /cloud
--vfs-cache-mode full
--vfs-read-chunk-size-limit 1G
--vfs-read-chunk-size 256M
--cache-dir /config/cache
--dir-cache-time 5m --vfs-cache-max-size 10G
--buffer-size 128M
--no-check-certificate
--allow-non-empty
--allow-other
--umask 000
--read-only"

折腾记录 | 04 Windows + Docker 配置 NAStool + Jellyfin 影视库 踩坑记录
https://ne0.io/posts/1459904819/
作者
Ne0 Wu
发布于
2024年11月17日
许可协议