最近捡了一个 1L 小主机, 目前装上了 Ubuntu 22.04, 打算把这个小东西当作家庭服务器用起来. 玩这个当然少不了搭建一套私有影音系统啦, 于是在网上找解决方案, 自然而然地搭起了一套 Jellyfin 环境, 然后就开始踩坑了:). 在了解了什么是刮削、怎么刮削、为什么要用刮削器之后很自然地就去看 TMM 这东西, 然后发现它新版 (v4) 收费 (不吐槽收费, 只是我觉得我没必要用, 而且我也不想为了规避收费就用老版). 再一个就是谁家服务器跑 GUI 呢? TMM 有 CLI 但好像是从 v4 才开始支持的? 具体没有细看, 最后想了想手动刮削还是太折腾. 那么能不能用 Jellyfin 自带的刮削器呢? 让它定期自动扫描自动刮削? 瞄了一眼 Jellyfin 的配置, 默认装的插件就有 IMDB、TVDB 等站点的元数据匹配功能, 只是由于懂得都懂的原因连不上这些 API 而已. 那么解决思路就很清晰了: 使用魔 (ke) 法 (xue), 给 Jellyfin 上代理 buff. Jellyfin 配置代理首先安装是通过 官方文档 进行的, 没有选择 docker 容器的方式进行安装, 而是直接安装在系统级作为一个 service: Once installed, Jellyfin will be running as a service. Manage it with sudo systemctl {action} jellyfin.service or sudo service jellyfin {action}. 由于 Jellyfin 是不支持在管理页面的网络设置里直接配代理的, 根据 这个 issus 我们知道 Jellyfin 支持 http_proxy 和 https_proxy 这两个环境变量, 那解决思路就很清晰了: 获取一个代理服务器; 给 Jellyfin 配上这两个环境变量, 指向代理服务器的 [地址:端口] 就可以了. 代理服务器我用本机 (和 Jellyfin 进程运行在同一个系统上), 代理软件选的是 Clash, 端口: 12333. 系统级环境变量 (❌) ☹️开发组在那个关于代理的 issue 是这么说的: I think it can already be done by setting environment variables http_proxy and https_proxy, at least on Linux. Not sure we need to add support for this in the server itself. 最开始我误解了这个答案, 以为直接提供系统级环境变量就可以了, 但是不管是修改 /etc/environment 还是 /etc/profile (/etc/profile.d), 亦或是修改 non-login shell 的 rc 配置文件 (如: /etc/bashrc), 配置对 Jellyfin 均无效, 但是它们都可以在对应的环境中生效 (login / non-login shell 环境都测试过, 没有问题), 测试方式就是直接 curl , 有回应即说明代理生效. 最后回过神来, Jellyfin 是由 systemd 管理的一个 service, systemd 环境变量的配置是不依赖任何外部环境的, 包括 /etc/environment、login / non-login shell 环境配置文件等. 那么就要换一个思路: 给 systemd service 单独设置环境变量. Systemd 环境变量 (✔️) 😄经过查阅资料, 我了解到 systemd 环境变量有两种类型: 适用于所有 services; 适用于单个 service. 配置所有的 services适配于所有 services 的环境变量原理是修改 systemd 的配置文件: /etc/systemd/system.conf, 修改 DefaultEnvironment= 这一条目就可以为所有 services 指定默认的环境变量, 具体可以看这个 post, 我的原则是能不改配置文件就不改, 于是采取头疼医头, 脚疼医脚的策略, 单独配置 Jellyfin 这个 service. 单独配置某个 service使用 systemctl edit {service} 即可编辑某个 service, 如: sudo systemctl edit jellyfin.service执行之后会看唤起编辑器 (我这里是 nano), 看到这样的显示: ### Editing /etc/systemd/system/jellyfin.service.d/override.conf ### Anything between here and the comment below will become the new contents of the file ### Lines below this comment will be discarded按照注释的提示在两块注释之间写的内容会被保留下来, 本文只关注环境变量的配置, 其他配置的修改请自行查阅文档. Environment 写法很简单, 直接用赋值即可, 可以出现多个 Environment = , 例如: [Service] Environment = "http_proxy=127.0.0.1:12333" Environment = "https_proxy=127.0.0.1:12333" EnvironmentFile 写法这种写法是指定一个外部文件作为环境变量的内容, 可以使 service 配置和环境变量配置解耦, 具体可以参阅一下 Jellyfin 的默认 service 配置, 它用的就是这种写法. 同理, 也可以出现多个 EnvironmentFile = , 比如我们写一个外部配置: [Service] EnvironmentFile = /etc/default/jellyfin_proxy.env文件 /etc/default/jellyfin_proxy.env 内容如下: http_proxy=127.0.0.1:12333 https_proxy=127.0.0.1:12333效果和直接设定 Environment 是一样的. 最后我们要保存的内容就是: ### Editing /etc/systemd/system/jellyfin.service.d/override.conf ### Anything between here and the comment below will become the new contents of the file [Service] Environment = "http_proxy=127.0.0.1:12333" Environment = "https_proxy=127.0.0.1:12333" ### Lines below this comment will be discarded或者是 (别忘了创建对应的外部配置文件): ### Editing /etc/systemd/system/jellyfin.service.d/override.conf ### Anything between here and the comment below will become the new contents of the file [Service] EnvironmentFile = /etc/default/jellyfin_proxy.env ### Lines below this comment will be discarded编辑 && 保存完成后, 我们让 systemd 重新载入一下它的守护进程, 并重启 Jellyfin service: sudo systemctl daemon-reload && sudo systemctl restart jellyfin.service 结果验证我们先通过 sudo systemctl status jellyfin.service 查看 service 状态, 得到以下输出: ● jellyfin.service - Jellyfin Media Server Loaded: loaded (/lib/systemd/system/jellyfin.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/jellyfin.service.d └─override.conf Active: active (running) since Sun 2023-02-12 21:36:54 CST; 2min 6s ago Main PID: 519127 (jellyfin) Tasks: 15 (limit: 38223) Memory: 81.9M CPU: 6.216s CGroup: /system.slice/jellyfin.service └─519127 /usr/bin/jellyfin --webdir=/usr/share/jellyfin/web --restartpath=/usr/lib/jellyfin/restart.sh --ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg可以看到输出这里的 Drop-In 部分包含了一个文件: /etc/systemd/system/jellyfin.service.d/override.conf, 这个文件实际上是我们刚刚编辑保存的, systemd 自动在它的管理路径里创建了这个文件, 以后我们可以直接对这个文件进行更改, 保存后也是一样先让 systemd 重新载入一下它的守护进程, 并重启对应的 service 即可以完成更改. 这个 Drop-In 的原理可以理解为运行时合入, 它会在 service 启动时将其默认的配置文件和 override.conf 动态合并并作为 service 运行时的新配置, 这样就可以在不改变 service 默认配置的情况下为 service 提供额外的配置. 我个人更喜欢这种方式而不是改变 systemd 的配置以此来让所有 services 拥有同样的默认环境, 因为它不用修改原来的配置文件, 在软件更新的时候 (无论是 systemd 还是 service 更新) 不用考虑上游的配置文件覆盖本地的问题. 双重验证: 对待问题应该要有刨根究底的态度, 我们到底解决了这个问题没有? 显示 Drop-In 就说明环境变量真的生效了么? 回答这两个问题我们可以直接查看 Jellyfin 对应进程的运行时环境变量, 使用如下命令: cat /proc/519127/environ | tr '\0' '\n' | grep http其中 519127 是我们刚才通过 systemd 获取到的 Jellyfin 进程的 PID, 输出如下: http_proxy=127.0.0.1:12333 https_proxy=127.0.0.1:12333这下我们就可以放心了, 环境变量设置成功, 经过后续测试 Jellyfin 元数据刮削就一切正常了. PS: Jellyfin 有个坑点, 至少对于我测试的两个地址: 一个是环回地址 (127.0.0.1), 一个是局域网地址 (192.168.68.198, 使用局域网的另一台设备做代理服务器) 来说, 设置环境变量时不能加上协议头 ( 或 https://), 否则就算设置成功也不会生效, 不清楚是不是 Jellyfin 的玄学 bug, 亦或者说是神奇 feature 😑. 所以上文写的都是没有加协议头的配置, 可以走代理并正常工作, 加了即使设置成功, 在 Jellyfin 里也无效 (然而在其他环境这两个环境变量的协议头是可加可不加的, 不影响). (责任编辑:) |