侧边栏壁纸
  • 累计撰写 66 篇文章
  • 累计创建 47 个标签
  • 累计收到 111 条评论

目 录CONTENT

文章目录

两种方法解决linux下NFS等网络挂载文件变动不触发inotify,导致jellyfin等无法实时监控

草莓牛奶
2024-04-15 / 0 评论 / 0 点赞 / 154 阅读 / 2,573 字 / 正在检测是否收录...
温馨提示:
「博客文章out of date 会及时更新,无特殊说明仍然有效,欢迎指正内容中的错误」

在使用NFS、SMB、WebDAV等网络文件系统时,一个常见的挑战是这些系统不支持本地inotify机制,这直接影响了媒体服务器如Emby和Jellyfin的实时文件监控功能

由于这些网络挂载无法像本地文件系统那样实时触发文件变更通知,Emby和Jellyfin等服务无法立即响应文件添加、删除或修改事件。这种限制需要通过定期扫描或使用其他工具来触发扫描,以确保媒体库保持更新,但这种方法通常会比实时监控更消耗资源且响应速度较慢。

目前,有两种解决办法,分别是watchertoucher和autoscan。(个人推荐使用watchertoucher

  1. watchertoucher: 这个工具通过在检测到文件变化时,自动在影响的目录中创建或删除一个虚拟文件,从而触发媒体服务器如Jellyfin的扫描机制。这种方法是通过模拟文件变动来间接激活媒体服务器的实时更新。

  2. autoscan: autoscan利用配置的触发器来检测特定事件或通过定时任务来周期性地扫描监控的目录。它可以集成多种外部应用如Sonarr、Radarr等,以实现更灵活和全面的文件变更监测。autoscan支持复杂的路径重写规则和细粒度的控制,适用于多服务器环境。

一、watchertoucher

简介:
pulpul-s/watchertoucher 是一个基于 Python 的监控脚本,它可以监控 CIFS、NFS 等网络文件系统上的文件新建、删除和移动事件,并在相应位置创建或删除一个虚拟文件。这使得 Jellyfin 的 inotify 功能能够响应并扫描库中的变化。虽然这是一种不太理想但有效的方法,以实现 Jellyfin 在网络文件系统上的实时监控。

1.环境准备

兼容性:
至少兼容 Python 3.9 和 Watchdog 3.0.0。(实测最新版python和watchdog同样兼容)

#安装python和pip
apt install python3 pip inotify-tools
#安装watchdog
pip install watchdog
#下载watchertoucher.py
curl -o watchertoucher.py https://raw.githubusercontent.com/pulpul-s/watchertoucher/main/watchertoucher.py
#编辑
nano watchertoucher.py
#赋予权限
chmod +x watchertoucher.py

将watchertoucher.py保存至<path>即可,无特殊要求。

2.设置脚本参数

使用方法:
用户需要在脚本中设置参数,并运行脚本。应该将 folder 变量设置为包含你的媒体文件夹的父文件夹,libraries 作为实际的媒体库文件夹。当检测到指定文件夹中的变化时,系统会在该库的根目录中触摸一个文件以响应变化。

例如,如果设置的 folder/mediaserver/,而 libraries 设置为 “audio”,则它会监控整个 mediaserver 文件夹,但只有当检测到 audio 文件夹中的变化时才会触摸文件。

## 要监视的文件类型
filetypes = [
    "*.mkv",
    "*.mp4",
    "*.avi",
    "*.m4v",
    "*.mov",
    "*.ts",
    "*.vob",
    "*.webm",
    "*.mp3",
    "*.mp2",
    "*.flac",
    "*.m4a",
]

## 监视变化的文件夹(实际媒体库文件夹的父目录)
folder = "/mediaserver/libraries/"

## 监视文件夹中的媒体库(父目录里的文件夹名称)
libraries = ["video", "audio"]

## 虚拟文件名,用于触发更新
touchfile = "watchertoucher.toucher"

## 写入新toucher文件的延迟时间(秒),设置为0以禁用
touchdelay = 10

## 忽略的文件列表,不要从列表中删除触摸文件
ignored_files = [touchfile]

## 是否递归监视文件夹 True/False,不要更改为True
recur = True

## 是否将更改记录到文件 True/False
logging = False

## 日志文件的位置/名称
logfile = "/var/log/watchertoucher.log"

3.设置自启动和重启

[Unit]
Description=watchertoucher service
#在网络连接后和远程文件系统挂载后启动
After=systemd-networkd-wait-online.service <mount-path>.mount

[Service]
#服务失败后自动重启
Restart=always
#服务重启的延迟时间
RestartSec=1
#服务运行的最长时间,超时后会自动重启
RuntimeMaxSec=24h
#务允许使用的最大内存
MemoryMax=64M
#限制CPU占用
CPUQuota=2%
#指定运行服务的用户
User=root
#启动服务的命令
ExecStart=nice -n 15 python3 /home/jellyfin/watchertoucher.py

[Install]
WantedBy=multi-user.target

注意:

  • <mount-path>.mount的具体值可以通过systemctl list-units --type=mount获得
  • 设置定时重启是由于Watchdog ocassionally stops reacting to changes on filesystems · Issue #3
  • 设置MemoryMax由于不设置会占用大量内存;设置CPUQuota由于不设置会占用大量CPU
  • nice -n 15是降低程序的优先级。nice 值的范围从-20(最高优先级)到19(最低优先级)

4.效果检验

#创建test.mp4文件
touch test.mp4

image-20240415191433828

性能优化:
实现了 touchdelay 功能,因此在同一库中一次性移动或保存大量文件时,脚本不会进行不必要的写操作。从触摸文件到 Jellyfin inotify 功能响应并更新大约需要一分钟。将此设置为 59 秒通常是安全的。

在创建test.mp4文件后,经过1min后jellyfin开始刮削元数据!

image-20240415195110737

同样的,在删除文件后,经过1min后完成媒体库的更新!

[19:52:27] [INF] [21] Emby.Server.Implementations.Library.LibraryManager: Removing item, Type: Movie, Name: 试·爱·舞, Path: /data/Movie/test/test.mp4, Id: a8a20900-20ad-e7df-f4a7-45064b7fe199

5.watchdog高占用

参考“kernel:NMI watchdog: BUG: soft lockup”内核软死锁BUG分析和解决

修改watchdog_thresh配置文件,增大看门狗的触发阈值,扩大之后就不容易使系统进入软死锁。

追加到配置文件中:

echo 30 > /proc/sys/kernel/watchdog_thresh 

查看修改结果:

cat /proc/sys/kernel/watchdog_thresh
>>>30

临时生效:

sysctl -w kernel.watchdog_thresh=30
kernel.watchdog_thresh=30

二、autoscan(不推荐)

概述
Cloudbox/autoscan是一款高效的文件变更监控工具,用于替换 Plex 和 Emby 的默认文件监控行为。它与 Sonarr, Radarr, Readarr, Lidarr 及 Google Drive 集成,无需依赖文件系统即可实时获取文件变更。

技术革新
Autoscan 是用 Go 语言重写的原 Plex Autoscan。这次重写采用了更为模块化的设计,便于将来扩展。

功能对比和增强

  • Autoscan 支持 Plex 音乐库,并增加了对 Emby 和 Jellyfin 的支持。
  • Autoscan 能向多个 Plex、Emby 和 Jellyfin 服务器发送扫描请求。
  • Google Drive 集成“A-Train”仅支持共享驱动,并需要服务账户认证。
  • 不支持 RClone Crypt 远端。
  • 连接 Plex 时,Autoscan 不依赖手动删除垃圾文件。建议在 Plex 中重新启用“扫描后自动清空垃圾”设置。

1.docker容器部署

以下以Autoscan 的docker镜像为例,进行部署:

docker run \
  --name=autoscan \
  -e "PUID=1000" \
  -e "PGID=1001" \
  -p 3030:3030 \
  -v "/opt/autoscan:/config" \
  -v "/mnt/unionfs:/mnt/unionfs:ro" \
  --restart=unless-stopped \
  -d cloudb0x/autoscan:latest

以下是参数说明:

参数 功能说明
-p 3030:3030 映射容器内的3030端口到主机的3030端口,用于Autoscan的Webhook触发器。
-e PUID=1000 指定运行Autoscan进程的用户ID(UID)。
-e PGID=1000 指定运行Autoscan进程的组ID(GID)。
-e AUTOSCAN_VERBOSITY=0 设置Autoscan日志的详细级别:0表示信息级别,1为调试级别,2为跟踪级别。
-v /config 挂载Autoscan的配置和数据库文件所在的目录。
-v /mnt/unionfs:ro 以只读方式挂载文件目录,确保容器可以访问但不修改原始数据。

/mnt/unionfs映射的路径,与watchertoucher中的/mediaserver/libraries是一个东西。

2.config文件配置

完整的配置文档详见Cloudbox/autoscan,以下以jellyfin为例进行配置:

# port for Autoscan webhooks to listen on
port: 3030

# 触发器配置
triggers:
  manual:
    - priority: 0
      paths:
        - path: /mnt/unionfs/Media/ # jellyfin服务器的地址
          minimum-age: 5s
          recursive: true #扫描是否应该递归地进行
          include: 
            - '\.(mkv|mp4|avi|m4v|mov|ts|vob|webm|mp3|mp2|flac|m4a)$' #使用正则表达式来包含或排除特定路径或文件类型

# 目标配置
targets:
  jellyfin:
    - url: https://jellyfin.domain.tld # jellyfin服务器的地址
      token: XXXX # Jellyfin API Token
      rewrite:
        - from: /mnt/unionfs/Media/ # 宿主机的媒体库地址
          to: /data/ # jellyfin容器内的媒体库地址

注意:

  • from: /mnt/unionfs/Media/ 指的是你的本地文件系统中的路径,而 to: /data/ 则是 Emby Docker 容器内可以访问的路径。当 Autoscan 检测到 /mnt/unionfs/Media/ 路径下的文件变动时,它会将这些变动的路径转换为 /data/ 路径,以确保 jellyfin容器可以正确地识别和处理这些文件。
  • minimum-age 指定文件变更后多久才开始扫描。这样做可以避免在文件正在被复制或下载时进行扫描,可能的值如 “30s”, “15m”, “1h” 表示秒、分钟、小时。例如,minimum-age: 2m 表示当文件变动后两分钟内不进行扫描,从而确保文件完全写入磁盘。
  • recursive 指定扫描是否应该递归地进行,即是否包括所有子目录。如果设置为 true,Autoscan 会监控指定路径下的所有子文件夹和文件;如果设置为 false,则只监控直接在指定路径下的文件和文件夹。这个设置帮助精确控制扫描范围,避免不必要的系统负担。

3.定时手动扫描

Autoscan 提供了通过http请求手动触发manual,详见Cloudbox/autoscan

比如,设置每五分钟自动触发 Autoscan 扫描的任务:

*/5 * * * * curl --request POST --url 'http://localhost:3030/triggers/manual?dir=%2Fmnt%2Funionfs%2FMedia%2F'

这行命令意味着每五分钟向 Autoscan 的 manual 端点发送一个 POST 请求,请求 Autoscan 扫描 /mnt/unionfs/Media/ 目录。

0

评论区