步骤/目录:
1.背景介绍
    (1)MDC
    (2)Plex
2.MDC的使用
3.EverAver的使用
4.Plex的使用
    (1)XBMCnfoMoviesImporter插件下载
    (2)安装与设置
5.linux + docker安装plex
    (1)docker-compose的编写
    (2)插件与设置
    (3)头像
        a.失败方法一
        b.失败方法二
        c.总结
        d.方法三
        e.方法四
        f.修改nfo标签
    (4)内网穿透
    (5)显卡加速(未实操)
        a.卸载之前的CUDA、驱动
        b.查看显卡是否可用CUDA
        c.安装NCT
        d.安装CRI-O
        e.配置
        f.安装显卡驱动
        g.安装驱动后检查
        h.plex-docker开启硬件加速

本文首发于个人博客https://lisper517.top/index.php/archives/92/,转载请注明出处。
本文的目的是对本地电影文件进行整理,并搭建个人影音库。
本文写作日期为2023年11月30日。用到的系统有win10、Ubuntu 22.04 LTS。

1.背景介绍

Python,爬虫与深度学习(17)——电影的信息爬取、下载与处理(二) 一文中,笔者曾经试图对本地电影文件进行压缩,并通过mysql库管理。压缩视频没有什么问题,但是根据视频文件名进行查询、归类时,由于文件名参差不齐,涉及的爬虫知识又比较复杂,笔者还想对视频内容进行比对,却一直没有好的解决办法。好在互联网上总是有人在做相似的项目,今天介绍的MDC就比较好地满足了这类需求。
在文件管理上,笔者选择用废旧笔记本装linux连硬盘,Samba共享,详情参考 树莓派+Samba+frp搭建NAS(网络云存储) 。当然,树莓派的孱弱性能不太适合装plex,这里用笔记本代替。

(1)MDC

Movie_Data_Capture 刮削软件,项目地址 。可以识别本地视频文件名,到Java网站上查询,下载海报,生成nfo文件(这些工作称为刮削),根据主演名创建文件夹。
其它类似的软件有AVDCMDCx(原作者似乎在23-10-4删库),tinyMediaManager(正常情况下用的最多。这里不用tMM是因为本文主要讨论不正常的情况),EverAver(只能对单部电影刮削)等。

另外,对于英语电影,可以使用tMM + 插件,具体可参考 提供插件的网站 。在该插件网站注册一个账号,右上角获得API,MDCx可填入该API,或者tMM安装插件后也需填入该API。

(2)Plex

plex官网 ,一个功能比较齐全的本地影音库解决方案。在存放电影文件的本地电脑上安装plex media server,只要该本地电脑能联网,就能在外网通过plex的客户端(安卓,苹果,Windows,Mac)或者网页端访问、管理电影文件。当然,在外网看是要花钱充会员的(在局域网内不用钱,所以也可以内网穿透);且plex只能用自带的播放器。其实plex和流媒体有很多相似之处,也能看一些电视、美剧。需要注意的是,plex也可对电影进行识别(文件名,还会对视频内容进行比对),获得海报、生成nfo,但在一些细分领域的识别正确率不高。plex需要使用XBMCnfoMoviesImporter插件才能识别本地的nfo文件,这将在之后讲解。
其它类似的有Jellyfin、Emby(Jellyfin是Emby的开源版本,Jellyfin疑似在文件较多时无法运行),Jvedio(可以用本地播放器,缺点是电影名的.必须改成-)等。plex是目前最成熟的影音管理软件,但是也有其它小问题。

2.MDC的使用

由于涉及爬虫,运行时请确认能够访问外网,最好是日服。可参考 Docker实践——如何查阅wiki百科及V2Ray 或者 Google云的免费使用
MDC发行版 中选择合适的版本进行下载。需要注意MDC最新的版本(7.0.1以后)开始内测,需要付费,有实力的读者可以支持一波。本文使用免费的6.6.7版本(最后一个免费版本)进行演示。
对压缩文件解压,得到config.ini(配置文件)和exe文件。配置文件修改以下几处:

stop_counter = 10
#默认为stop_counter = 0
rerun_delay = 1m
#默认为rerun_delay = 0
[watermark]
switch = 0
#默认为switch = 1
[storyline]
switch = 0
#默认为switch = 1

更多配置选项参考 配置说明 (该6.6.7版本配置说明网页在本文写作的这几天已失效)。
接下来,将ini文件和exe文件放到存放电影的文件夹中(建议先用少量几部电影试验),把V2Ray改为全局模式,运行exe文件,等待一段时间。
如果无法访问日服,MDC可能有些差错,可尝试上文提到的其它软件,推荐MDCx。
第一次试刮削后,可自行更改配置,换其它刮削软件尝试,找到适于自己的软件及设置。

3.EverAver的使用

非常简单,把文件拖拽到软件框中即可。对于少量刮削出错的,使用EverAver单独刮削,或者使用其它软件的单独刮削功能。由于该软件19年后就没有更新过,现在也能用,但不推荐。

4.Plex的使用

(1)XBMCnfoMoviesImporter插件下载

github项目地址中按照最下面的指示操作即可,看不懂英文就看本文接下来的操作。
首先下载XBMCnfoMoviesImporter的zip包,解压并将文件夹改名为 XBMCnfoMoviesImporter.bundle (此时该文件夹下应该有Contents文件夹,不要多套了一层),放到plex的插件目录下(Windows在安装目录的 Plex Media Server\Resources\Plug-ins-xxxxxxxxx 下,参考plex官网帮助)。

如果除了电影,还有看电视剧的需求,可以装 XBMCnfoTVImporter插件 ,作者是同一个人。

(2)安装与设置

没什么特别的,安装即可。安装好后,右下角的任务栏会有plex图标,左键双击可点开网页,注册一个账号登录。在右上角 设置 - 管理 - 媒体库 -添加资料库 可新增电影库,在 高级 - 代理 中注意选择 XBMCnfoMoviesImporter ,plex才能识别本地的nfo文件。

5.linux + docker安装plex

在前文提到过,笔者使用的是 旧笔记本(Ubuntu 22.04)连硬盘+SMB分享 ,所以最好能在Ubuntu上装plex。步骤如下:

(1)docker-compose的编写

在Ubuntu命令行中如下操作:

su root
mkdir -p /docker/plex/conf/plex
ls -l NAS硬盘挂载目录
chown -R 用户名:用户组 /docker/plex/conf
id 用户名

查看NAS硬盘目录所属的用户、用户组,修改目录到该用户及组下,记下uid、gid。

vim /docker/plex/docker-compose.yml

在docker-compose文件中写入如下内容:

version: "3.9"
services:
  plex:
    image: lscr.io/linuxserver/plex:latest
    container_name: plex
    network_mode: host
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - VERSION=docker
      - PLEX_CLAIM= #optional
    volumes:
      - /docker/plex/conf/plex:/config
      - /path/to/tvseries:/tv
      - /path/to/movies:/movies
    restart: unless-stopped

修改 PUIDPGID ;修改 /path/to/tvseries/path/to/movies 分别为存放电视剧、电影的地方,或者随便怎么挂载,这个不是死的。需要注意的是 /config 是存放影音库等配置的地方,影像较多时留50GB的空间比较稳妥(等下也会将XBMCnfoMoviesImporter插件放到这里)。最后需要注意的是, /config 如果挂载到宿主机的机械硬盘上,plex会自动对视频截图作为封面,而不使用MDC刮削的封面,这可能与硬盘读取速度有关,所以 /config 一定要放在固态硬盘上。
最后docker run:

cd /docker/plex
docker-compose config
docker-compose up

等待pull并成功run后,退出并后台运行:

docker-compose up -d

如果设置了防火墙,记得打开32400端口:

ufw allow 32400

(2)插件与设置

插件方面,linux与windows下的插件是通用的。按前文的步骤,把XBMCnfoMoviesImporter.bundle放到 /docker/plex/conf/plex/Library/Application Support/Plex Media Server/Plug-ins 下即可,然后 docker-compose restart 一下。
浏览器访问 笔记本本地ip:32400/web 即可进入plex media server网页。登录账号,跟随引导即可,添加电影库的操作也是一样的(如果在其它电脑上也装过plex,此时注意选择笔记本。此前实验时创建的其它电脑,在设置里可以删除),同样先用一个test文件夹、少量几部电影测试一下。笔者还进行了如下设置:

允许我在家庭外访问我的媒体 取消勾选
启用电影预告片 取消勾选
启用视频预览缩略图 取消勾选
包含相关的额外内容 取消勾选

对XBMCnfoMoviesImporter:

Enable debug logging 勾选上

(3)头像

使用刮削软件生成的nfo文件,其中演员头像也是可以在plex中显示的(比如MDCx生成的nfo,演员头像在 <actor> 标签的
<thumb> 里,是 .actors/演员名.jpg ),但是需要一些操作。先到 gfriends项目 下载别人整理好的演员头像,然后进行一些设置。

a.失败方法一

根据这个提问下提问者的说法,在XBMC插件的设置中,把 actor thumb location 设置为link, path to movie library or global actor folder 不用管,在nfo里把thumb标签改成头像图片的绝对路径。失败,演员头像显示为黑,上面没有演员名的首字。

b.失败方法二

该提问者在后面的回答中提出,把 actor thumb location 设置为global, path to movie library or global actor folder 填存放演员头像的目录(如 /movies/actor_photo ,该目录下存放所有的头像jpg图片)。同样失败,同样显示黑图。
以上两种方法,提问者都是在windows下运行,笔者在linux,可能有影响。

c.总结

另一个问题中提到,存放头像的整个路径上都不能有空格,要用 _ 替代空格。源文件的 __init__.py 负责该设置,从750行的 if athumbloc in ['local','global']: 开始,这里其实有把空格替换成下划线。

plex获得演员头像困难的根源在于它虽然管理本地电影,但核心是围绕线上刮削+本地缓存的,也就是说电影的海报、演员头像都需要从plex提供的数据库获取,缓存到自己的server上,完全没有考虑过server本地提供nfo、海报(不装XBMC插件,根本识别不了本地nfo),也不想让你碰缓存的数据。另一个问题是它会优先用本地缓存的图片,如果你更新了一些图片则它还是会显示以前的图片,解决方法可能是 扫描资料库文件 ,或者删除影音库再重建。

第一个提问中,提问者说头像显示为黑图说明plex已经缓存了图片(显示名字首字母说明没有缓存)。笔者在 /docker/plex/conf/plex 下查找了所有jpg图片,并没有缓存的头像。使用 grep -iR "actor photo" /docker/plex/conf/plex 也没发现有用的log信息(但是在最终的方法中还是找到了有用的log)。有人还提到,nfo里的thumb标签会覆盖掉 actor thumb locationpath to movie library or global actor folder 设置,所以设置成local或者global时要删掉(这个不完全对,笔者设置link+ http://localhost 、thumb标签是 actor/演员名.jpg ,log里发现XBMC把它们拼接成了 http://localhostactor/演员名.jpg )。

d.方法三

有人对XBMC插件进行了修改,名为 JAVnfoMoviesImporter.bundle ,安装方式和原来相同,不同在于它会在线从前面提到的gfriends项目获得演员头像。由于从github上刮削,可能需要翻越。而且gfriends项目作者已经停止更新,一些新人可能没有头像(这个可能性不大,因为还是有人在零散提交)。笔者没有使用这种方法,主要是想在本地存头像,一些演员的头像拍丑了、想用自己的图。

e.方法四

第二个问题的最后,有人提出了另一种解决方案,稍微修改一下 __init__.py ,然后在docker-compose里另建一个nginx容器来提供头像链接;或者也可以不改 __init__.py ,只建nginx容器,笔者尝试也可以。不过改不改py文件,nfo文件都是要修改的。
操作如下:

cd /docker/plex
docker-compose stop
mkdir -p /docker/plex/conf/nginx
chown -R 用户名:用户组 /docker/plex/conf
vim /docker/plex/conf/nginx/default.conf

写入nginx配置:

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /var/www/html;
        index  index.php index.html index.htm;
    }
}

然后修改docker-compose.yml:

vim /docker/plex/docker-compose.yml

修改如下:

version: "3.9"
services:
  plex:
    image: lscr.io/linuxserver/plex:latest
    container_name: plex
    network_mode: host
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - VERSION=docker
      - PLEX_CLAIM= #optional
    volumes:
      - /docker/plex/conf/plex:/config
      - /path/to/tvseries:/tv
      - /path/to/movies:/movies
    restart: unless-stopped

  nginx:
    image: nginx:1.23.1
    ports:
      - "80:80"
    volumes:
      - /docker/plex/conf/nginx:/etc/nginx/conf.d
      - 存放头像的目录:/var/www/html
    logging:
      driver: syslog
    restart: always

如果你已经用了笔记本的80端口,也可以改成其它端口(比如改成9090端口: 9090:80 )。

ufw allow 80
cd /docker/plex
docker-compose config
docker-compose up -d

现在测试一下nginx图片服务器能否正常工作。在浏览器打开 笔记本内网ip/图片名.jpg (或者 笔记本内网ip:9090/图片名.jpg ),应该能看到头像图片。
最后设置一下plex(其实就是保持默认设置), actor thumb location 设置为link, path to movie library or global actor folder 保持为 http://localhost (可以直接删掉并保存,XBMC会自动填充这个值)。
重点是nfo文件里,thumb标签的值,改成 http://localhost/演员名.jpg 即可(如果nginx用的不是80端口,这里应该填 http://localhost:端口号/演员名.jpg )(有些刮削软件填的是 .actors/演员名.jpg ,适用于EMBY等其它影音管理软件)。这时nfo里的thumb标签确实会覆盖掉头像的链接。测试一下,把之前测试的几部电影剪切走,换成其它新的电影,能正常显示演员头像。

最后修改一下nginx的设置,不要把nginx容器的端口暴露到宿主机上。如下操作:

ufw delete allow 80
cd /docker/plex
docker-compose stop
vim /docker/plex/docker-compose.yml

把端口映射删掉,如下:

version: "3.9"
services:
  plex:
    image: lscr.io/linuxserver/plex:latest
    container_name: plex
    network_mode: host
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - VERSION=docker
      - PLEX_CLAIM= #optional
    volumes:
      - /docker/plex/conf/plex:/config
      - /path/to/tvseries:/tv
      - /path/to/movies:/movies
    restart: unless-stopped

  nginx:
    image: nginx:1.23.1
    volumes:
      - /docker/plex/conf/nginx:/etc/nginx/conf.d
      - 存放头像的目录:/var/www/html
    logging:
      driver: syslog
    restart: always

然后删除并重新构建:

docker-compose stop nginx
docker-compose rm nginx
#按y确认
docker-compose config
docker-compose up -d

需要注意的是thumb标签的值稍微有所不同。

docker container ls

其中会有一个 plex-nginx-1 容器(老版本的docker-compose可能是plex_nginx_1或者其它名称)。查看它在容器组合里的ip:

docker inspect plex-nginx-1 | grep IPAddress

比如说是172.22.0.2,那么thumb标签的值就改成 http://172.22.0.2/演员名.jpg 。如果对docker有经验的读者,可能会想改成 http://nginx/演员名.jpg 或者 http://plex-nginx-1/演员名.jpg ,可以进入plex容器来验证:

docker exec -it plex bash
cd /tmp
wget http://nginx/演员名.jpg
wget http://plex-nginx-1/演员名.jpg
wget http://172.22.0.2/演员名.jpg

plex容器自带了wget命令,但最终只有改成ip值才行。

f.修改nfo标签

把所有thumb标签的值从 .actors/演员名.jpg 改成 http://172.22.0.2/演员名.jpg 。使用如下python脚本:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
import os

dir = r'电影存放目录'
content = ''


def main():
    global content
    for dirpath, dirnames, filenames in os.walk(dir):
        for filename in filenames:
            suffix = os.path.splitext(filename)[-1].upper()
            if suffix != '.NFO':
                continue
            abs_path = os.path.join(dir, dirpath, filename)
            with open(abs_path, 'r+', encoding='utf-8') as f:
                content = f.read()
                if content.find(r'<thumb>.actors/') == -1 and content.find(
                        r'<thumb>http://172.22.0.2/') == -1:
                    print(f'没有头像{abs_path}')
                content = content.replace(r'<thumb>.actors/',
                                          r'<thumb>http://172.22.0.2/')
                f.close()
            with open(abs_path, 'w', encoding='utf-8') as f:
                f.write(content)
                f.close()


if __name__ == "__main__":
    main()

每次有新文件,刮削后运行一次即可。

(4)内网穿透

plex在外网访问需要开会员,2023年,费用大约是包月$5、包月$40、永久$120,有需要的可以购买。从学术研究的角度,也可以尝试用内网穿透(前提是有公网ip,像前文提到的Google云服务器),比如用frp,映射笔记本的32400端口即可。可参考 Docker树莓派实践——frp(附dashboard开启https、frp双向验证) ;或者能访问ipv6的,笔者更建议 IPv6 + DDNS (能跑满家里的上传带宽),见 IPv6与DDNS ,这里不再赘述。

(5)显卡加速(未实操)

如果在自己的电脑上观看该电脑上的视频,会使用该电脑的显卡解码;如果用自己的电脑观看云视频,就涉及到在服务器端还是在客户端解码的问题。plex解码笔者不太清楚,按常理来说用手机看最好在服务器端解码(本文为例就是笔记本上解码),用PC就在客户端解码。如果笔记本用的是Nvidia某些型号的显卡,可以用显卡解码,毕竟CPU硬解码还是比较占CPU。笔者测试时,观看720p电影,CPU占用不大( top 命令,或者 watch -d -n 1 cat /usr/local/watchdog/cpu_temperature 看CPU温度),没有开硬件加速的必要。

docker-plexNvidia 小节,提到了开启显卡加速的方法,即先安装 nvidia-docker ,然后运行一个nvidia容器(加 --runtime=nvidia ),plex容器则在yml里写 -e NVIDIA_VISIBLE_DEVICES=all (或者把 all 换成UUID来指定特定显卡。 nvidia-smi --query-gpu=gpu_name,gpu_uuid --format=csv 可查看GPU的UUID)。

可惜的是,截止23年12月,nvidia-docker这个项目已经废弃了,转而被NVIDIA Container Toolkit取代。接下来就演示用NCT为plex开启显卡加速(笔者没有实操)。

a.卸载之前的CUDA、驱动

如果之前装过CUDA,或者在本次流程装CUDA时出现了意外,可以卸载后重装。

根据 Nvidia官方文档 ,执行以下命令:

sudo apt-get --purge remove "*cuda*" "*cublas*" "*cufft*" "*cufile*" "*curand*" \
 "*cusolver*" "*cusparse*" "*gds-tools*" "*npp*" "*nvjpeg*" "nsight*" "*nvvm*"
sudo apt-get --purge remove "*nvidia*" "libxnvctrl*"
sudo apt-get autoremove

b.查看显卡是否可用CUDA

update-pciids
lspci | grep -i nvidia

获取当前的显卡型号,到 NVIDIA官网 比对,是否能开启CUDA。如果不能,就不需要进行接下来的步骤了(没有对应的显卡驱动)。根据官方的 这个回答 ,2008年以后制造的英伟达显卡都支持CUDA(包括笔记本),所以N卡其实可以无脑装。

c.安装NCT

参考 NCT安装官方指南
为笔记本开启翻越,进行如下操作(Ubuntu下。其它发行版参考原文):

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

可以更新一些实验性功能包,一般情况下没必要。

sed -i -e '/experimental/ s/^#//g' /etc/apt/sources.list.d/nvidia-container-toolkit.list

安装即可。

apt-get update
apt-get install -y nvidia-container-toolkit

d.安装CRI-O

接下来需要用到CRI-O,不太清楚是什么东西,好像是docker的某种替代或者补充,笔者还没装过。安装CRI-O(参考 这篇文章 ):

apt update
apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y
export OS=xUbuntu_22.04
export CRIO_VERSION=1.24
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /"| sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$CRIO_VERSION/$OS/ /"|sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION.list
curl -L https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable:cri-o:$CRIO_VERSION/$OS/Release.key | sudo apt-key add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key add -
apt update
apt install cri-o cri-o-runc -y
systemctl start crio
systemctl enable crio
systemctl status crio

参考文章后面还有一些附加的内容,这里没有继续。

e.配置

第一个配置会调整宿主机的 /etc/docker/daemon.json 文件,使得docker可以使用NVIDIA Container Runtime。

nvidia-ctk runtime configure --runtime=docker
systemctl restart docker

第二个配置会调整 /etc/containerd/config.toml 文件,使得containerd可以使用NVIDIA Container Runtime。

nvidia-ctk runtime configure --runtime=containerd
systemctl restart containerd

第三个配置调整 /etc/crio/crio.conf 文件,使得CRI-O可以使用NVIDIA Container Runtime。

nvidia-ctk runtime configure --runtime=crio
systemctl restart crio

f.安装显卡驱动

参考 官网文章

apt-get install linux-headers-$(uname -r)
distribution=$(. /etc/os-release;echo $ID$VERSION_ID | sed -e 's/\.//g')
wget https://developer.download.nvidia.com/compute/cuda/repos/$distribution/x86_64/cuda-keyring_1.0-1_all.deb
dpkg -i cuda-keyring_1.0-1_all.deb
apt-get update
apt-get -y install cuda-drivers

这个是通过包管理安装,没有 /usr/local/cuda-版本号/nvcc

g.安装驱动后检查

参考 官方说明

h.plex-docker开启硬件加速

运行一个CUDA容器(这里笔者不是很确定):

docker run --runtime=nvidia --gpus all ubuntu nvidia-smi

在plex-docker的docker-compose.yml中增加环境参数: -e NVIDIA_VISIBLE_DEVICES=all ,重新build即可。

标签: docker, MDC, plex

添加新评论