added:友联本地和远程重写逻辑
This commit is contained in:
1 parent
c83c28fb9c
commit
c7e2f77893
4 files changed
+472
-4
No files matched your search
@@ -0,0 +1,139 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Configuration
|
||||
const LINKS_FILE = path.join(__dirname, '../themes/Ying/static/json/link_lite.json');
|
||||
const CONCURRENCY = 10; // Check 10 links at a time
|
||||
const TIMEOUT = 10000; // 10 seconds timeout
|
||||
|
||||
async function checkLink(link) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT);
|
||||
|
||||
try {
|
||||
// Some blogs block headless requests, so we fake a User-Agent
|
||||
const response = await fetch(link.url, {
|
||||
method: 'HEAD', // Try HEAD first to save bandwidth
|
||||
signal: controller.signal,
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
||||
}
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (response.ok) {
|
||||
return { link, status: 'OK', code: response.status };
|
||||
} else if (response.status === 405 || response.status === 403 || response.status === 503) {
|
||||
// Some servers reject HEAD or block bots, try GET
|
||||
const controllerGet = new AbortController();
|
||||
const timeoutIdGet = setTimeout(() => controllerGet.abort(), TIMEOUT);
|
||||
try {
|
||||
const responseGet = await fetch(link.url, {
|
||||
method: 'GET',
|
||||
signal: controllerGet.signal,
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
||||
}
|
||||
});
|
||||
clearTimeout(timeoutIdGet);
|
||||
if (responseGet.ok) {
|
||||
return { link, status: 'OK', code: responseGet.status };
|
||||
} else {
|
||||
return { link, status: 'FAIL', code: responseGet.status };
|
||||
}
|
||||
} catch (err) {
|
||||
clearTimeout(timeoutIdGet);
|
||||
return { link, status: 'ERROR', error: err.message };
|
||||
}
|
||||
} else {
|
||||
return { link, status: 'FAIL', code: response.status };
|
||||
}
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId);
|
||||
// Retry with GET if HEAD failed with network error (sometimes happens)
|
||||
if (error.name !== 'AbortError') {
|
||||
const controllerGet = new AbortController();
|
||||
const timeoutIdGet = setTimeout(() => controllerGet.abort(), TIMEOUT);
|
||||
try {
|
||||
const responseGet = await fetch(link.url, {
|
||||
method: 'GET',
|
||||
signal: controllerGet.signal,
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
||||
}
|
||||
});
|
||||
clearTimeout(timeoutIdGet);
|
||||
if (responseGet.ok) {
|
||||
return { link, status: 'OK', code: responseGet.status };
|
||||
} else {
|
||||
return { link, status: 'ERROR', error: error.message }; // Return original error if GET also fails or is not tried properly
|
||||
}
|
||||
} catch (err) {
|
||||
clearTimeout(timeoutIdGet);
|
||||
return { link, status: 'ERROR', error: error.message };
|
||||
}
|
||||
}
|
||||
return { link, status: 'ERROR', error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('Starting friend link check...');
|
||||
console.log(`Reading links from: ${LINKS_FILE}`);
|
||||
|
||||
if (!fs.existsSync(LINKS_FILE)) {
|
||||
console.error('Error: Link file not found!');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let links;
|
||||
try {
|
||||
const fileContent = fs.readFileSync(LINKS_FILE, 'utf8');
|
||||
links = JSON.parse(fileContent);
|
||||
} catch (e) {
|
||||
console.error('Error parsing JSON:', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Found ${links.length} links. Checking...`);
|
||||
|
||||
const results = [];
|
||||
const failedLinks = [];
|
||||
|
||||
// Process in chunks
|
||||
for (let i = 0; i < links.length; i += CONCURRENCY) {
|
||||
const chunk = links.slice(i, i + CONCURRENCY);
|
||||
const chunkResults = await Promise.all(chunk.map(checkLink));
|
||||
|
||||
chunkResults.forEach(res => {
|
||||
if (res.status === 'OK') {
|
||||
process.stdout.write('.'); // Progress indicator
|
||||
} else {
|
||||
process.stdout.write('F');
|
||||
failedLinks.push(res);
|
||||
}
|
||||
results.push(res);
|
||||
});
|
||||
}
|
||||
|
||||
console.log('\n\nCheck completed!');
|
||||
console.log('---------------------------------------------------');
|
||||
|
||||
if (failedLinks.length === 0) {
|
||||
console.log('✅ All links are accessible!');
|
||||
} else {
|
||||
console.log(`⚠️ Found ${failedLinks.length} inaccessible links:\n`);
|
||||
failedLinks.forEach((item, index) => {
|
||||
console.log(`${index + 1}. ${item.link.name} (${item.link.url})`);
|
||||
if (item.code) {
|
||||
console.log(` Status Code: ${item.code}`);
|
||||
} else {
|
||||
console.log(` Error: ${item.error}`);
|
||||
}
|
||||
console.log('');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -70,13 +70,49 @@
|
||||
</style>
|
||||
<div class="post-content" itemprop="articleBody">
|
||||
<div class="links">
|
||||
<ul uk-scrollspy="target: > li; cls: uk-animation-slide-bottom-small; delay: 0">
|
||||
<ul id="links-list" uk-scrollspy="target: > li; cls: uk-animation-slide-bottom-small; delay: 0">
|
||||
<!-- 静态生成的内容作为 SEO 兜底或构建时数据 -->
|
||||
{{ range site.Data.links.blogs }}
|
||||
<li><a href="{{ .url }}" class="url-name">{{ .name }}</a><span style="margin-left: 13px;">{{
|
||||
.description }}</span></li>
|
||||
<li><a href="{{ .url }}" class="url-name" target="_blank">{{ .name }}</a><span style="margin-left: 13px;">{{ .description }}</span></li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
// 配置:友链数据源地址
|
||||
// 1. 本地模块模式:使用 '/json/link_lite.json' (默认)
|
||||
// 2. 远程模式:修改为您的 GitHub + jsDelivr 链接
|
||||
// 例如:const linksJsonUrl = 'https://cdn.jsdelivr.net/gh/您的用户名/您的仓库名@main/link_lite.json';
|
||||
const linksJsonUrl = '/json/link_lite.json';
|
||||
|
||||
const list = document.getElementById('links-list');
|
||||
if (!list) return;
|
||||
|
||||
fetch(linksJsonUrl)
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error('Network response was not ok');
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data && Array.isArray(data) && data.length > 0) {
|
||||
// 清空现有的静态内容,使用动态数据
|
||||
list.innerHTML = '';
|
||||
|
||||
data.forEach(item => {
|
||||
const li = document.createElement('li');
|
||||
// 保持原有的 DOM 结构和类名
|
||||
li.innerHTML = `<a href="${item.url}" class="url-name" target="_blank">${item.name}</a><span style="margin-left: 13px;">${item.description || ''}</span>`;
|
||||
list.appendChild(li);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.warn('友链动态加载失败,回退到静态内容:', error);
|
||||
// 加载失败时保留静态内容 (Hugo 生成的)
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -1,7 +1,8 @@
|
||||
{{ define "main" }}
|
||||
<div id="pjax-container">
|
||||
<div class="post-content" itemprop="articleBody">
|
||||
<div class="items" uk-scrollspy="target: > .item-box; cls: uk-animation-slide-bottom-small; delay: 0">
|
||||
<div id="links-container" class="items" uk-scrollspy="target: > .item-box; cls: uk-animation-slide-bottom-small; delay: 0">
|
||||
<!-- 静态生成的内容作为 SEO 兜底或构建时数据 -->
|
||||
{{ range site.Data.links.blogs }}
|
||||
<div class="item-box">
|
||||
<div class="website-img">
|
||||
@@ -24,5 +25,55 @@
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
// 配置:友链数据源地址 (与 new-links-lite.html 保持一致)
|
||||
// 1. 本地模块模式:使用 '/json/link_lite.json' (默认)
|
||||
// 2. 远程模式:修改为您的 GitHub + jsDelivr 链接
|
||||
const linksJsonUrl = '/json/link_lite.json';
|
||||
|
||||
const container = document.getElementById('links-container');
|
||||
if (!container) return;
|
||||
|
||||
fetch(linksJsonUrl)
|
||||
.then(response => {
|
||||
if (!response.ok) throw new Error('Network response was not ok');
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (data && Array.isArray(data) && data.length > 0) {
|
||||
// 清空现有的静态内容,使用动态数据
|
||||
container.innerHTML = '';
|
||||
|
||||
data.forEach(item => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'item-box';
|
||||
div.innerHTML = `
|
||||
<div class="website-img">
|
||||
<img src="https://s0.wp.com/mshots/v1/${item.url}?w=800&h=600" alt="${item.name}">
|
||||
</div>
|
||||
<div class="link-info">
|
||||
<div class="link-avatar">
|
||||
<img src="${item.image}" alt="${item.name}">
|
||||
</div>
|
||||
<div class="link-des">
|
||||
<div class="link-name">${item.name}</div>
|
||||
<div class="link-des" style="color: #64748B;">${item.description || ''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="${item.url}" target="_blank">
|
||||
<div class="website-go-button">逛一逛</div>
|
||||
</a>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.warn('友链动态加载失败,回退到静态内容:', error);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
{{ end }}
|
||||
@@ -0,0 +1,242 @@
|
||||
[
|
||||
{
|
||||
"name": "吾柯",
|
||||
"url": "https://blog.keepke.com",
|
||||
"description": "保持思考与理性",
|
||||
"image": "https://blog.keepke.com/logo.png"
|
||||
},
|
||||
{
|
||||
"name": "叶开",
|
||||
"url": "https://qq.md",
|
||||
"description": "福建三明尤溪人士",
|
||||
"image": "https://cravatar.cn/avatar/4741124456fb02fa4da30494dbc6c99e?d=monsterid&s=80"
|
||||
},
|
||||
{
|
||||
"name": "一泽",
|
||||
"url": "https://yang99.fun",
|
||||
"description": "感谢相识",
|
||||
"image": "https://q.qlogo.cn/g?b=qq&nk=3369963811@qq.com&s=100"
|
||||
},
|
||||
{
|
||||
"name": "七栀",
|
||||
"url": "https://qydzz.cn",
|
||||
"description": "用文字记录那些时间带走的东西",
|
||||
"image": "https://qydzz.cn/logo.png"
|
||||
},
|
||||
{
|
||||
"name": "若志随笔",
|
||||
"url": "https://www.rz.sb",
|
||||
"description": "一个若志的网络自留地",
|
||||
"image": "https://q1.qlogo.cn/g?b=qq&nk=80360650&s=640"
|
||||
},
|
||||
{
|
||||
"name": "黑桃三",
|
||||
"url": "https://heitaosan.com",
|
||||
"description": "逆着光行走,任风吹雨打",
|
||||
"image": "https://s2.ax1x.com/2020/01/03/lUmf81.png"
|
||||
},
|
||||
{
|
||||
"name": "十七的小栈",
|
||||
"url": "https://blog.allnull.cn",
|
||||
"description": "别让世俗淹没了生活",
|
||||
"image": "https://cravatar.cn/avatar/56238a7f177c534928fd3cf4161ab59e?s=65&r=G&d=mm"
|
||||
},
|
||||
{
|
||||
"name": "Vian",
|
||||
"url": "https://vian.top",
|
||||
"description": "想要的都拥有,得不到的都释怀!",
|
||||
"image": "https://www.vian.top/avatar.ico"
|
||||
},
|
||||
{
|
||||
"name": "油油",
|
||||
"url": "https://blog.200011.net",
|
||||
"description": "A website for myself",
|
||||
"image": "https://q1.qlogo.cn/g?b=qq&nk=1376652515&s=640"
|
||||
},
|
||||
{
|
||||
"name": "段先森",
|
||||
"url": "https://duanxiansen.com",
|
||||
"description": "迄今所有人生都大写着失败,但并不妨碍我继续向前",
|
||||
"image": "https://q.qlogo.cn/g?b=qq&nk=2443266417@qq.com&s=100"
|
||||
},
|
||||
{
|
||||
"name": "Fivk博客",
|
||||
"url": "https://blog.fivk.cn",
|
||||
"description": "相逢的人会再相逢",
|
||||
"image": "https://q1.qlogo.cn/g?b=qq&nk=11470226&s=640"
|
||||
},
|
||||
{
|
||||
"name": "百品博客",
|
||||
"url": "https://baipin.pw",
|
||||
"description": "我欲穿花寻路,直入白云深处,浩气展虹霓",
|
||||
"image": "https://www.baipin.pw/wp-content/uploads/2019/07/cropped-ABUIABACGAAg_bP2wwUorbiplQQwgAU4gAU.jpg"
|
||||
},
|
||||
{
|
||||
"name": "WhiteFan",
|
||||
"url": "https://www.baifan97.cn",
|
||||
"description": "一个斜杠青年的碎碎念",
|
||||
"image": "https://ypy.baifan97.cn/typecho/uploads/img/avatar.png"
|
||||
},
|
||||
{
|
||||
"name": "北枫",
|
||||
"url": "https://beifeng.me",
|
||||
"description": "记录一个人的生活点滴",
|
||||
"image": "https://q1.qlogo.cn/g?b=qq&nk=41777657&s=640"
|
||||
},
|
||||
{
|
||||
"name": "团团生活志",
|
||||
"url": "https://t-t.live",
|
||||
"description": "爱生活 爱分享",
|
||||
"image": "https://img.t-t.live/img/tx.png"
|
||||
},
|
||||
{
|
||||
"name": "臭袜子",
|
||||
"url": "https://huziyan.com",
|
||||
"description": "臭袜子",
|
||||
"image": "https://huziyan.com/usr/themes/icefox/assets/img/tx.jpg"
|
||||
},
|
||||
{
|
||||
"name": "岳泽以",
|
||||
"url": "https://www.yuezeyi.com",
|
||||
"description": "我们历经苦难,我们生生不息",
|
||||
"image": "https://q2.qlogo.cn/g?b=qq&nk=2780008080&s=100"
|
||||
},
|
||||
{
|
||||
"name": "三石的记录",
|
||||
"url": "https://www.fllv.cn",
|
||||
"description": "记录生活",
|
||||
"image": "https://cdn.helingqi.com/wavatar/a25a7640aa68e6d26e32afee8120f7e5?s=65&r=G&d="
|
||||
},
|
||||
{
|
||||
"name": "竹春廿柒",
|
||||
"url": "https://mojinxi.cn",
|
||||
"description": "相视而笑,莫逆于心。",
|
||||
"image": "https://mojinxi.cn/img/logo.png"
|
||||
},
|
||||
{
|
||||
"name": "大嘴狗狗",
|
||||
"url": "https://www.sirit.com.cn",
|
||||
"description": "真正的幸福在于对平淡生活的热爱",
|
||||
"image": "https://www.sirit.com.cn/siritlogo.png"
|
||||
},
|
||||
{
|
||||
"name": "半截の诗",
|
||||
"url": "https://sweetjing.cc/",
|
||||
"description": "一切都会好起来,然后走向正轨,保持热爱,奔赴山海。",
|
||||
"image": "https://q1.qlogo.cn/g?b=qq&nk=1486823198&s=640"
|
||||
},
|
||||
{
|
||||
"name": "XIAOMING'S BLOG",
|
||||
"url": "https://vimin.cc",
|
||||
"description": "记录生活点滴,谱写精彩生活!",
|
||||
"image": "https://cravatar.cn/avatar/6eb95597489dd26f15a973e667d71aef?s=100&r=G&d="
|
||||
},
|
||||
{
|
||||
"name": "网友小宋",
|
||||
"url": "https://xyzbz.cn",
|
||||
"description": "一个九三年的老青年",
|
||||
"image": "https://cravatar.cn/avatar/120340d1df519f4e28613fe5d404b286?s=65&r=G&d="
|
||||
},
|
||||
{
|
||||
"name": "微风忆夏",
|
||||
"url": "https://sumiler.com",
|
||||
"description": "微风轻轻起 夏日不再来",
|
||||
"image": "https://cravatar.cn/avatar//a35f5ef7a4bce3b7cfa6f538ffcae7aa"
|
||||
},
|
||||
{
|
||||
"name": "林林杂语",
|
||||
"url": "https://www.xiaozonglin.cn",
|
||||
"description": "一位来自福建泉州的高中生",
|
||||
"image": "https://cravatar.cn/avatar/04bfc914bd50b42eb507bf66aad0cc31?d=mp"
|
||||
},
|
||||
{
|
||||
"name": "西瓜撞地球",
|
||||
"url": "https://www.bio-w.cn",
|
||||
"description": "我在人间贩卖彩虹",
|
||||
"image": "https://bu.dusays.com/2022/10/17/634d313602a1e.png"
|
||||
},
|
||||
{
|
||||
"name": "Kris Yan",
|
||||
"url": "https://blog.krisyan.dev",
|
||||
"description": "無限進步 @Schale夏萊",
|
||||
"image": "https://cravatar.cn/avatar/05729ab2ca3b99203a674859f77d592b?&d=mp"
|
||||
},
|
||||
{
|
||||
"name": "Echo 的小窝",
|
||||
"url": "https://www.liveout.cn/",
|
||||
"description": "漂泊于互联网中的小窝",
|
||||
"image": "https://cravatar.cn/avatar/d9d83d9ebd03447fff3b094e140a0cbe"
|
||||
},
|
||||
{
|
||||
"name": "未来往事",
|
||||
"url": "https://felixway.cn",
|
||||
"description": "漂泊于互联网中的小窝",
|
||||
"image": "https://cravatar.cn/avatar/2ee35215cbea58cd8b2605e7f517d689?&d=mp"
|
||||
},
|
||||
{
|
||||
"name": "小稚生活志",
|
||||
"url": "https://ihello.cc",
|
||||
"description": "心存阳光,必有诗和远方",
|
||||
"image": "https://bu.dusays.com/2024/02/02/65bbce27b129a.jpg"
|
||||
},
|
||||
{
|
||||
"name": "风呼呼",
|
||||
"url": "https://whooc.com",
|
||||
"description": "寒冻三尺非此界,烈日焦灼正午时!",
|
||||
"image": "https://whooc.com/logo"
|
||||
},
|
||||
{
|
||||
"name": "柳橙睿",
|
||||
"url": "https://www.liuchengrui.cn",
|
||||
"description": "其实我是一个假柳橙",
|
||||
"image": "https://www.liuchengrui.cn/myphoto.png"
|
||||
},
|
||||
{
|
||||
"name": "永恒末匕",
|
||||
"url": "https://likaijian.com",
|
||||
"description": "留下瞬间,记录永恒",
|
||||
"image": "https://q.qlogo.cn/headimg_dl?dst_uin=1527335101&spec=640"
|
||||
},
|
||||
{
|
||||
"name": "刘郎阁",
|
||||
"url": "https://vjo.cc",
|
||||
"description": "一个积极向上的生活探索者!",
|
||||
"image": "https://yjvc.cn/usr/uploads/logo.jpeg"
|
||||
},
|
||||
{
|
||||
"name": "浮沉流年",
|
||||
"url": "https://www.fcln.net",
|
||||
"description": "借一点落日的光与来日方长",
|
||||
"image": "https://cravatar.cn/avatar//4355eea603309a0c159ca27f54e27c89?s=65&r=G&d="
|
||||
},
|
||||
{
|
||||
"name": "二十六",
|
||||
"url": "https://www.ershiliu.com/",
|
||||
"description": "人生如逆旅,我亦是行人。",
|
||||
"image": "https://www.ershiliu.com/favicon.ico"
|
||||
},
|
||||
{
|
||||
"name": "阿呆日记",
|
||||
"url": "https://dai.ge",
|
||||
"description": "肥宅的摆烂生活",
|
||||
"image": "https://dai.ge/img/logo.png"
|
||||
},
|
||||
{
|
||||
"name": "邹江博客",
|
||||
"url": "https://www.zoujiang.com",
|
||||
"description": "热爱你来过的每度温暖",
|
||||
"image": "https://www.zoujiang.com/logo.jpg"
|
||||
},
|
||||
{
|
||||
"name": "清梦云熙",
|
||||
"url": "https://skylan.cc",
|
||||
"description": "相逢何必曾相识",
|
||||
"image": "https://cravatar.cn/avatar/853572275a978dbccefbe2242ba1c415"
|
||||
},
|
||||
{
|
||||
"name": "如约而至",
|
||||
"url": "https://aloner.ink",
|
||||
"description": "随便写写",
|
||||
"image": "https://cravatar.cn/avatar/af1874b7856255302fc3df5102a6ce6d"
|
||||
}
|
||||
]
|
||||
Reference in new issue
Block a user