news 2026/9/7 14:38:21

Immich CLI 实战指南:认证、上传与自动化管理自托管照片库的完整命令参考

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Immich CLI 实战指南:认证、上传与自动化管理自托管照片库的完整命令参考

Immich CLI 实战指南:认证、上传与自动化管理自托管照片库的完整命令参考

【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immich

Immich 除了 Web 端与移动端,还提供官方的命令行工具@immich/cli,用于在终端中向 Immich 服务器批量上传照片和视频、检查服务器版本与统计信息。本文以官方功能文档 command-line-interface.md 为主体,完整覆盖安装、认证、upload命令全部选项与环境变量,并结合 packages/cli 目录下的源码,深入讲解去重、并发上传、XMP sidecar 附带上传、watch 监听等底层实现细节,帮助你在服务器、NAS 脚本或 CI 环境中把 CLI 真正用起来。

功能定位与适用场景

官方文档将 CLI 的当前能力概括为两点:

  • 将照片和视频上传到 Immich;
  • 查看服务器版本信息。

文档同时注明更多功能在规划中。如果你的目标是批量导入 Google Photos Takeout 导出的目录,官方文档建议使用社区维护的工具 immich-go;而 CLI 更适合"日常把某个目录同步/归档进 Immich"这类场景,因为它支持 dry-run、并发控制、JSON 输出等面向脚本化的设计。

CLI 源码位于 packages/cli 目录,包名为@immich/cli,入口命令注册在 src/index.ts,package.jsonbin字段将immich命令映射到构建产物(见 packages/cli/package.json)。

环境要求与安装

要求

  • Node.js 22 及以上(packages/cli/package.json 中engines声明为node >=22.0.0);
  • Npm。

如果系统无法安装 Node/npm,可以使用官方提供的 Docker 版本(见下文)。

通过 NPM 安装

npm i -g @immich/cli

如果你安装过旧版(legacy)CLI,需要先卸载:

npm uninstall -g immich

通过 Docker 运行

当 npm 不可用时,可直接运行官方 CLI 镜像。docker run命令会直接在容器内执行immich命令,因此可以把upload等参数直接追加在命令行末尾:

docker run -it -v "$(pwd)":/import:ro -e IMMICH_INSTANCE_URL=https://your-immich-instance/api -e IMMICH_API_KEY=your-api-key ghcr.io/immich-app/immich-cli:latest

例如执行递归上传:

docker run -it -v "$(pwd)":/import:ro -e IMMICH_INSTANCE_URL=https://your-immich-instance/api -e IMMICH_API_KEY=your-api-key ghcr.io/immich-app/immich-cli:latest upload -a -c 5 --recursive directory/

请根据实际环境修改IMMICH_INSTANCE_URLIMMICH_API_KEY两个环境变量;也可以改用 Docker env file 来存放敏感的 API key。

从 packages/cli/Dockerfile 可以确认镜像的工作目录被设置为/importWORKDIR /import),所以-v "$(pwd)":/import:ro把宿主机当前目录以只读方式挂载进去,容器内的.即指向待上传目录;ENTRYPOINT直接执行 CLI 的构建产物,参数透传给immich命令。

命令总览(Usage)

运行immich无参数时输出的完整帮助如下(与官方文档一致):

$ immich Usage: immich [options] [command] Command line interface for Immich Options: -V, --version output the version number -d, --config-directory <directory> Configuration directory where auth.yml will be stored (default: "~/.config/immich/", env: IMMICH_CONFIG_DIR) -u, --url [url] Immich server URL (env: IMMICH_INSTANCE_URL) -k, --key [key] Immich API key (env: IMMICH_API_KEY) -h, --help display help for command Commands: login|login-key <url> <key> Login using an API key logout Remove stored credentials server-info Display server information upload [options] [paths...] Upload assets help [command] display help for command

对照 src/index.ts 可以看到,这四个全局选项(-d/-u/-k等)都通过 commander 的Option.env()绑定了环境变量,因此所有选项都优先取命令行参数,其次回退到同名环境变量。

全局选项环境变量默认值说明
-V, --version输出版本号
-d, --config-directory <dir>IMMICH_CONFIG_DIR~/.config/immich/存放auth.yml的凭证目录
-u, --url <url>IMMICH_INSTANCE_URLImmich 服务器 URL(以/api结尾)
-k, --key <key>IMMICH_API_KEYImmich API key

认证机制:login / logout 与 auth.yml

获取 API Key

API key 在 Web 界面的用户设置面板中获取,可以为 key 指定权限以限制其访问范围。

login 命令

# immich login [url] [key] immich login http://192.168.1.216:2283/api HFEJ38DNSDUEG

login成功后会把凭证写入配置目录下的auth.yml文件,默认目录为~/.config/immich/;目录可以用-d选项或环境变量IMMICH_CONFIG_DIR指定。请妥善保管该文件——用完执行logout,或手动删除它。

从 src/commands/auth.ts 的实现可以看到login的完整流程:

  1. 调用connect(url, key)发起连接。connect位于 src/utils.ts,它还会先请求<url>/.well-known/immich端点做服务发现:如果服务器返回了 API 端点,CLI 会自动把 URL 纠正为端点地址,因此即使 URL 写得略有偏差也能连上;
  2. 通过requirePermissions([Permission.UserRead])校验当前 key 是否具备UserRead权限,缺失时打印缺失的权限名并退出(process.exit(1));
  3. 调用getMyUser()确认身份,打印Logged in as <email>
  4. 若配置目录不存在则递归创建,最后以0o600(仅属主可读写)的文件权限写入auth.yml(见 src/utils.ts 的writeAuthFile),降低凭证被同机其他用户读取的风险。

logout 命令

immich logout

实现为直接删除auth.yml文件(src/commands/auth.ts)。

认证的回退顺序

执行任何需要认证的命令时,src/utils.ts 中的authenticate按以下顺序取凭证:

  1. 命令行同时提供-u-k时直接使用它们(不读 auth 文件);
  2. 否则读取配置目录中的auth.yml。若文件不存在则提示No auth file exists. Please login first.并退出。

这意味着login并不是每次上传的强制前置步骤——你完全可以每次都用-u/-kIMMICH_INSTANCE_URL/IMMICH_API_KEY环境变量传入凭证,这正是 Docker 用法的工作方式。

upload 命令:完整选项参考

官方文档中upload子命令的完整帮助输出:

Usage: immich upload [paths...] [options] Upload assets Arguments: paths One or more paths to assets to be uploaded Options: -r, --recursive Recursive (default: false, env: IMMICH_RECURSIVE) -i, --ignore <pattern> Pattern to ignore (env: IMMICH_IGNORE_PATHS) -h, --skip-hash Don't hash files before upload (default: false, env: IMMICH_SKIP_HASH) -H, --include-hidden Include hidden folders (default: false, env: IMMICH_INCLUDE_HIDDEN) -a, --album Automatically create albums based on folder name (default: false, env: IMMICH_AUTO_CREATE_ALBUM) -A, --album-name <name> Add all assets to specified album (env: IMMICH_ALBUM_NAME) --visibility <visibility> Set the visibility of uploaded assets (choices: "archive", "timeline", "hidden", "locked", env: IMMICH_VISIBILITY) -n, --dry-run Don't perform any actions, just show what will be done (default: false, env: IMMICH_DRY_RUN) -c, --concurrency <number> Number of assets to upload at the same time (default: 4, env: IMMICH_UPLOAD_CONCURRENCY) -j, --json-output Output detailed information in json format (default: false, env: IMMICH_JSON_OUTPUT) --delete Delete local assets after upload (env: IMMICH_DELETE_ASSETS) --delete-duplicates Delete local assets that are duplicates (already exist on server) (env: IMMICH_DELETE_DUPLICATES) --no-progress Hide progress bars (env: IMMICH_PROGRESS_BAR) --watch Watch for changes and upload automatically (default: false, env: IMMICH_WATCH_CHANGES) --help display help for command

官方文档特别说明:以上所有选项同样可以从环境变量读取,这对 Docker 场景(用--env-file注入配置)和 cron 脚本尤其有用。对照 src/index.ts 的注册代码,还可以补充两个源码级约束:

  • -A, --album-name-a, --album互斥(.conflicts('album')),同时指定会报错;
  • -n, --dry-run--skip-hash互斥(.conflicts('skipHash'))——dry-run 依赖哈希检查来判断哪些文件"将被上传",因此二者不能同时使用;
  • --watch会自动隐含progress: false.implies({ progress: false })),因为进度条渲染与监听日志输出会互相干扰。

关于并发默认值,有一个值得注意的细节:文档的帮助输出标注default: 4,而从 src/index.ts 的当前源码看,默认值是按 CPU 核数动态计算的Math.max(1, os.cpus().length - 1)。以你所运行版本的immich upload --help实际输出为准。

选项速查表

选项环境变量默认值作用
-r, --recursiveIMMICH_RECURSIVEfalse递归扫描子目录
-i, --ignore <pattern>IMMICH_IGNORE_PATHS忽略匹配 glob 模式的文件,可多次指定
--skip-hashIMMICH_SKIP_HASHfalse上传前不计算文件哈希(提速用)
-H, --include-hiddenIMMICH_INCLUDE_HIDDENfalse包含隐藏文件/目录
-a, --albumIMMICH_AUTO_CREATE_ALBUMfalse按所在文件夹名自动创建/归入相册
-A, --album-name <name>IMMICH_ALBUM_NAME将所有上传资产加入指定名称的相册
--visibility <v>IMMICH_VISIBILITY上传资产的可见性:archive/timeline/hidden/locked
-n, --dry-runIMMICH_DRY_RUNfalse只做检查,不执行任何写操作
-c, --concurrency <n>IMMICH_UPLOAD_CONCURRENCY见上文说明同时上传的资产数
-j, --json-outputIMMICH_JSON_OUTPUTfalse以 JSON 输出newFilesduplicatesnewAssets
--deleteIMMICH_DELETE_ASSETS上传成功后删除本地文件
--delete-duplicatesIMMICH_DELETE_DUPLICATES删除服务端已存在的重复文件
--no-progressIMMICH_PROGRESS_BAR隐藏进度条
--watchIMMICH_WATCH_CHANGESfalse监听目录变化并自动上传

Quick Start:从零完成一次上传

第一步:认证

# immich login [url] [key] immich login http://192.168.1.216:2283/api HFEJ38DNSDUEG

第二步:上传资产

上传单个文件:

immich upload file1.jpg file2.jpg

默认不扫描子目录,递归上传整个目录:

immich upload --recursive directory/

不确定会发生什么时,先用--dry-run预演,它不会执行任何实际操作:

immich upload --dry-run --recursive directory/

第三步:按需组合选项

跳过哈希检查(--skip-hash):默认情况下upload会先对每个文件计算 SHA-1,用来避免重复上传。如果你对文件的唯一性有把握,可以传--skip-hash省掉这一步。注意 Immich 服务端始终会自己做基于哈希的去重,所以这纯粹是性能层面的取舍——带宽充足时跳过客户端哈希可能更快。

immich upload --skip-hash --recursive directory/

按文件夹自动建相册(--album):为每个上传资产按其所在文件夹名自动创建相册:

immich upload --album --recursive directory/

上传到指定相册(--album-name):把所有资产加入指定名称的相册:

immich upload --album-name "My summer holiday" --recursive directory/

用 glob 模式排除文件(--ignore):可以传多个排除模式。glob 的用法可参考 库功能文档:

immich upload --ignore **/Raw/** --recursive directory/
immich upload --ignore **/Raw/** **/*.tif --recursive directory/

包含隐藏文件(--include-hidden):默认跳过隐藏文件,如需包含:

immich upload --include-hidden --recursive directory/

设置可见性(--visibility):把上传资产设为archivetimelinehiddenlocked

immich upload --visibility archive --recursive directory/

JSON 输出(--json-output):输出包含newFilesduplicatesnewAssets三个键的 JSON。由于前面有若干行日志输出,需要去掉输出的前几行才能解析。例如列出将被上传的文件供后续处理:

immich upload --dry-run --json-output . | tail -n +6 | jq .newFiles[]

深入源码:一次 upload 到底做了什么

upload的实现集中在 src/commands/asset.ts,主入口upload()(asset.ts#L139-L162)的流程是:认证 → 权限校验 → 扫描文件 → 批量上传。

1. 权限与文件扫描

  • 上传要求 API key 具备AssetUpload权限(asset.ts#L141),否则 CLI 会明确提示缺失的权限名。
  • scan()会先调用服务端的getSupportedMediaTypes()拿到当前服务器支持的全部图片/视频扩展名,再用 fast-glob 扫描本地目录(src/utils.ts 的crawl)。这解释了为什么--recursive不加时不会进入子目录(模式只加/*而非/**)、--ignore模式会被包装成**/<pattern>匹配全路径、--include-hidden对应 glob 的dot选项。

2. 去重:客户端 SHA-1 + 服务端批量比对

checkForDuplicates()(asset.ts#L179-L310)是--skip-hash所控制的环节:

  1. 逐文件流式计算 SHA-1(sha1(),utils.ts#L211-L219),进度条按文件总字节数显示Hashing files/Checking for duplicates两条进度;
  2. 校验项每攒满5000 条就调用一次服务端checkBulkUpload批量接口,按返回的action分为newFiles(Accept)与duplicates(已存在的资产);
  3. 所有任务通过内部Queue执行,失败自动重试 3 次,最终逐条报告失败文件。

--skip-hash时则直接跳过本步,把所有文件当作新文件(asset.ts#L180-L183),这正是文档所说"服务端仍会自己哈希去重"的原因。

3. 上传与 XMP sidecar

uploadFile()(asset.ts#L404-L445)通过FormDataPOST /assets提交:

  • fileCreatedAt/fileModifiedAt:取自文件的mtime
  • fileSizeisFavorite=falseassetData(文件流);
  • visibility:仅在指定--visibility时附加;
  • sidecarDatafindSidecar()(asset.ts#L447-L457)会自动查找同名 XMP sidecar,支持两种命名:photo.ext.xmpphoto.xmp。存在则一并上传,无需任何额外选项。

上传结果按服务端返回状态统计:新资产计入 success,重复状态(AssetMediaStatus.Duplicate)计入 skipped,结束时打印成功/跳过的数量与字节数,并逐条列出上传失败的文件。

4. 相册、删除本地文件

uploadBatch()(asset.ts#L69-L78)在上传完成后依次执行:

  • updateAlbums()--album时以资产的父目录名作为相册名(getAlbumName(),asset.ts#L595-L597),先getAllAlbums取已有相册,只创建缺失的,再分批把资产加入对应相册;--album-name则全部归入该固定名称的相册;
  • deleteFiles()--delete删除上传成功的文件,--delete-duplicates删除被判为重复的文件;删除时会顺带unlink对应的 XMP sidecar。注意 dry-run 模式下只打印Would have deleted N local assets

5. watch 模式:目录监听自动上传

--watch使用 chokidar 监听指定路径(startWatch):

  • 只处理服务器支持媒体类型扩展名的文件,ignore模式同样生效;
  • 变更事件先汇入Batcher(utils.ts#L225-L282),每 100 个文件或每 10 秒UPLOAD_WATCH_BATCH_SIZE/UPLOAD_WATCH_DEBOUNCE_TIME_MS,asset.ts#L27-L28)触发一次批量上传,避免写入中的文件被反复处理(awaitWriteFinish: true);
  • 初始扫描仍走一次性的scan()(注释说明 watcher 不处理初始扫描),然后进入长驻监听,Ctrl+C时干净关闭 watcher。

这使得--watch非常适合放在后台长期运行,充当"目录 → Immich"的轻量同步器。

并发模型:Queue 与 fastq

哈希、去重校验、上传三个阶段都使用同一个自研的内存队列封装 src/queue.ts:基于fastq.promise,支持concurrency并行度与retry次数的失败重试(上传链路统一配置为retry: 3)。因此-c, --concurrency不仅影响上传并行度,也决定了本地哈希计算与批量比对请求的并发程度——调大它主要收益在磁盘读与网络并发,调小则对服务器压力更温和。

server-info:查看服务器版本与统计

immich server-info

实现见 src/commands/server-info.ts,它并发请求四个接口后输出:

  • Url:认证后解析出的服务器地址(经.well-known/immich服务发现纠正后);
  • Version:服务器 major.minor.patch 版本;
  • Formats:服务器支持的图片/视频扩展名列表;
  • Statistics:图片数、视频数、资产总数。

该命令要求 API key 同时具备ServerAboutAssetStatisticsUserRead三个权限,创建 key 时若未勾选对应权限会收到明确的缺失权限提示。

常见问题与使用注意

  • URL 必须以/api结尾IMMICH_INSTANCE_URL/login的 URL 示例均为https://your-immich-instance/api。连接失败时,logError(utils.ts#L101-L113)会特别提示检查是否有反向代理或 SSO 门户代替了 API 应答。
  • 凭证安全auth.yml0o600权限写入,但仍建议用毕logout或删除文件;Docker 场景优先用 env file 而非明文参数。
  • dry-run 与 skip-hash 不可同用--album--album-name不可同用,源码中均有显式冲突校验。
  • 忽略模式语义--ignore按全路径匹配(内部包装为**/<pattern>),写法与 库文档 中扫描设置的排除模式一致,推荐只用于基础的文件夹级排除。
  • 版本差异:帮助文本(如--skip-hash的短选项、--concurrency的默认值标注)可能随版本变化,以你所装版本的immich upload --help实际输出为准;本文引用的行为以当前仓库 packages/cli 源码为准。

小结

Immich CLI 用一条login完成认证、一条upload覆盖绝大多数批量导入需求,全部选项均可用环境变量驱动,天然适配 Docker 与定时任务。理解其源码后可得到几个实用结论:去重是"客户端 SHA-1 + 服务端批量比对"的两段式设计,--skip-hash只省本地计算而服务端去重不受影响;--watch通过 100 文件/10 秒的批处理窗口实现低开销的目录监听;XMP sidecar 会被自动附带上传。配合--dry-run--json-output,它也能作为脚本化迁移管道的可靠一环。

【免费下载链接】immichHigh performance self-hosted photo and video management solution.项目地址: https://gitcode.com/GitHub_Trending/im/immich

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 14:37:37

Kubernetes核心:Pod与五大控制器实战解析

1. 先搞清楚&#xff1a;Pod为什么非要套一层“壳”&#xff0c;不能直接跑容器网上教程讲到Kubernetes&#xff08;K8s&#xff09;时&#xff0c;几乎都会给你配一张图&#xff1a;最小的调度单位是Pod&#xff0c;不是容器。我第一次学的时候心里是犯嘀咕的——既然Docker容…

作者头像 李华
网站建设 2026/9/7 14:37:19

纯HTML+CSS+JS实现全屏视频背景:完整教程与避坑指南

简介&#xff1a;全屏视频背景是提升网页沉浸感的常见设计&#xff0c;这份HTMLCSS代码资源正适合前端初学者与需要快速落地该效果的开发者。压缩包共3个文件&#xff0c;包含1个mp4示例视频、1个html页面和1个css样式文件&#xff0c;总大小仅4.11MB&#xff0c;小巧便于直接打…

作者头像 李华
网站建设 2026/9/7 14:36:21

新闻App评论后端架构演进:从单表到智能审核的高并发实战

做了这么多年新闻App的后端&#xff0c;评论区是我觉得最“有温度”也最“有杀气”的一块系统。说它有温度&#xff0c;是因为用户最真实的声音都沉淀在这里&#xff1b;说有杀气&#xff0c;是因为每次热点新闻一爆&#xff0c;评论流量的尖峰能在几秒钟之内把服务打到崩溃边缘…

作者头像 李华
网站建设 2026/9/7 14:34:47

MEMS惯导晃动环境自对准:建模、滤波与参数整定实战

MEMS惯导在晃动环境下做自对准&#xff0c;这个需求我太熟悉了。不管是船载设备、移动测绘车&#xff0c;还是机械臂末端的姿态参考系统&#xff0c;你都会撞上同一个尴尬局面&#xff1a;理论书上都写“静基座对准”&#xff0c;可实际现场根本没有绝对的“静”——发动机在震…

作者头像 李华
网站建设 2026/9/7 14:34:29

用系统架构视角拆解秦始皇大一统:一场硬核的底层重构

1. 引言&#xff1a;用软件工程的眼光看华夏第一套国家操作系统 把“秦始皇统一六国”和“第一性原理”“系统一致性校验”放在一起&#xff0c;看起来像缝合怪&#xff0c;但真拆开看&#xff0c;这个题目的容量比想象中大得多。做过程序设计、搞过系统架构的人&#xff0c;再…

作者头像 李华