尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Immich 外部库(External Libraries)完全实战指南:导入路径、排除模式与文件系统监控

Immich 外部库(External Libraries)完全实战指南:导入路径、排除模式与文件系统监控 Immich 外部库External Libraries完全实战指南导入路径、排除模式与文件系统监控【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immichImmich 的外部库功能让你把散落在 Immich 存储目录之外的照片和视频NAS 目录、老照片文件夹、家庭视频等纳入统一管理它们会出现在时间线、地图和相册中行为与普通资产一致。本文基于 外部库官方文档 展开结合服务端源码逐层剖析导入路径校验、排除模式glob匹配、文件监控watcher与夜间扫描任务的完整实现帮你不仅会用还知道它为什么这样工作。外部库是什么边界在哪里外部库追踪存储在 Immich 文件系统之外外部的资产。当外部库被扫描时Immich 会从磁盘加载视频和照片并创建对应的资产记录之后这些资产会显示在主时间线中看起来、用起来和任何普通资产一样——包括在地图上查看、加入相册等。文件在 Immich 之外被修改后需要重新扫描库才能让变更生效。几个必须牢记的关键边界均直接来自官方文档单一属主当前一个外部库只能属于一个用户该用户在库创建时选定此后不可更改删除文件的去向如果外部资产在磁盘上被删除重新扫描时 Immich 会将其移入回收站。要恢复资产需先恢复原始文件30 天后文件会从回收站移除Immich 内对该资产做过的所有元数据变更都会丢失这与系统配置中回收站默认days: 30一致见 config.dto.ts 中trash.days的默认值元数据不会写回外部文件无论以何种方式给外部资产添加元数据加入相册、编辑描述等这些元数据只存储在 Immich 内部不会持久化到外部资产文件。如果资产在库内被移动到另一个位置重新扫描时所有此类元数据都会丢失——因为移动后该资产被视为新资产。这是已知问题官方说明将在未来版本修复缓存导致的延迟显示由于激进的缓存机制刷新后的资产可能无法立即在 Web 视图中正确显示需要清理浏览器缓存。在 Chrome 中按 F12 打开开发者工具按 F5 重新加载再右键点击重新加载按钮选择 “Empty Cache and Hard Reload”。这也是已知问题。导入路径Import Paths扫描什么、如何校验外部库使用导入路径来决定扫描哪些文件。每个库可以有多个导入路径以便把不同位置的文件加入同一个库。导入路径会被递归扫描如果同一文件出现在多个导入路径中它只会被添加一次。每个导入路径必须是一个存在于文件系统上且可读的目录导入路径对话框会提示任何不可访问的路径。如果编辑导入路径导致某个外部文件不再位于任何导入路径中它会被按“文件已删除”的方式从库中移除。如果文件被移回某个导入路径则会像新文件一样被重新添加。从源码看导入路径的校验逻辑集中在 LibraryService.validateImportPath其检查顺序为不能指向 Immich 的媒体上传目录StorageCore.isImmichPath否则报错 “Cannot use media upload folder for external libraries”必须是绝对路径否则提示 “Import path must be absolute” 并给出解析后的建议路径路径必须存在且是目录stat失败时区分ENOENT等错误并给出可读消息;必须具有读权限R_OK检查否则报 “Lacking read permission for folder”。这正是文档中“导入路径对话框会提示不可访问路径”的底层实现库创建或更新时所有导入路径都会先经过 validate 逐条验证。排除模式Exclusion Patterns用 glob 过滤不想要的文件默认情况下导入路径中的所有文件都会被加入库。若某些文件不应被导入可以使用排除模式。排除模式是与完整文件路径匹配的 glob 模式匹配的文件不会被加入库。排除模式可以在每个库的扫描设置页面中添加。文档给出的基本示例可直接照抄使用**/*.tif排除所有.tif扩展名的文件**/hidden.jpg排除所有名为hidden.jpg的文件**/Raw/**排除任何名为Raw的目录中的所有文件**/*.{tif,jpg}排除.tif或.jpg扩展名的所有文件通配符语义需要注意*匹配零个或多个字符仅限文件名或单个目录名内**递归匹配零个或多个子目录且当**出现在模式末尾时它包含子目录中的任何/所有文件。例如**/exclude_me/**会排除任何名为exclude_me的目录及其所有子目录中的全部文件。特殊字符需要转义例如**/\eaDir/**排除任何名为eaDir的目录中的所有文件官方说明还指出Immich 内部用 glob 包处理排除模式某些场景下模式会被翻译成 Postgres LIKE 模式。设计意图是支持基础的目录排除不建议高级用法因为复杂 glob 无法可靠地翻译成 Postgres 语法。源码层面有两条补充证据值得知道新建库时系统会自动注入一组默认排除模式覆盖 Synology#recycle、#snapshot、群晖/威联通eaDir、macOS._*、.stversions、.stfolder等 NAS 系统文件见 LibraryService.create文件监控器构建匹配器时用picomatch以库的exclusionPatterns作为ignore列表只对支持的文件扩展名做匹配见 library.service.ts。实战把现有图库接入 Immich下面完整复现文档中的示例场景。假设你有以下目录要接入/home/user/old-pics童年照片文件夹/mnt/nas/christmas-trip圣诞旅行照片其中子目录/mnt/nas/christmas-trip/Raw是单反相机原始文件不希望导入/mnt/media/videos同一次旅行的视频。规划思路圣诞照片因为要排除 Raw 文件应独立成库视频和老照片可以放在同一个库里因为没有匹配排除模式的文件若其他文件夹中没有需要排除的文件也可以把三个目录都放进同一个库。第一步挂载 Docker 卷immich-server容器需要能访问这些目录。修改 docker compose 文件可对照仓库中的 docker/docker-compose.ymlimmich-server: volumes: - ${UPLOAD_LOCATION}:/data - /mnt/nas/christmas-trip:/mnt/media/christmas-trip:ro - /home/user/old-pics:/mnt/media/old-pics:ro - /mnt/media/videos:/mnt/media/videos:ro - /mnt/media/videos2:/mnt/media/videos2 # WARNING: Immich will be able to delete the files in this folder, as it does not end with :ro - C:/Users/user_name/Desktop/my media:/mnt/media/my-media:ro # import path in Windows system.要点末尾的ro标志只授予卷只读访问禁止在 Web UI 中删除这些图片、向库写入元数据如 XMP sidecars修改后必须运行docker compose up -d使变更生效并确认容器内能看到挂载路径注意 Windows 宿主机的导入路径写法带引号的C:/...形式。第二步创建库并配置排除模式以下操作必须由 Immich 管理员执行。创建“Christmas Trip”库点击右上角头像点击Administration - External Libraries点击Create Library选择拥有该库的用户之后不可更改进入库管理页面后点击Folders区域的Add输入/mnt/media/christmas-trip点击 Add点击EditLibrary将其重命名为 “Christmas Trip”。注意这里必须使用容器内看到的路径/mnt/media/christmas-trip而不是宿主机路径/mnt/nas/christmas-trip——所有路径都必须是 Docker 容器视角下的路径。接着添加排除模式过滤 Raw 文件点击Exclusion Patterns区域的Add输入**/Raw/**点击 Add点击Scan。此时圣诞旅行库将在后台开始扫描。趁此期间创建第二个库回到Administration - External Libraries点击Create Library选择属主用户在Folders区域Add/mnt/media/old-pics再次Add/mnt/media/videos点击Scan点击EditLibrary重命名为 “Old videos and photos”。几秒钟内old-pics 和 videos 文件夹中的资产就会出现在主时间线中。扫描的底层机制从磁盘遍历到资产同步理解扫描的内部流程能解释很多“为什么”。从 library.service.ts 的源码结构看一次库扫描queueScan会依次入队两类任务LibrarySyncFilesQueueAll新文件导入先逐条验证导入路径见上文的validateImportPath再用 storage.repository.ts 中的walk递归遍历磁盘、套用排除模式按分页批次把“尚未入库的外部资产路径”筛选出来filterNewExternalAssetPaths为每批新文件入队LibrarySyncFiles任务。每个新文件经 processEntity 生成资产记录originalPath记录绝对路径、isExternal: true、文件修改时间取自磁盘mtime、类型按扩展名判断视频/图片随后批量建库记录并触发SidecarCheckXMP 侧车发现进而做元数据提取LibrarySyncAssetsQueueAll存量资产对账先用detectOfflineExternalAssets把不在任何导入路径内、或被排除模式命中的资产标记为离线再对剩余资产分批入队LibrarySyncAssets。checkExistingAsset 决定每个资产的命运磁盘上找不到文件 → 标记离线对应文档中“磁盘删除后移入回收站”文件mtime变化 → 触发元数据重新提取之前离线的资产重新回到导入路径且不被排除 → 恢复在线。这也解释了文档中的两个行为细节排除模式是“按完整路径 glob 匹配”的且同一文件出现在多个导入路径只会被添加一次数据库侧按libraryId originalPath去重。相关行为在 library.service.spec.ts 与 library.repository.ts 中有对应测试与实现可查。自动监控Automatic Watching实验特性该功能面向高级用户官方明确标注为实验性EXPERIMENTAL启用后 Immich 会自动监听文件系统新资产无需重新扫描即可自动导入。如果你的照片在网络驱动器上自动文件监听大概率不工作此时需要依赖周期性库刷新见下文“自定义扫描间隔”来拉取变更。源码印证监控通过 StorageRepository.watch 封装的 chokidar 实现library.service.ts 中配置了usePolling: false、ignoreInitial: true以及awaitWriteFinishstabilityThreshold: 5000毫秒、pollInterval: 1000毫秒——即文件写完并稳定 5 秒后才触发导入任务避免读到写了一半的文件。另外只有抢到DatabaseLock.Library数据库锁的那一个微服务实例才会启动监控保证多副本部署下监听只发生一次见 onConfigInit。文件 add/change 事件入队LibrarySyncFilesunlink 事件入队LibraryRemoveAsset。监控功能排障ENOSPC错误需要提高文件监听器上限。对应 sysctl 键为fs.inotify.max_user_watches默认值 8192应调大到大于你要监听的文件数。注意 Immich 必须监听导入路径中的所有文件包括被忽略的文件例如ERROR [LibraryService] Library watcher for library c69faf55-f96d-4aa0-b83b-2d80cbc27d98 encountered error: Error: ENOSPC: System limit for number of file watchers reached, watch /media/photo.jpg监听器挂起罕见情况下库监听器可能挂起导致 Immich 无法启动。此时需在配置文件中禁用库监听器。如果监听是在 Immich 界面内启用的就必须在不启动微服务的情况下启动应用在 docker compose 文件中禁用 microservices启动 Immich在管理设置中禁用库监听器关闭 Immich重新启用 microservices之后 Immich 即可正常启动。夜间任务Nightly Job与删除库系统内置一个每日执行的自动扫描任务其调度可配置见下文“自定义扫描间隔”。从 config.dto.ts 看默认配置为library.scan.enabled: true、cronExpression为EVERY_DAY_AT_MIDNIGHT即每天午夜、library.watch.enabled: false监控默认关闭。该夜间任务同时会清理处于“删除中”卡住状态的库。在库管理页面点击 “Scan all libraries” 也可以手动触发这一清理。源码中handleQueueScanAll 会先入队LibraryDeleteCheck再由 handleQueueCleanup 找出所有处于待删除状态的库并重新入队删除任务——这就是“服务器重启导致删除中断后由夜间任务兜底”的实现。删除库删除外部库时库内所有资产会随库一起被立即删除。注意库虽然可能在后台花较长时间才能真正删完但会立即从库列表中移除。若删除过程被打断例如服务器重启会在下一次夜间 cron 任务中完成清理也可以点击库列表中的 “Scan All Libraries” 按钮手动启动清理。源码层面handleDeleteLibrary 对每个资产入队AssetDelete且deleteOnDisk: false——Immich 只删除自己的资产记录不会删除外部磁盘上的原始文件删除库前无需担心源数据。文件夹视图Folder View文件夹视图是时间线之外的另一种浏览方式类似文件资源管理器允许你浏览库内的文件夹与文件。对于精心整理、高度自定义的外部库或者配置得当的存储模板这个功能非常实用。可以在Account Settings Features Folders中启用。更多细节参见 文件夹视图文档。设置自定义扫描间隔此操作仅管理员可执行。在Administration - Settings - External Library下可以定义触发外部库重新扫描的自定义间隔支持预设选项或 cron 表达式格式可参考 Crontab Guru 之类的工具学习 cron 语法。对应的服务端配置结构为library.scan.{enabled, cronExpression}见 config.dto.ts 中AdminConfigLibraryScanDto的定义与默认值。外部库无法正确扫描时的排查清单有时外部库不能正常扫描通常是因为 Immich 无法访问文件。文档给出的排查清单逐项核对docker-compose 文件中卷是否挂载正确卷是否同时挂载到了所有 worker 容器导入路径是否设置正确并且与 docker-compose 文件中设置的路径一致导入路径中不要使用符号链接也不要跨 Docker 挂载点做链接文件权限是否正确确认路径使用正斜杠/而非反斜杠。验证 Immich 能否触达外部库的实操方法进入容器 shell 执行docker exec -it immich_server bash如果你的导入路径是/mnt/photos用ls /mnt/photos检查。如果你使用了独立的 microservices 容器务必为它配置相同的挂载点并在该容器内同样确认可访问性因为监控与扫描任务实际运行在 microservices 中见前文源码分析。小结外部库让 Immich 从“上传式图库”扩展为“索引式图库”原始文件留在原处Immich 只维护资产索引与元数据。掌握导入路径的容器视角、**/xxx/**这类排除模式、ro只读挂载、监控的 inotify 限制与夜间扫描的 cron 配置就足以稳定运营大规模外部媒体库。所有行为均可在 server/src/services/library.service.ts 及其 单元测试 中对照源码验证。【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immich创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表