# 单张图片与历史路径导入 ## 保留原目录结构 如果旧图床文件已经按 URL 路径组织,可以将整个目录树只读挂载到 `/data/migrations`。ImageSilo 会把该目录下的相对路径直接作为公网路径,不写入数据库,也不要求创建历史路径映射: ```text /data/migrations/i/2022/04/example.jpg -> /i/2022/04/example.jpg ``` 只会公开 JPEG、PNG、WebP 和 GIF 普通文件;路径穿越、越界软链接和保留的系统路由都会被拒绝。数据库中的历史路径映射优先于迁移目录中的同名文件。 这种方式适合冷迁移或长期只读兼容。需要在后台管理、搜索、设置可见性或转换 WebP 的图片,仍应使用下方的单张导入接口。 后台“迁移管理”会递归扫描该目录并平铺展示所有可公开交付的图片,支持搜索、格式/大小筛选和复制链接。列表使用 30 分钟惰性快照:缓存过期后的首次访问才重新扫描,不会后台定时扫盘;目录有外部变动时可点击“刷新”立即重建快照。图片直链不依赖该列表快照,文件变动仍按实时文件状态交付。默认只读;若要允许永久删除专用迁移副本,挂载必须可写、容器用户 `10001:10001` 必须拥有删除权限,并显式设置 `IMAGESILO_MIGRATION_MUTATIONS=true`。删除图片后只会向上递归移除真正为空的父目录(包括空的顶层 `i` 或 `images` 目录),不会删除迁移根目录,也不会清理仍含非图片文件的目录。原始迁移快照应继续独立保留。 ImageSilo 的核心导入契约始终只有“一张合法图片 + 一个旧 URL path”。服务端不识别第三方图床格式,也不提供批量任务队列;任意来源都由外部脚本顺序枚举并调用同一个接口。 ## 单张 curl API Token 必须同时具备 `images:upload` 与 `aliases:write`;如果导入为私密并需要脚本自动下载校验,还必须具备 `images:read_private`: ```bash curl --fail --show-error \ --header "Authorization: Bearer $IMAGESILO_TOKEN" \ --form 'file=@/absolute/path/example.jpg' \ --form 'alias=/old/path/example.jpg' \ --form 'visibility=public' \ "$IMAGESILO_BASE_URL/api/v1/imports" ``` 导入只验证格式、大小和像素并保存原始字节,不执行压缩或 WebP 转换。成功响应包含新 Image ID、标准 URL、SHA-256 和已创建的别名。 别名冲突返回 `409 Conflict`。图片记录与一个别名在同一个 SQLite 事务中提交;冲突或数据库失败不会留下新图片记录、正式文件或缩略图。 ## 清单脚本 [import-manifest.sh](../scripts/import-manifest.sh) 使用 TSV 清单严格串行导入,并在每项成功后访问旧 URL、重新计算 SHA-256。它需要 `curl`、`jq`,以及 `sha256sum` 或 `shasum`。 清单格式: ```text # 旧 URL path本地图片路径 /i/2022/05/a.jpg /absolute/source/a.jpg /legacy/b.webp /absolute/source/b.webp ``` 执行: ```bash IMAGESILO_BASE_URL=https://img.example.com \ IMAGESILO_TOKEN=ist_xxx \ scripts/import-manifest.sh \ --manifest ./imports.tsv \ --output ./imports-result.jsonl \ --visibility public ``` 结果文件已存在时脚本拒绝覆盖。出现冲突、HTTP 错误、响应 SHA 不一致或旧 URL 字节不一致时,脚本以非零状态退出,并保留逐项 JSONL 结果供筛选和重试。 ## 迁移验收 - 清单输入数、成功数、冲突数和错误数可对账。 - 每个成功项的源文件、API 返回 SHA-256 和旧 URL 下载字节一致。 - 重复路径不会创建额外图片记录或正式文件。 - 迁移结束后手动执行系统巡检,并确认缺失文件、孤儿文件和清理失败均为零。 - 使用停止写入后的最终清单再执行一次正式迁移;不要把来源系统解析逻辑加入 ImageSilo 核心服务。