提示

返回博客列表

把下载的视频变成私人 Netflix——Jellyfin 家庭媒体库搭建全攻略

把下载的视频变成私人 Netflix——Jellyfin 家庭媒体库搭建全攻略

你用下载器攒了几百个视频:技术教程、纪录片、电影、自己喜欢的 up 主合集。但它们散落在各个文件夹里,想找个视频得翻半天,想在手机上看得先拷过去,想跟家人共享更是无从下手。其实你缺的不是视频,而是一个媒体服务器。Jellyfin 是开源免费的 Emby/Plex 替代品,装好之后你的所有视频会自动生成海报墙、自动按类型/年份/演员分类、支持任意设备播放(手机/平板/电视/浏览器)、还支持外网访问和硬件转码——完完全全的"私人 Netflix"体验。这篇文章从零带你搭建,包括 Docker 部署、元数据刮削、硬件加速转码、外网访问和自动入库。

TL;DR:Jellyfin = 开源媒体服务器。Docker 一行命令部署,视频放到指定目录后自动刮削海报和元数据(从 TMDB/豆瓣),支持硬件转码(Intel QSV/NVIDIA NVENC)实现实时转码播放,通过 DDNS + 反向代理实现外网访问。配合 yt-dlp 下载视频后自动放到 Jellyfin 媒体目录,整个流程全自动化。

目录

一、为什么选 Jellyfin 而不是 Plex/Emby

市面上三个主流的家庭媒体服务器:

特性 Jellyfin Plex Emby
开源/免费 ✅ 完全开源免费 ❌ 高级功能收费 ❌ 高级功能收费
硬件转码 ✅ 免费 ❌ 需 Plex Pass($120/永久) ❌ 需 Emby Premiere($4.99/月)
离线播放 ✅ 免费 ❌ 需 Plex Pass ❌ 需 Emby Premiere
数据隐私 ✅ 完全本地 ❌ 需通过 Plex 服务器认证 ❌ 需通过 Emby 服务器认证
插件生态 中等 丰富 中等
客户端 Web/Android/iOS/TV/KDl Web/Android/iOS/TV/游戏机 Web/Android/iOS/TV

一句话总结:Jellyfin 是唯一一个"不花一分钱就能用全部功能"的选择。 Plex 和 Emby 的核心功能(硬件转码、离线下载)都需要付费订阅。而且 Jellyfin 完全本地运行,不需要把数据经过第三方服务器——这对隐私敏感的国内用户来说是刚需。

Jellyfin 是 Emby 的一个开源分支(2018 年 Emby 闭源后社区 fork 出来的),所以很多 Emby 的插件和教程对 Jellyfin 也适用。

二、Docker 部署:一行命令跑起来

2.1 准备工作

# 服务器要求:Linux(Ubuntu/Debian/CentOS),有 Docker
# 最低配置:1 核 CPU + 1GB 内存(纯直接播放)
# 推荐配置:4 核 CPU + 4GB 内存(带硬件转码)

# 创建目录结构
mkdir -p ~/jellyfin/{config,cache,media}
mkdir -p ~/jellyfin/media/{movies,tvshows,downloads}

2.2 Docker Compose 部署

# docker-compose.yml
version: '3.8'

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    restart: unless-stopped
    ports:
      - "8096:8096"      # HTTP
      - "8920:8920"      # HTTPS(可选)
    volumes:
      - ./config:/config
      - ./cache:/cache
      - ./media:/media:ro  # 只读挂载媒体目录
    environment:
      - TZ=Asia/Shanghai
      - JELLYFIN_PublishedServerUrl=https://your-domain.com  # 外网地址
    devices:
      # 硬件加速(Intel QSV)
      - /dev/dri:/dev/dri
    group_add:
      - "44"   # video 组 ID(ubuntu),用于访问 /dev/dri
      - "105"  # render 组 ID
# 启动
docker compose up -d

# 查看日志
docker compose logs -f jellyfin

启动后访问 http://你的服务器IP:8096,按照引导设置语言(中文)、创建管理员账户、添加媒体库。

2.3 媒体库类型选择

Jellyfin 支持多种媒体库类型,每种对应不同的元数据刮削策略:

类型 用途 目录结构要求 刮削源
电影 电影收藏 每个电影一个文件夹 TMDB/豆瓣
电视剧 剧集/系列视频 剧名/Season 01/EP01.mp4 TVDB/TMDB
音乐 音乐收藏 歌手/专辑/曲目.flac MusicBrainz
混合内容 不按分类的视频 无要求 无(使用文件名)
合集 系列电影打包 无要求 TMDB
家庭视频 自己拍的视频 无要求

对于下载的各种视频(教程、up 主合集、纪录片),推荐使用混合内容类型——Jellyfin 会用文件名作为标题,不会尝试刮削元数据(因为大部分网络视频在 TMDB 上没有条目)。

2.4 推荐的文件命名规范

Jellyfin 对文件名有要求,命名不规范会导致刮削失败:

电影:
  /media/movies/盗梦空间 (2010)/盗梦空间 (2010).mp4
  /media/movies/Inception (2010)/Inception (2010) [1080P][H.264].mp4

电视剧:
  /media/tvshows/权力的游戏/Season 01/Game of Thrones S01E01.mp4
  /media/tvshows/权力的游戏/Season 01/权力的游戏 S01E01 凛冬将至.mp4

混合内容(教程/纪录片/短视频):
  /media/downloads/Fireship/Fireship - Docker in 100 Seconds [1080P].mp4
  /media/downloads/阮一峰/阮一峰 - ES6 入门教程 01 [720P].mp4

三、元数据刮削:让视频自动"有封面有简介"

3.1 内置刮削器配置

在 Jellyfin 控制台 → 媒体库 → 管理媒体库 → 勾选需要的元数据下载器:

推荐配置(国内用户):
  ✅ TheMovieDb(电影/电视剧海报和简介)
  ✅ The Open Movie Database(补充信息)
  ✅ Screen Grabber(从视频中自动截图做封面)

不推荐(国内访问不稳定):
  ❌ TheTVDB(经常被墙)
  ❌ FanArt(很慢)

3.2 安装豆瓣刮削插件

TMDB 对中文内容覆盖不全,很多国产电影、综艺、动漫没有条目。安装豆瓣插件可以大幅提升中文内容的刮削成功率:

# 进入 Jellyfin 插件目录
cd ~/jellyfin/config/plugins

# 下载豆瓣插件(以 MetaTube 为例)
# 仓库地址:https://github.com/cxfksword/jellyfin-plugin-metashare
wget https://github.com/cxfksword/jellyfin-plugin-metashare/releases/download/v1.6.5/MetaTube.dll

# 放到插件目录后重启 Jellyfin
docker restart jellyfin

重启后在 Jellyfin 控制台 → 插件 → 目录 → 找到 MetaTube → 点击安装 → 重启。

配置 MetaTube:设置 → 插件 → MetaTube → 选择数据源(豆瓣/Douban)→ 保存。

3.3 手动修复元数据

刮削器不是万能的。对于刮削失败的视频:

方法 1:右键视频 → 识别 → 手动输入 IMDB ID 或 TMDB ID
  例如:Inception 的 IMDB ID 是 tt1375666

方法 2:右键视频 → 编辑元数据 → 手动填写标题/简介/年份/海报

方法 3:在视频文件夹中放一张 poster.jpg 作为封面
  /media/movies/某电影/poster.jpg

3.4 用 NFO 文件预设元数据

对于刮削器无法识别的视频(比如下载的 B 站教程),可以提前生成 NFO 文件:

<!-- 某视频目录/tvshow.nfo -->
<?xml version="1.0" encoding="utf-8"?>
<tvshow>
  <title>ES6 入门教程</title>
  <plot>阮一峰老师的 ES6 入门系列教程</plot>
  <genre>教程</genre>
  <premiered>2024-01-01</premiered>
  <studio>阮一峰</studio>
</tvshow>

四、硬件加速转码:为什么需要以及怎么配

4.1 什么情况下需要转码

直接播放(Direct Play):客户端支持视频的编码格式 → 服务器直接发送原始文件 → 几乎不消耗 CPU。

转码(Transcoding):客户端不支持编码格式 / 带宽不足需要降码率 / 字幕需要烧录到画面 → 服务器实时转换格式 → 消耗 CPU 或 GPU。

常见需要转码的场景:

- 用手机浏览器看 H.265 编码的视频(Safari 以外大多数不支持 H.265)
- 外网带宽不够,需要把 4K 转成 1080P 传输
- 视频有 ASS 特效字幕,客户端不支持,需要烧录到画面
- 音频是 DTS/Dolby Atmos,客户端只支持 AAC

4.2 硬件加速方案对比

方案 适用硬件 转码能力 功耗 成本
Intel QSV Intel 核显(HD 610+) 4-8 路 1080P 同时转码 极低 免费(CPU 自带)
NVIDIA NVENC NVIDIA GTX 1050+ 3-8 路(有 session 限制) 需要独显
VA-API AMD/Intel Linux 驱动 3-5 路 免费
Apple VideoToolbox Mac 3-5 路 Mac 自带

推荐方案:Intel 核显 QSV。几乎所有 Intel CPU(第 7 代酷睿及以上)都自带,不需要额外硬件,转码效果也很好。

4.3 配置 Intel QSV 硬件加速

# docker-compose.yml 中已包含的配置
devices:
  - /dev/dri:/dev/dri
group_add:
  - "44"   # video 组
  - "105"  # render 组

# 确认 /dev/dri 权限
ls -la /dev/dri
# 输出类似:crw-rw---- 1 root video 226, 0 Jan 1 00:00 renderD128

然后在 Jellyfin 控制台 → 播放 → 硬件加速:

硬件加速:Intel QuickSync (QSV)
启用硬件解码:✅ 全部勾选
   ✅ H.264
   ✅ H.265/HEVC
   ✅ VP9
   ✅ AV1(12 代酷睿及以上支持)
硬件编码选项:
   ✅ 启用硬件编码
   ✅ 允许 HEVC 编码

4.4 验证硬件加速是否生效

播放一个需要转码的视频,在 Jellyfin 控制台 → 仪表盘 → 查看当前播放信息:

播放方式:转码  ← 说明在转码
原因:视频编码不支持  ← 转码原因

如果是硬件加速转码,日志中会出现:
[hevc_qsv @ ...]  ← QSV 硬件加速

也可以用命令行验证:

# 进入容器
docker exec -it jellyfin bash

# 检查 QSV 是否可用
/usr/lib/jellyfin-ffmpeg/ffmpeg -v debug -init_hw_device qsv=hw
# 输出包含 "qsv device initialized" 说明正常

五、外网访问:随时随地看你的视频库

5.1 方案一:DDNS + 端口转发

前提:有公网 IP(向运营商申请)

1. 路由器上设置端口转发:外网 8096 → 内网 192.168.1.x:8096
2. 配置 DDNS(动态域名):
   - 阿里云 DDNS:在路由器上设置,或跑一个脚本定时更新
   - 免费方案:duckdns.org
3. 访问:http://your-domain.duckdns.org:8096

5.2 方案二:Cloudflare Tunnel(不需要公网 IP)

没有公网 IP 时的最佳方案:

# 在 docker-compose.yml 中添加
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared
    restart: unless-stopped
    command: tunnel --no-autoupdate run --token YOUR_TUNNEL_TOKEN

在 Cloudflare Zero Trust 面板创建 Tunnel,绑定域名,指向 http://jellyfin:8096

注意:Cloudflare Tunnel 免费版有 100MB 上传限制,看视频可能被限速。看高清视频建议用有公网 IP 的方案。

5.3 方案三:frp 内网穿透

# frpc.ini(客户端,跑在 Jellyfin 服务器上)
[jellyfin]
type = tcp
local_ip = 127.0.0.1
local_port = 8096
remote_port = 8096

需要一个有公网 IP 的 VPS 做 frp 服务端。相比 Cloudflare Tunnel 没有流量限制,但需要额外一台服务器。

5.4 Nginx 反向代理(配合 HTTPS)

# /etc/nginx/sites-available/jellyfin
server {
    listen 443 ssl http2;
    server_name media.your-domain.com;

    ssl_certificate /etc/ssl/certs/your-domain.pem;
    ssl_certificate_key /etc/ssl/private/your-domain.key;

    # Jellyfin 要求较大的请求体(用于上传)
    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:8096;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket 支持(Jellyfin 需要)
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

六、自动入库:下载完自动归档到 Jellyfin

6.1 下载完成后的自动处理脚本

#!/usr/bin/env python3
"""
下载完成后的自动处理:移动到 Jellyfin 媒体目录并通知刷新
"""
import os
import shutil
import requests
from pathlib import Path

JELLYFIN_API_KEY = 'your_api_key_here'
JELLYFIN_URL = 'http://localhost:8096'
MEDIA_ROOT = '/media'


def move_to_jellyfin(filepath, source='Unknown'):
    """将下载完成的视频移动到 Jellyfin 媒体目录"""
    filepath = Path(filepath)
    source_dir = MEDIA_ROOT / 'downloads' / source

    # 按上传者分文件夹
    uploader = extract_uploader(filepath)
    if uploader:
        target_dir = source_dir / uploader
    else:
        target_dir = source_dir / 'Uncategorized'

    target_dir.mkdir(parents=True, exist_ok=True)
    target = target_dir / filepath.name

    # 移动(同盘快,跨盘慢)
    shutil.move(str(filepath), str(target))
    print(f"归档: {filepath.name}{target}")

    return target


def notify_jellyfin_refresh():
    """通知 Jellyfin 刷新媒体库"""
    headers = {
        'X-MediaBrowser-Token': JELLYFIN_API_KEY,
    }

    # 获取所有媒体库
    resp = requests.get(
        f'{JELLYFIN_URL}/Library/VirtualFolders',
        headers=headers
    )
    libraries = resp.json()

    # 触发每个库的扫描
    for lib in libraries:
        lib_id = lib['ItemId']
        requests.post(
            f'{JELLYFIN_URL}/Library/Refresh',
            headers=headers,
            json={'ItemIds': [lib_id]}
        )
        print(f"已触发媒体库刷新: {lib['Name']}")

    return True


def extract_uploader(filepath):
    """从文件名提取上传者"""
    name = filepath.stem
    if ' - ' in name:
        return name.split(' - ')[0]
    return None


# yt-dlp 下载完成后自动调用
# yt-dlp --exec "python jellyfin_auto.py %(filepath)s" URL
if __name__ == '__main__':
    import sys
    if len(sys.argv) > 1:
        downloaded_file = sys.argv[1]
        source = sys.argv[2] if len(sys.argv) > 2 else 'YouTube'

        try:
            new_path = move_to_jellyfin(downloaded_file, source)
            notify_jellyfin_refresh()
            print("自动入库完成")
        except Exception as e:
            print(f"自动入库失败: {e}")

6.2 配合 yt-dlp 使用

# 下载完成后自动执行脚本
yt-dlp \
  --exec "python /scripts/jellyfin_auto.py %(filepath)s YouTube" \
  "https://www.youtube.com/watch?v=xxx"

6.3 定时扫描目录

如果不方便在下载时触发,可以写一个定时任务:

# 用 crontab 每 30 分钟扫描一次
# */30 * * * * python /scripts/jellyfin_scan.py

# jellyfin_scan.py
import os
import time
from pathlib import Path

WATCH_DIR = '/downloads/pending'
MEDIA_DIR = '/media'

while True:
    for file in Path(WATCH_DIR).glob('*.mp4'):
        # 等文件写入完成(大小不再变化)
        size1 = file.stat().st_size
        time.sleep(5)
        size2 = file.stat().st_size

        if size1 == size2:
            move_to_jellyfin(str(file))
            notify_jellyfin_refresh()

    time.sleep(1800)  # 30 分钟

七、多用户与权限管理

Jellyfin 支持多用户,每个用户有独立的观看记录、收藏和"继续观看"列表。

管理员设置:
  控制台 → 用户 → 添加用户

推荐配置:
  - 管理员账户(你):完全控制权
  - 家人账户:可以播放,不能删除/管理
  - 访客账户:只能播放,不记录观看历史

权限设置(每个用户可配置):
  ✅ 允许媒体播放
  ❌ 允许删除媒体(不要给家人这个权限!)
  ❌ 允许管理服务器
  ✅ 允许远程访问(外网)

还可以设置家长控制——根据内容分级限制某些用户能看什么。

八、常见问题排查

问题 原因 解决方案
视频不显示 文件格式不支持或目录权限问题 检查文件扩展名、目录挂载
刮削失败 TMDB 被墙或文件命名不规范 加豆瓣插件、检查命名格式
播放卡顿 服务器在软件转码 启用硬件加速
外网无法访问 端口未转发或 DDNS 失效 检查路由器设置和 DDNS 状态
字幕不显示 字幕文件编码不是 UTF-8 iconv 转码或 Jellyfin 设置中调整
硬件转码不工作 /dev/dri 权限问题 chmod 666 /dev/dri/renderD128
手机端无法播放 HEVC 客户端不支持 在 Jellyfin 设置中启用"允许 HEVC 转码"

九、合规与温馨提示

  • Jellyfin 是一个合法的开源软件,搭建媒体服务器本身不涉及任何法律问题
  • 但服务器上存储的内容必须是你合法拥有的——自己拍摄的视频、购买的 DRM-free 内容、或者已获得版权方授权的素材
  • 与他人分享受版权保护的内容(即使是通过私人服务器)可能构成侵权
  • 使用 DDNS/内网穿透将服务暴露到公网时,注意服务器安全——设置强密码、开启 HTTPS、定期更新系统
  • 更多法律讨论见 下载视频算侵权吗?聊聊个人备份与版权的那条线

搭好 Jellyfin 之后,我第一次在手机上打开自己的视频库,看到那些精心整理的海报墙,心里只有一个感受:早就该弄了。 之前那些散落在各个硬盘里的视频,终于有了一个像样的"家"。而且 Jellyfin 的"继续观看"功能会自动记住你看到哪了——手机上看了一半,打开电视接着看,无缝衔接。这种体验,说真的,比很多视频平台的体验还好。

本文由 VidDown 技术博客原创发布。VidDown 下载器支持 30+ 平台的视频下载,配合 yt-dlp 的 --exec 参数可以实现下载后自动归档到 Jellyfin 媒体库。访问 VidDown 了解更多。

想亲手试试?用 VidDown 一键解析下载

粘贴视频链接即可解析,多平台支持、网页端即用;下载桌面客户端解锁海外平台本地解析,开通会员更享不限次下载。

顶部