Leaving Soon背后:Janitorr符号链接与PathStructure路径结构实现原理
2026/8/23 16:44:31 网站建设 项目流程

Leaving Soon背后:Janitorr符号链接与PathStructure路径结构实现原理

【免费下载链接】janitorrCleans your Radarr, Sonarr, Jellyseerr and Jellyfin before you run out of space项目地址: https://gitcode.com/gh_mirrors/ja/janitorr

Janitorr是一款自动清理 Radarr、Sonarr、Jellyseerr 与 Jellyfin 媒体库的开源工具,它最著名的功能"Leaving Soon(即将删除)"会在文件被真正删除前,把待清理的媒体集中展示在媒体服务器首页,给用户一个反悔的机会。本文带你从符号链接和 PathStructure 路径结构这两个核心机制出发,读懂这套"删除前预告"功能是如何实现的。

一、Leaving Soon:删除前的"最后一眼"

普通清理工具的做法是:文件一到期就直接删掉。Janitorr 则多走了一步——

  • 距离删除还有 N 天(默认 14 天)时,Janitorr 会把这些媒体加入一个名为Leaving Soon的媒体库;
  • 这个媒体库会出现在 Jellyfin/Emby 的首页,像一个"下架预告"橱窗;
  • 到期且磁盘空间确实不足时,文件才被真正删除。

橱窗里的内容并不是把几百 GB 的影片复制一份,而是符号链接(symlink)——指向原始文件的"快捷方式"。这就是本文要拆解的第一个原理。

相关行为开关:LeavingSoonType.kt 中的枚举决定了 Leaving Soon 橱窗对电影、剧集还是两者同时生效。

二、符号链接:零成本"上架"媒体

符号链接是操作系统中的快捷方式:一个几十字节的链接文件,指向磁盘上真实存在的媒体文件。Jellyfin 扫描到链接后,会像展示真实文件一样展示它(海报、详情照常可用),但不占用额外磁盘空间

Janitorr 的链接创建逻辑在 AbstractMediaServerService.kt 的createLinks方法中,处理分两条路:

  • 电影:为单个电影文件创建一条符号链接,并复制字幕等附加文件;
  • 剧集:以"季"为单位,扫描原始季文件夹中的全部视频文件,逐一在目标目录建立链接——这样即使整季文件后续有变动,橱窗内容也能保持完整。

创建前先检查目标是否已存在(Files.exists),已存在则跳过,因此同一轮任务重复执行不会产生重复链接。

这里有一个隐藏的前提:Janitorr 容器必须能"看到"和 Radarr/Sonarr 完全一致的目录结构。例如 Radarr 在/data/media/movies找到电影,Janitorr 也必须能在/data/media/movies访问到它——否则链接会指向一个不存在的位置。唯一例外是 Leaving Soon 目录本身,它允许 Janitorr 和 Jellyfin 用不同路径认识它(后面配置部分会讲)。

三、PathStructure:四个路径撑起一套映射

"从哪链接到哪"是整个功能的核心。Janitorr 用了一个只有 4 个字段的轻量数据类来表达完整的映射关系——PathStructure.kt:

字段含义示例
sourceFolder源文件所在目录(*arr 库内真实位置)/data/media/tv/Seinfeld/Season 05
sourceFile源文件(或季文件夹)本身.../Season 05/Seinfeld.S05E01.mkv
targetFolderLeaving Soon 内的目标目录/data/media/leaving-soon/tv/tag-based/Seinfeld/Season 05
targetFileLeaving Soon 内的目标链接.../Season 05/Seinfeld.S05E01.mkv

这四个字段由 pathStructure 方法 从每个媒体条目(LibraryItem)计算而来。

路径是从哪来的?

输入来自 LibraryItem.kt 中的三个关键路径(均由 Radarr/Sonarr API 提供):

  • rootFolderPath:媒体库根目录,如/data/media/tv
  • parentPath:节目/电影本身的位置,如/data/media/tv/Seinfeld
  • filePath:文件真实所在的完整路径(可能包含任意多层子文件夹)。

一个巧妙的细节:重复文件夹去重

计算路径时,Janitorr 会检测"文件夹名与文件名重复"的情况(例如.../Movie 2013/Movie 2013.mkv)。若源结构是ShowName/ShowName-E01.mkv这种"文件夹名与文件名前缀撞车"的嵌套,它会通过removePath辅助方法剔除多余层级,避免在 Leaving Soon 里生成一层无意义的重复目录。这个"子序列剔除"算法实现在 StringExtensions.kt 的removeSubsequence中。

四、从计算到上架:一次 updateLeavingSoon 的完整旅程

真正把这些拼起来的是 BaseMediaServerService.kt 中的updateLeavingSoon方法,流程可以概括为 5 步:

  1. 门禁检查:未开启文件系统访问,或 Leaving Soon 类型与当前媒体类型不匹配时直接返回;
  2. 构建双路径:为 Janitorr 与媒体服务器各算一份目标路径——/leaving-soon/{tv|movies}/{cleanup-type},并处理 Windows 路径的特殊写法;
  3. 准备媒体库:在 Jellyfin/Emby 中查找对应的 Leaving Soon 媒体库,不存在就创建,路径未挂载就补挂载;
  4. 重建或增量更新:根据from-scratch配置决定是清空目录重建(顺便清除孤儿数据)还是增量补充链接;
  5. 建链接 + 留痕:调用createLinks建立符号链接,并放置一个empty-file.media空文件——因为 Jellyfin 在媒体库被清空后不会主动重新扫描,这个空文件就是保证它"还有东西可看"的保险。

五、部署时的路径配置:一处最容易踩的坑

前面提到,Leaving Soon 目录是唯一允许两边路径不一致的目录。对应配置在 FileSystemProperties.kt 中定义,示例见 application-template.yml:

  • leaving-soon-dir:Janitorr 认识的目录(符号链接建在这里);
  • media-server-leaving-soon-dir:告诉 Jellyfin/Emby 去哪找这个目录(若与上者相同可省略)。

举例:如果你的 Docker 映射是 Janitorr 侧/share_media/media/leaving-soon → /data/media/leaving-soon,而 Jellyfin 侧映射为→ /library/leaving-soon,那么两个配置项就要分别写/data/media/leaving-soon/library/leaving-soon。而媒体库本身的映射必须两边完全一致,这是符号链接机制成立的前提。

六、小结

Leaving Soon 功能的设计非常"克制",却把几件小事做到了位:

  • 符号链接代替文件复制,让"预告橱窗"几乎零磁盘开销;
  • 用一个4 字段 PathStructure把"源位置 → 目标位置"的映射讲得清清楚楚,电影与剧集各走一套建链策略;
  • 通过双路径配置优雅化解了容器映射不一致这个最常见的部署坑;
  • empty-file.media这类小细节保证了媒体服务器的扫描机制持续工作。

对自组媒体库的用户来说,理解这套机制后你就能明白:Leaving Soon 展示的每一张海报背后,都只是几十字节的链接——而链接指向的,才是你硬盘上真正的电影与剧集。

【免费下载链接】janitorrCleans your Radarr, Sonarr, Jellyseerr and Jellyfin before you run out of space项目地址: https://gitcode.com/gh_mirrors/ja/janitorr

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询