结论:不需要重传。 第二次发布(更新)时,插件会按「资源路径」查缓存,已经传过的图直接复用原来的图床地址,一个网络请求都不发;只有这一次新增的图片才真正交给 PicGo。

代码里的依据

Hexo 发布链路在 ​index.js​ 的 ​uploadDocImagesToPicGo()(2235 行):

for (const url of pending) {
const assetPath = toAssetPath(url);
if (cache[assetPath]) { // ← 命中缓存
cached++;
urlMap.set(url, cache[assetPath]);
continue; // ← 直接跳过,不发请求
}
...stageAssetToTemp → PicGo 上传 → cache[assetPath] = remote
}

有三个关键点:

  • 缓存键是归一化后的资源路径,比如 ​/assets/image-20250101120000-abc.png​,不是文档 ID,也不是 URL 原文。​toAssetPath()​ 会把 ​assets/x.png​、​/assets/x.png​、​http://127.0.0.1:6806/assets/x.png 这三种写法都归一成同一个 key,所以就算你在思源里换了一种引用写法,也能命中同一条缓存。
  • 缓存持久化在磁盘上:​<工作空间>/data/storage/petal/QingZhou/settings​ 的 ​picgoCache 字段。插件重载、思源重启、换设备登录同一个工作空间,缓存都还在。
  • 重新发布其实只是覆盖同一个 .md 文件:​hexoMappings​ 记着 file 路径,​mine === true​ 时不弹确认直接 ​writeTextFileSync 覆盖。文章里旧图的链接还是上次那批图床 URL。

怎么自己确认

每次发布,弹窗底部的日志都会打一行:

图片处理完成:新上传 0,复用缓存 7,失败 0

「新上传 0」就是你要的结果。第一次发布是「新上传 7,复用缓存 0」,之后只要不改图,就一直是前者。

四种模式的差异,顺便理一下

图片处理方式 第一次 重新发布
上传到图床(PicGo) 上传 查 ​picgoCache,命中即跳过
复制到博客仓库 写进仓库 fs.existsSync​ 有就直接跳过(​copyDocImagesToRepo,2146 行)
上传到博客园图床 上传 查 ​assetCache,命中即跳过
保持原样 不动 不动

三种带上传的模式都有缓存,只是缓存表不同:PicGo 用 ​picgoCache​,博客园用 ​assetCache。

三个会让你「以为要重传」的例外

  1. 手动点了「清空图片缓存」 :缓存清空后,下次发布就会被当作从未上传过,图床(博客园)里会多出一份重复图片,已发布文章里的链接不受影响。弹窗里那句确认文案说的就是这个。
  2. 在思源里给图片换了名(重命名或换了一张同位置的新图,路径变了):换名等于换 key,会重新上传,旧图留在图床成为孤儿。这是「路径当 key」的代价;换内容不换名反而更隐蔽,会继续用旧地址,博客上显示的还是旧图。
  3. 换图床(PicGo 里从 SM.MS 换成阿里云或 GitHub):缓存里存的是旧图床 URL,不会自动迁移,得清缓存才会重传到新图床。

顺手发现一个不一致,要不要修

设置里的「清空图片缓存」按钮(​_wirePaneData​,7402 行)只清 ​assetCache:

this.data.assetCache = {};

picgoCache​ 没有任何清理入口,只能手动去改 ​settings 这个 JSON 文件。也就是说,走 Hexo 加 PicGo 的用户,遇到上面第 2、3 种情况时,在界面上根本清不掉缓存。README 里那句「清空图片缓存」写得像通用开关,实际只对博客园生效。

建议的改法很小:按钮里两行都清,确认文案按当前 ​hexoImageMode​ 说对应的话;或者在「数据管理」里拆成两个条目(博客园图床缓存和 PicGo 图床缓存),各自显示条数。你倾向哪种?定了我就改 ​index.js​,​index.css 不用动。