fix: 修复博客图片加载失败(掘金防盗链)

- 将《Git使用教学》中的掘金外链图片下载至 source/images/ 并替换为站内路径
- _config.yml 注入 no-referrer meta 作为兜底方案
- 新增 tools/download-juejin-images.js 批量下载/替换脚本
This commit is contained in:
2026-07-08 21:52:22 +08:00
parent 1d8ce5a16c
commit b3f44d235a
57 changed files with 1389 additions and 5 deletions
+74
View File
@@ -0,0 +1,74 @@
// 下载 Markdown 中的掘金外链图片到 source/images/,并替换链接为站内路径
const fs = require('fs');
const path = require('path');
const https = require('https');
const http = require('http');
const ROOT = 'c:/Users/Administrator/Desktop/新建文件夹/blog';
const MD = path.join(ROOT, 'source/_posts/Git使用教学.md');
const OUT = path.join(ROOT, 'source/images');
function download(url) {
return new Promise((resolve, reject) => {
const lib = url.startsWith('https') ? https : http;
const req = lib.get(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }, (res) => {
// 跟随重定向
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
res.resume();
return download(new URL(res.headers.location, url).href).then(resolve, reject);
}
if (res.statusCode !== 200) {
res.resume();
return reject(new Error('HTTP ' + res.statusCode));
}
const chunks = [];
res.on('data', (c) => chunks.push(c));
res.on('end', () => resolve(Buffer.concat(chunks)));
});
req.on('error', reject);
req.setTimeout(30000, () => req.destroy(new Error('timeout')));
});
}
(async () => {
fs.mkdirSync(OUT, { recursive: true });
let content = fs.readFileSync(MD, 'utf8');
const re = /!\[[^\]]*\]\((https:\/\/p3-juejin\.byteimg\.com\/[^)\s]+)\)/g;
const map = {}; // url -> /images/xxx.webp
let m;
const tasks = [];
while ((m = re.exec(content)) !== null) {
const url = m[1];
if (map[url]) continue;
const seg = url.split('/').pop();
const hash = seg.split('~')[0];
if (!hash) {
console.log('跳过(无法解析文件名): ' + url);
continue;
}
const file = hash + '.webp';
map[url] = '/images/' + file;
tasks.push(
download(url)
.then((buf) => {
fs.writeFileSync(path.join(OUT, file), buf);
console.log('[OK] ' + file + ' <- ' + url);
})
.catch((e) => {
console.log('[FAIL] ' + url + ' -> ' + e.message);
delete map[url];
})
);
}
await Promise.all(tasks);
for (const url in map) {
content = content.split(url).join(map[url]);
}
fs.writeFileSync(MD, content); // UTF-8 无 BOM
console.log('\n完成:处理 ' + Object.keys(map).length + ' 张图片');
})();