批量导入
把旧图床或博客里的图片批量转存进 ImgYoung,支持图片地址清单、站点地图、订阅源、网页与 Markdown、HTML 文本,并导出新旧链接对照表。
什么时候用
旧图床要下线,或者博客里的图片散落在各处,想全部收进 ImgYoung,并拿到「旧链接 → 新链接」的对照表去替换文章里的地址。批量导入就是做这件事:
- 给出图片地址,或者给出能找到图片的站点、文本。
- 确认要导入哪些域名下的图片。
- 服务端逐张抓取并入库,完成后下载对照表。
导入的图片归属当前账号,走与上传相同的处理流程:格式白名单、像素预算、EXIF 处理和存储配额照常生效。只想转存一张图时,用URL 转存。
所有登录用户都能使用。普通用户只能看到和操作自己创建的任务;管理员能看到所有人的任务,并能取消、删除任何人的任务,但确认和重试只有创建者能做。整个实例同一时刻只处理一个导入任务,管理员可以借此取消卡住的任务,让后面的任务继续。
新建导入
在侧栏「内容」组打开「导入」,点「新建导入」;也可以在「图片」页点「上传图片」旁的「批量导入」。对话框有三个标签,按手头已有的材料选一个:
| 标签 | 填什么 | 之后 |
|---|---|---|
| 图片地址 | 图片地址,一行一个 | 直接开始导入 |
| 网站 | 站点地图、订阅源或网页地址,一行一个 | 扫描后,确认要导入的域名 |
| 文本与文件 | 粘贴 Markdown 或 HTML 文本,或选择文件 | 扫描后,确认要导入的域名 |
图片地址
每行一个 http 或 https 的图片地址。同一个地址出现多次只导入一次。提交后任务直接进入「导入中」,没有确认步骤。
网站
每行一个地址,类型由抓回的内容决定,不看扩展名:
| 地址指向 | 处理 |
|---|---|
站点地图(urlset、sitemapindex,含 gzip 压缩) | 逐个扫描其中的文章页面;索引里的子站点地图依次展开 |
| 订阅源(RSS、Atom) | 逐个扫描其中的文章页面 |
| 每行一个地址的纯文本 | 按文本站点地图处理,逐个扫描 |
| 网页 | 扫描这一页 |
| 图片 | 直接作为待导入的图片 |
服务端只展开到文章页面,不会顺着页面里的链接继续抓取。站点地图或订阅源里不属于它所在域名的页面会被跳过,直接填写的网页地址不受这条限制。
任务创建后进入「扫描中」,页面显示已处理的页面数。扫描结束后进入「待确认」。
文本与文件
粘贴文本,或选择一个或多个 .md、.markdown、.html、.htm、.txt 文件。粘贴的文本在报告里记作「粘贴的文本」,文件以文件名为文档名。
文本里的图片若写的是相对路径,在「基准地址」里填文章所在页面的地址,服务端据此补全。没有基准地址,相对路径无法抓取,会列在扫描报告的「无法抓取的引用」里。HTML 里的 <base href> 优先于基准地址。
扫描在提交时完成,任务直接进入「待确认」。
高级选项
三个标签共用,都可以留空:
| 选项 | 作用 |
|---|---|
| 有效期 | 导入图片的有效期。留空时先取你的默认有效期,没有再取全局默认,见生命周期与查重 |
| EXIF | 剥离或保留元数据。留空时用全局默认,见EXIF 处理 |
| Referer | 抓取图片时发送的来源页地址,用于有防盗链的旧图床,见防盗链的图床 |
确认要导入的域名
「待确认」的任务打开后,页面显示:
- 扫描报告:扫描了多少页面或文档,几页没有找到图片,几页抓取失败(逐条列出地址与原因,站点地图或订阅源的内容无法解析时原因码为
import_listing_invalid),几处图片引用无法抓取(逐条列出),几个页面因不在站点域名下被跳过。 - 域名表:发现的图片按域名分组,每个域名一行,显示图片数和最多 3 个示例地址,数量多的在前。
默认一个域名都不选。勾选旧图床所在的域名,点「开始导入」:所选域名下的图片进入导入,其余的不导入。可以用「全选」「清空」批量操作。域名表只显示地址文本,不加载缩略图。
没有勾选任何域名时,「开始导入」不可点。扫描没有发现任何图片时,页面显示「没有发现图片」,这时只能删除任务。
一个页面里图片的域名往往不止一个:旧图床、统计图标、第三方头像都会出现在表里。只勾选你要搬走的那个。
导入过程
任务进入「导入中」后,页面显示进度和各状态的数量,失败的条目实时列出,不需要手动刷新。
- 并发:一个任务同时转存 4 张。这 4 个名额与上传并发上限相互独立,不占用上传频率额度;规划内存时按两者之和估算。
- 排队:整个实例同一时刻只处理一个导入任务,其余任务按创建先后排队,期间没有进展。
- 处理流程:每张图抓取后走与上传相同的流程,成功后记下新图片的短 ID。文件名取地址路径的最后一段。
- 失败:单张图失败不影响其他图,失败原因记在条目上。全部条目处理完后,任务进入「已完成」,即使其中有失败的。
- 重启:服务重启后,「导入中」的任务从没处理的条目继续,已经入库的图不会重复导入;「扫描中」的任务从头重新扫描。
失败的条目
| 错误码 | 常见原因 | 处理 |
|---|---|---|
url_blocked | 地址不是公网地址 | 内网地址不能导入,见抓取限制 |
url_too_large | 图片超过单图大小上限 | 调大「单图上限」后重试 |
url_bad_status | 远端返回了非 2xx,常见于防盗链 | 填写 Referer 后重新创建任务,或确认旧地址是否已失效 |
url_fetch_failed | 超时或连接失败 | 稍后重试 |
url_too_many_redirects | 重定向超过 5 次 | 检查地址 |
upload_unsupported_type | 格式不在白名单内,如 SVG、AVIF | 无法导入,见格式与上限 |
upload_invalid_image | 内容不是可解析的图片 | 检查地址是否真的指向图片 |
upload_too_many_pixels | 分辨率超过像素预算 | 调大「像素预算」后重试 |
页面按错误码显示本地化的说明,并附远端或服务端返回的原文(最长 500 个字符)。每张图最长处理 20 分钟。
重试
任务结束后点「重试」:失败的条目和没处理的条目一起重新进入「导入中」。已经成功的不受影响。任务不会自动重试失败项。
「已完成」「已中止」「已取消」的任务都可以重试;扫描没有完成就中止或取消的站点任务没有候选可以继续,重试会从头重新扫描;没有失败和未处理的条目时重试会被拒绝(import_nothing_to_retry)。
中止
没有可用渠道或数据库等服务端故障时,继续下去只会让后面的图全部同样失败,所以整个任务中止,状态为「已中止」,页面显示原因,没处理的条目保留。存储配额同理:连续 3 张图都因配额不足失败,就认为配额已满而中止;只是某一张图超过剩余额度时,只有这一张失败,后面放得下的图照常导入。先解决问题(调高配额、修复渠道),再点「重试」继续。
取消
「扫描中」「待确认」「导入中」的任务可以取消。正在转存的图片会被中断,没处理完的条目保持待转存,已经导入的图片保留。取消后的任务可以重试。
对照表
任务结束后(「已完成」「已中止」「已取消」),点「下载对照表」选择 JSON 或 CSV。对照表只包含已导入成功、图片仍然存在的条目。新地址是图片的完整访问地址:设置了对外站点地址(base_url)时用它,否则按当前访问的域名生成。
| 列 | 含义 |
|---|---|
old_url | 旧图片的地址 |
new_url | 新图片的地址 |
image_id | 新图片的短 ID |
source | 引用这张图的页面地址或文档名 |
raw | 引用在该处的原文,可能是相对路径,用来在源文章里查找替换 |
- CSV:UTF-8,首行是表头,每处引用一行;没有引用位置的图片输出一行,
source与raw为空。以=、+、-、@开头的单元格前会加一个单引号,避免用电子表格打开时被当成公式;要按原文精确查找替换时,用 JSON 对照表。 - JSON:每张图一个对象,所有引用位置嵌套在
references数组里:
[
{
"old_url": "https://old.example.com/img/a.png",
"new_url": "https://img.example.com/i/R0RjUyP1UW",
"image_id": "R0RjUyP1UW",
"references": [
{ "source": "https://blog.example.com/post-1", "raw": "/img/a.png" }
]
}
]对照表只用于你自己替换文章里的地址,ImgYoung 不会改动源文章。
删除任务
「待确认」「已完成」「已取消」「已中止」的任务可以删除,任务记录、条目和对照表一并删除,已经导入的图片不受影响。「扫描中」「导入中」的任务要先取消。删除前先下载需要的对照表。
限制与注意事项
- 只扫描静态 HTML:靠脚本渲染出来的图片找不到,这类页面会计入报告里「没有找到图片的页面」。
- 站点模式给出的是对照表:抓回的是渲染后的网页,不是文章源文件,所以 ImgYoung 不改写文章,由你按对照表替换。
- 不识别本地文件引用:
data:内嵌图片、本地路径和 Obsidian 的![[文件]]都不是可抓取的地址,会列在「无法抓取的引用」里。本地图片请用上传。 - 格式:只能导入 JPEG、PNG、GIF 和 WebP;SVG、AVIF 等会以
upload_unsupported_type失败。 - 只抓公网地址:与 URL 转存相同,内网地址被拒绝,见抓取限制。
- 扫描的限制:失败页面与无法抓取的引用在报告里各列出前 1000 条。并发抓取 4 个页面,单个站点地图、订阅源或页面最大 50 MiB,抓取一个地址最长 2 分钟。页面数与图片数不设上限。不读取
robots.txt,请求的User-Agent为ImgYoung/<版本> (+https://github.com/x-haose/imgyoung)。 - 提交大小:「文本与文件」一次提交的内容不超过 32 MiB,其中每份文档不超过 4 MiB,解析一份文档超过 15 秒会被拒绝。
防盗链的图床
图片抓取时会带 Referer:「高级选项」里填了就用它,没填就用引用这张图的页面地址;两者都没有(例如图片地址清单)就不发。只放行自家页面的旧图床,对不带来源的请求会返回 403 之类的状态码,表现为 url_bad_status。这时在 Referer 里填旧站的首页或文章页地址,重新创建任务。
用脚本调用
导入接口使用登录会话认证,不接受上传 Token。认证方式见接口参考,每个接口的参数与返回见接口参考:后台·批量导入。
登录后创建一个图片地址清单的任务(csrf_token 取自登录响应):
curl -b jar.txt \
-H "X-CSRF-Token: <csrf_token>" \
-H "Content-Type: application/json" \
-d '{"mode": "images", "urls": ["https://old.example.com/img/a.png", "https://old.example.com/img/b.jpg"]}' \
https://img.example.com/api/admin/imports下载对照表:
curl -b jar.txt -OJ \
"https://img.example.com/api/admin/imports/<任务 ID>/mapping?format=csv"错误码
| 操作 | 状态码 | 错误码 | 含义 |
|---|---|---|---|
| 新建 | 400 | import_input_invalid | 请求不合法,提示里指出哪一项有问题,例如某个地址不是 http 或 https 绝对地址 |
| 新建 | 413 | import_input_invalid | 请求体超过 32 MiB |
| 查看、取消、重试、删除、确认、对照表 | 404 | import_not_found | 任务不存在,或属于别的用户(管理员能看到所有人的任务) |
| 新建 | 429 | import_busy | 文本解析的名额被占满,等待超过 15 秒仍没有轮到,稍后重试 |
| 确认、重试 | 403 | import_owner_only | 管理员操作别人的任务,这两项只有创建者能做 |
| 取消、重试、删除、确认 | 409 | import_state_invalid | 任务当前状态不允许这个操作 |
| 确认 | 400 | import_no_selection | 所选域名下没有待导入的图片地址 |
| 重试 | 409 | import_nothing_to_retry | 没有失败或未处理的条目 |
各状态允许的操作:
| 状态 | 界面显示 | 可以做 |
|---|---|---|
scanning | 扫描中 | 取消 |
ready | 待确认 | 开始导入、取消、删除 |
importing | 导入中 | 取消 |
done | 已完成 | 重试、下载对照表、删除 |
cancelled | 已取消 | 重试、下载对照表、删除 |
aborted | 已中止 | 重试、下载对照表、删除 |