分享一些优化观影体验的工具们

年初把自己的观影记录从豆瓣切换到了 Trakt1,不知不觉 Trakt 标记的电影和剧也有接近 80,豆瓣之前标记的有 1400+,算下来总共差不多 1500 了。

一方面感叹自己还是爱电影的,另一方面也意识到为了更好地看电影,之前折腾了一些工具,做个总结吧。

受限于很多因素,生活中没有办法用正常途径获取一些影视作品。但是也不能传播盗版,所以这篇文章也就不涉及具体的资源获取途径了。

1. 影视资源的追踪

人生苦短,时间还是要用来看点自己中意的作品,可以参考 Upcoming Anticipated Movies,留意上线时间。

部分网站会有 RSS 提供订阅,比如一些动漫在字幕组压制好之后提供每一个 episode 的更新,浏览器搭配 RssHub 订阅就好了。

但是更常见的情况是,部分网站并没有 RSS,为了避免人工轮询,我们可以用 Change Detection,指定一个 URL 和对应的 HTML Element,可以定时检查是否有变化。比如在某个网站内,可以指定搜索关键字为「Vyndros Mandalorian」,搜索结果按时间降序排列,CSS Selector 筛选结果列表的第一项,每天检查一次在变更的时候触发 Telegram Bot 的通知。

值得一提的是,Change Detection 不光支持普通的 HTTP 请求,还支持 WebDrive Chrome,即使在树莓派上用 Docker Compose 搭建性能也完全够用了。

2. 下载工具

磁力下载中,影响速度的一个最重要因素是 tracker,会决定能连接到的 peer 的数量。

可以使用 Aria2 Pro,后台内置了定时更新 tracker 的脚本和 AriaNg 的 WebUI。

3. 规范命名

规范的命名能够让 Server 更容易地识别作品,抓取到正确的元数据,标题、海报、演员等。

最常用的工具是 FileBot,但是曾经的开源软件删除了 license 和 repo 变闭源了,我们可以用之前开源的 fork 版本 FB-Mod

不足之处是这是一个 GUI 的桌面应用,尝试过其他几个命令行的重命名工具,都并不好用。

4. Media Server

曾经是 Plex 的用户,Plex Pass 相比于普通版多了服务器的硬件加速支持,代价是 120 刀的一次性终身会员费用。 因为 Plex 对于 Trakt 的支持欠佳,后来切换到了 Jellyfin。 不得不说 Plex 作为商业化的产品,使用体验其实是更优秀的,但是因为产品打磨得比较好,对于 nerd 来说又缺了一点自由度,没有折腾的空间啊。

Jellyfin 是 Emby 的开源 fork,因为后者曾经作为开源项目,却最终选择了闭源,社区基于当时的开源分支继续开发 Jellyfin。

推荐使用 LinuxServer 构建的 Jellyfin,相比于原版会多一些 mod,以及硬件加速更清晰的文档。注意的问题:

  1. 需要在 ./config/fonts 目录下配置中文的 woff2 字体,否则 ssa 字幕无法渲染。

  2. Jellyfin 会给电影和剧生成封面,同时封面中包含汉字「电影」「节目」,但是 Ubuntu 的 base image 又没有安装中文字体,导致只能显示方框。需要手动安装 CJK 字体,fonts-noto-cjk 只包含了 regular 和 bold 字重,而 fonts-noto-cjk-extra 是全字重。

    1docker exec -it jellyfin bash
    2
    3apt update
    4apt install fonts-noto-cjk-extra
    
  3. Transcode 缓存没能及时清理,有时候甚至会导致 Jellyfin 挂掉,目前好像只能进入 ./config/data/transcodes 手动 rm -rf ./* 😊

    可以 follow 这个 Issue: Set limit for transcode cache

5. 字幕同步

对于日语和其它小语种,字幕可以说是必需的,但是字幕和片源往往不能完全匹配,这时候手动调节 offset 会非常繁琐。

可以使用 ffsubsync,使用起来也很简单:

1ffs YOUR_MOVIE.mkv -i ORIGINAL_SUBTITLE.srt -o SYNCED_SUBTITLE.srt

为了能少敲几个字符,我在 zshenv 中定义了 function:

1ffss () {
2	ffs $1 -i $2 -o $2
3}

之后就可以 'ffss MOVIE.mkv SUBTITLE.srt',字幕直接原地修改了。但是这仍然不够方便,如果是一部日剧,往往要对每一个 eposide 执行一次,能不能再方便一点呢?当然可以!

 1function syncSub() {
 2    targetDir="$1" vExt="$2" subExt="$3"
 3    
 4    cd "$targetDir" || exit 1
 5    
 6    for videoFile in *."$vExt"; do
 7        baseName="${videoFile%.$vExt}"
 8        subName="$baseName.$subExt"
 9        
10        if [[ -f $subName ]]; then
11            ffss "$videoFile" "$subName"
12        fi
13    done
14}

在每个 eposide 和 subtitle 命名规范的前提下,指定文件夹(甚至一次多个文件夹)、视频拓展名、字幕拓展名,就可以批量同步了。

ffsubsync 的原理大概是对 audio 和 subtitle 做了切分,每一小段有 2 种状态:有声音或者没有声音,那么这就是两个数组最大重叠区域的问题了。暴力做法需要 O(n^2) 的复杂度,这里的 n 对应视频的长度,可以想象这绝对太耗时了。使用快速傅里叶变换,居然可以优化到 O(nlogn)!

6. 记录同步

Trakt 官方对 Plex 平台提供了 Plex Trakt Scrobbler,但是只对 Trakt VIP 会员开放。

好在 Jellyfin 有 Trakt 的插件 Trakt for Jellyfin Plugin,简单地配置一下,就可以同步影视的收集和观看记录了。


  1. 所以在这么巨大的沉没成本下,为什么要迁移平台呢? 主要原因是豆瓣每次都依赖手动地标记,会比较累; 最主要的原因是,发现消失的电影越来越多啦~ 🙃 ↩︎