前言

在数字时代,我们拥有的电影、电视剧、音乐和家庭视频越来越多,如何高效、安全地管理这些媒体文件,成为了许多 NAS 和服务器玩家的核心诉oken。手动整理费时费力,而简单的文件堆砌又容易导致混乱和数据丢失的风险。

本文旨在提供一套经过深思熟虑的、兼具自动化、灵活性与数据安全的终极媒体库搭建方案。这套方案的核心是“关注点分离”,通过巧妙地运用软链接与硬链接,将媒体库的“访问层”、“分类层”和“数据层”彻底解耦,让你在享受自动化整理便利的同时,高枕无忧。

无论你是刚入门的新手,还是寻求优化现有结构的老玩家,相信本文都能为你提供清晰的思路和可直接落地的完整实践。

一、设计理念与核心目标

在开始创建目录和编写脚本之前,我们必须明确我们的设计哲学。一个好的顶层设计能让后续所有工作事半功倍。

  1. 统一访问入口:无论后端物理存储如何复杂(例如,分布在多个硬盘或阵列上),所有 Docker 容器(如 Jellyfin, Plex, MoviePilot)都应该通过一个统一、简洁的路径(例如 /mnt/Library)来访问整个媒体库。这极大地简化了容器的配置和迁移。

  2. 物理数据分离:媒体文件可以根据类型或访问频率,存储在不同的物理磁盘上。例如,将访问频繁的影视剧放在高速 SSD(/vol2),而将归档性质的音乐、家庭视频放在大容量 HDD(/vol1)。

  3. 自动与手动分离:这是保障数据安全的核心。由 MoviePilot 等工具自动整理和链接的区域,应被视为“可随时销毁和重建的”;而由我们手动整理的重要文件(如无法识别的影片、珍贵的家庭录像),则必须存放在一个“神圣不可侵犯”的区域。

  4. 安全的清空与重建:当自动分类出现大规模错误,或我们想调整分类规则时,应该能毫秒级地“一键重置”整个自动分类库,而不删除任何原始媒体文件,也绝不影响手动维护区的内容。

  5. 技术核心:软链接 vs. 硬链接

    • 软链接 (Symbolic Link):如同 Windows 的“快捷方式”,它本身是一个小文件,指向另一个文件或目录。我们用它来构建容器内的统一访问入口 /mnt/Library
    • 硬链接 (Hard Link):如同文件的“分身”,它直接指向文件的物理存储数据块。只要文件的硬链接数不为零,文件就不会被真正删除。这是实现“安全清空”和“节省空间”的关键技术。

二、最终目录结构详解

基于以上理念,我们设计了如下的三层结构:

1. 容器统一视图 (/mnt/Library)

这是所有媒体服务容器看到的唯一路径,通过软链接实现。

1
2
3
4
5
6
/mnt/Library
├── 电影 -> /vol2/1000/Library/电影
├── 电视剧 -> /vol2/1000/Library/电视剧
├── 音乐 -> /vol1/1000/Library/音乐
├── 家庭视频 -> /vol1/1000/Library/家庭视频
└── 自主分类 -> /vol2/1000/Library/_自主分类

2. 物理存储分类视图 (/volX/1000/Library/)

这是链接的目标区域,也是自动化工具(MoviePilot, Radarr, Sonarr)实际操作的区域。

高速盘,存放可随时重建的硬链接库和需要手动维护的真实文件

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
/vol2/1000/Library/

├── 电影/ # (硬链接库, 可清空重建)
│ ├── 动漫
│ ├── 纪录片
│ ├── 音乐
│ ├── 儿童
│ ├── 国产
│ ├── 欧美
│ └── 其他

├── 电视剧/ # (硬链接库, 可清空重建)
│ ├── 动漫
│ ├── 纪录片
│ ├── 音乐
│ ├── 儿童
│ ├── 综艺
│ ├── 国产
│ ├── 欧美
│ └── 其他

└── _自主分类/ # (真实文件, 手动维护, 永久保留!)
大容量盘,存放音乐和家庭视频等
/vol1/1000/Library/

├── 音乐/ # (真实文件或硬链接)
└── 家庭视频/ # (真实文件或硬链接)

3. 映射关系图

下图直观地展示了“访问层”到“分类层”的软链接映射关系。

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
   graph TD
subgraph 容器内部 (Container View)
A[”/mnt/Library (挂载点)“]
A —> B1[”/mnt/Library/电影“]
A —> B2[”/mnt/Library/电视剧“]
A —> B3[”/mnt/Library/自主分类“]
A —> B4[”/mnt/Library/音乐“]
A —> B5[”/mnt/Library/家庭视频“]
end

subgraph 主机物理存储 (Host Physical Storage)
C[”/vol2/1000/Library (实际数据位置)“]
C —> D1[”.../电影 (物理文件夹)“]
C —> D2[”.../电视剧 (物理文件夹)“]
C —> D3[”.../自主分类 (物理文件夹)“]
C —> D4[”.../音乐 (物理文件夹)“]
C —> D5[”.../家庭视频 (物理文件夹)“]
end

B1 —”ln -s (软链接)“—> D1
B2 —”ln -s (软链接)“—> D2
B3 —”ln -s (软链接)“—> D3
B4 —”ln -s (软链接)“—> D4
B5 —”ln -s (软链接)“—> D5

style A fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#ccf,stroke:#333,stroke-width:2px

重要提示:关于硬链接的限制
硬链接技术要求链接文件和源文件必须在同一个文件系统(分区)中。这意味着,您的下载目录(例如 /vol2/1000/Downloads)和您的硬链接分类库(/vol2/1000/Library必须位于同一个物理卷 /vol2 上。如果跨盘符(例如从 /vol1 的下载目录硬链接到 /vol2),操作将会失败。这也是我们将影视剧的分类库放在 /vol2 的原因,假设 /vol2 也是您的主下载盘。

三、自动化工具配置

为了让 MoviePilot 和下载器能够理解并使用我们的目录结构,需要进行精确的配置。

1. MoviePilot 分类插件配置

这份配置定义了媒体文件应该如何根据类型(genre_ids)和地区被归类。最后的 其他: {} 是一个万能的“兜底”规则,确保没有任何影片被遗漏。

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
# MoviePilot `categories.yaml`
# movie
movie:
电影/动漫:
genre_ids: ’16‘
电影/纪录片:
genre_ids: ’99‘
电影/音乐:
# 匹配演唱会, MV, 音乐剧等
genre_ids: ’10402‘
电影/儿童:
# 匹配家庭和儿童分类
genre_ids: ’10751,10762‘
电影/国产:
production_countries: ’CN,HK,TW,MO,SG‘
original_language: ’zh,cn‘
电影/欧美:
production_countries: ’US,GB,FR,DE,CA,AU,ES,IT,IE,NZ,SE,NO,DK,FI,PT,CH,BE,NL‘
电影/其他: {} # 兜底规则,匹配所有未被上方规则命中的电影

# tv
tv:
剧集/动漫:
genre_ids: ’16‘
剧集/纪录片:
genre_ids: ’99‘
剧集/音乐:
genre_ids: ’10402‘
剧集/儿童:
genre_ids: ’10762,10751‘
剧集/综艺:
genre_ids: ’10764,10767‘
剧集/国产:
origin_country: ’CN,HK,TW,MO,SG‘
original_language: ’zh,cn‘
剧集/欧美:
origin_country: ’US,GB,FR,DE,CA,AU,ES,IT,IE,NZ,SE,NO,DK,FI,PT,CH,BE,NL‘
剧集/其他: {} # 兜底规则,匹配所有未被上方规则命中的剧集
  1. qBittorrent 分类配置 (categories.json)
    这份配置用于在下载器(以 qBittorrent 为例)中创建与 MoviePilot 完全对应的分类,从而实现下载完成后的自动归类。
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
{
”电影“: {
”save_path“: ”“
},
”电影/动漫“: {
”save_path“: ”“
},
”电影/纪录片“: {
”save_path“: ”“
},
”电影/音乐“: {
”save_path“: ”“
},
”电影/儿童“: {
”save_path“: ”“
},
”电影/国产“: {
”save_path“: ”“
},
”电影/欧美“: {
”save_path“: ”“
},
”电影/其他“: {
”save_path“: ”“
},
”剧集“: {
”save_path“: ”“
},
”剧集/动漫“: {
”save_path“: ”“
},
”剧集/纪录片“: {
”save_path“: ”“
},
”剧集/音乐“: {
”save_path“: ”“
},
”剧集/儿童“: {
”save_path“: ”“
},
”剧集/综艺“: {
”save_path“: ”“
},
”剧集/国产“: {
”save_path“: ”“
},
”剧集/欧美“: {
”save_path“: ”“
},
”剧集/其他“: {
”save_path“: ”“
}
}

四、部署实施脚本

以下是两个核心的 Shell 脚本,用于初始化和维护这套结构。

脚本一:初次构建脚本 (first_build.sh)

此脚本仅需在部署初期运行一次,用于创建所有必需的目录和链接。

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
#!/bin/bash
# ===================================================
# 初次构建媒体库目录结构
# 脚本已优化,确保分类与自动化配置一致且可重复运行
# ===================================================

set -e

echo ”🚀 开始初次构建媒体库目录结构...“

# 创建物理盘基础路径
mkdir -p /vol1/1000/Library
mkdir -p /vol2/1000/Library

# 创建自动分类目录(与 MoviePilot/qBittorrent 分类完全一致)
echo ”—> 正在创建电影与电视剧分类目录...“
mkdir -p /vol2/1000/Library/电影/{动漫,纪录片,音乐,儿童,国产,欧美,其他}
mkdir -p /vol2/1000/Library/电视剧/{动漫,纪录片,音乐,儿童,综艺,国产,欧美,其他}

echo ”—> 正在创建音乐与家庭视频分类目录...“
for category in 音乐 家庭视频; do
mkdir -p /vol1/1000/Library/$category
done

# 创建手动维护的自主分类目录
echo ”—> 正在创建自主分类目录...“
mkdir -p /vol2/1000/Library/_自主分类

# 创建容器统一访问入口
mkdir -p /mnt/Library

# 建立软链接(使用 -sf 强制覆盖,使脚本可重复运行而无错误)
echo ”—> 正在建立 /mnt/Library 的软链接...“
ln -sf /vol2/1000/Library/电影 /mnt/Library/电影
ln -sf /vol2/1000/Library/电视剧 /mnt/Library/电视剧
ln -sf /vol1/1000/Library/音乐 /mnt/Library/音乐
ln -sf /vol1/1000/Library/家庭视频 /mnt/Library/家庭视频
ln -sf /vol2/1000/Library/_自主分类 /mnt/Library/自主分类

echo ”✅ 初次构建完成!“

当需要彻底清理和重置自动分类库时,运行此脚本。它会安全地删除所有自动生成的链接和目录,然后重建一个干净的结构,绝不会触碰 _自主分类 目录。

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
#!/bin/bash
# ===================================================
# 重新初始化媒体库链接目录
# 功能:安全删除所有自动分类内容并重建目录结构
# 绝对保障 _自主分类 目录的安全
# ===================================================

set -e

echo ”⚠️ 警告:此操作将清空所有自动分类内容!“
read -p ”请确认是否继续? (y/N) “ -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo ”操作已取消。“
exit 1
fi

echo ”🚀 开始重新初始化...“

# 1. 安全删除 /vol2 下的自动分类目录(通过 find 精确排除 _自主分类)
echo ”—> 正在清理 /vol2 的自动分类目录...“
find /vol2/1000/Library/ -mindepth 1 -maxdepth 1 ! -name ’_自主分类‘ -exec rm -rf {} +

# 2. 安全清理 /vol1 下的自动分类目录
echo ”—> 正在清理 /vol1 的自动分类目录...“
rm -rf /vol1/1000/Library/音乐
rm -rf /vol1/1000/Library/家庭视频

# 3. 重建所有自动分类目录结构(关键!)
echo ”—> 正在重建自动分类目录结构...“
mkdir -p /vol2/1000/Library/电影/{动漫,纪录片,音乐,儿童,国产,欧美,其他}
mkdir -p /vol2/1000/Library/电视剧/{动漫,纪录片,音乐,儿童,综艺,国产,欧美,其他}
mkdir -p /vol1/1000/Library/音乐
mkdir -p /vol1/1000/Library/家庭视频

# 4. 重建软链接
echo ”—> 正在重建 /mnt/Library 下的软链接...“
ln -sf /vol2/1000/Library/电影 /mnt/Library/电影
ln -sf /vol2/1000/Library/电视剧 /mnt/Library/电视剧
ln -sf /vol1/1000/Library/音乐 /mnt/Library/音乐
ln -sf /vol1/1000/Library/家庭视频 /mnt/Library/家庭视频
ln -sf /vol2/1000/Library/_自主分类 /mnt/Library/自主分类

echo ”✅ 媒体库已成功重新初始化!“

五、工作流程与使用建议

  • 首次部署:运行 bash first_build.sh 建立基础结构。
  • 配置工具:
    • 将上述 categories.yaml 和 categories.json 分别配置到 MoviePilot 和 qBittorrent 中。
    • 在 Jellyfin/Plex 等媒体服务器中,添加媒体库时,路径请选择 /mnt/Library/电影、/mnt/Library/电视剧 等。
    • 在 Radarr/Sonarr 等索引器中,设置的根目录 (Root Folder) 也应该是 /mnt/Library/电影 和 /mnt/Library/电视剧。
    • 关键:确保所有自动化工具的配置路径都是 /mnt/Library 下的路径,而不是直接操作物理路径 /volX。
  • 日常使用:享受自动化。下载的媒体文件会被 MoviePilot 自动识别、创建硬链接并归类到 /vol2/1000/Library 下的对应目录中。Jellyfin 等服务通过 /mnt/Library 软链接实时访问这些分类好的文件。
  • 手动整理:对于无法自动识别或特别珍贵的资源,请手动将真实文件移动到 /vol2/1000/Library/_自主分类 下的自建目录中。
  • 维护与重置:如果某天发现自动分类库一片混乱,或者想更换分类规则,只需大胆地运行 bash rebuild_links.sh。它会为你清空旧世界,创造新天地,而你的原始下载文件和手动分类文件安然无恙。

总结

至此,我们构建了一套强大、安全且易于维护的自动化媒体库系统。它可能初看起来有些复杂,但一旦搭建完成,你将获得长久的安逸和对数据的绝对掌控感。这套方案的精髓在于其分层解耦的思想,使其能够灵活适应未来硬件的升级和软件的变迁。
希望这篇详尽的指南能帮助你打造出属于自己的、完美的数字媒体中心。