惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
博客园 - 聂微东
Microsoft Azure Blog
Microsoft Azure Blog
V
Visual Studio Blog
IT之家
IT之家
博客园 - 【当耐特】
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
B
Blog
爱范儿
爱范儿
阮一峰的网络日志
阮一峰的网络日志
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Help Net Security
J
Java Code Geeks
aimingoo的专栏
aimingoo的专栏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
B
Blog RSS Feed
Blog — PlanetScale
Blog — PlanetScale
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research

新锐博客

vscode连接cnb并推送仓库 - 新锐博客 twikoo不用token查询文章浏览量 - 新锐博客 基于Astro构建的支持对话与生图的Web应用 - 新锐博客 deepseek-v4-flash-0731使用体验 - 新锐博客 基元律动免费送68元额度 - 新锐博客 Linux更换软件源 - 新锐博客 华为鸿蒙7.0花粉beta版发布 - 新锐博客 使用测速脚本测一下服务器带宽 - 新锐博客 trae告别白嫖时代,auto也需排队了 - 新锐博客 流量不够用?大流量卡免费领 - 新锐博客 推荐一个免费在线图片处理网站 - 新锐博客 AI清理C盘的优缺点 - 新锐博客 twikoo不算bug的bug - 新锐博客 最近网站的一些变动 - 新锐博客 腾讯EO开始发多余套餐啦!速领 - 新锐博客 hi168停止对个人用户的运营 - 新锐博客 哪吒监控曝高危漏洞,请尽快升级 - 新锐博客 IndexDB实现大文件下载的思路 - 新锐博客 鱼鱼api使用教程 - 新锐博客 服务器安装Dokploy替代vercel - 新锐博客 对于近几年的电视剧的无力吐槽 - 新锐博客 关于网站被攻击的后续 - 新锐博客 使用sessionStorage给音乐播放进度存储 - 新锐博客 修复了一些bug,网站基本上趋于稳定了 - 新锐博客 AI模型掺水?如何辨别真假? - 新锐博客 感谢一九云给我防住了攻击 - 新锐博客 对一些新手使用AI编程的建议 - 新锐博客 Edgeone标记过期和直接删除有何区别? - 新锐博客 用Navigation Timing API给博客添加上加载时间 - 新锐博客 使用 Astro 自建博客,从零开始鏖战 14 小时 - 新锐博客
利用Github Actions检测友链状态 - 新锐博客
莫忘 · 2025-08-15 · via 新锐博客

前言

之前就写了用cloudflare检测友链的状态,但是cloudflare最近访问有点困难,就想到用github Action来解决这一事情

效果

友链检测

教程

首先就是添加links.js文件,并且添加如下代码

const fs = require('fs');
const path = require('path');

hexo.extend.generator.register('links-api', function(locals) {
  const linksData = hexo.locals.get('data').links;
  
  if (!linksData) {
    return;
  }

  // 获取实际的链接数据
  const actualLinksData = linksData.links;
  
  if (!actualLinksData || !Array.isArray(actualLinksData)) {
    return;
  }

  // 查找"小伙伴"分类
  let xiaohuobanCategory = null;
  
  for (const category of actualLinksData) {
    if (category.class_name === '小伙伴') {
      xiaohuobanCategory = category;
      break;
    }
  }

  if (!xiaohuobanCategory || !xiaohuobanCategory.link_list) {
    return;
  }

  // 构建API数据 - 转换为指定格式
  const friends = xiaohuobanCategory.link_list.map(link => [
    link.name,        // 网站名称
    link.link,        // 网站链接
    link.avatar       // 网站图标
  ]);

  const apiData = {
    friends: friends
  };

  // 确保目录存在
  const apiDir = path.join(hexo.public_dir, 'api');
  if (!fs.existsSync(apiDir)) {
    fs.mkdirSync(apiDir, { recursive: true });
  }

  // 写入JSON文件
  const filePath = path.join(apiDir, 'links.json');
  fs.writeFileSync(filePath, JSON.stringify(apiData, null, 2), 'utf8');

  return {
    path: '/links.json',
    data: JSON.stringify(apiData, null, 2)
  };
}); 

此代码的作用就是生成以小伙伴分类为基础的友链json文件,你可以根据实际情况进行修改

然后就是到github中fork我的项目links-status到自己的仓库

点击编辑config.yml中的内容就可以修改设置了。

找到Actions找到检测友链状态的脚本点击RUN workflow就可以了

因为不会写代码,一切都是AI写的,所以在生成文件到page分支的时候很慢,大约需要三分钟

构建好以后可以用vercel,edgeone pages等平台选择page分支部署就可以了,然后将代码中的json文件地址替换成你自己的

如果你有更好的方法可以留言告诉我,一起进步!~

最后就是solitude主题怎么引入呢?

很简单,就是在source文件夹的js文件夹中添加一个links-status.js的文件,并且放入代码

// 友链状态检测脚本
let retryCount = 0;
const MAX_RETRIES = 3;
const STATUS_URL = 'https://links.ityr.xyz/status.json';

function fetchLinkStatus() {
    return fetch(STATUS_URL)
        .then(response => {
            if (!response.ok) {
                throw new Error('网络请求失败');
            }
            return response.json();
        });
}

function updateLinkStatus(data) {
    if (data && data.link_status) {
        const statusMap = {};
        data.link_status.forEach(link => {
            statusMap[link.name] = link;
        });
        
        // 更新每个链接的状态
        const statusElements = document.querySelectorAll('.site-card-status');
        statusElements.forEach(el => {
            const linkName = el.getAttribute('data-name');
            if (statusMap[linkName]) {
                const status = statusMap[linkName];
                let statusClass = '';
                let statusText = '';
                
                // 根据success字段和latency判断状态
                if (!status.success || status.latency === -1) {
                    statusClass = 'status-error';
                    const errorCount = status.error_count || 0;
                    statusText = "异常[" + errorCount + "]";
                } else {
                    // 显示响应时间
                    const latency = status.latency;
                    if (latency <= 3) {
                        statusClass = 'status-normal';
                    } else {
                        statusClass = 'status-slow';
                    }
                    statusText = latency + 's';
                }
                
                // 更新状态
                el.className = 'site-card-status ' + statusClass;
                el.textContent = statusText;
                el.classList.remove('status-loading');
            }
        });
    } else {
        throw new Error('无效的状态数据');
    }
}

function handleError() {
    retryCount++;
    if (retryCount <= MAX_RETRIES) {
        setTimeout(fetchAndUpdateStatus, 2000 * retryCount); // 2秒、4秒、6秒后重试
    } else {
        // 将所有状态设为错误
        document.querySelectorAll('.site-card-status.status-loading').forEach(el => {
            el.className = 'site-card-status status-error';
            el.textContent = '获取失败';
        });
    }
}

function fetchAndUpdateStatus() {
    fetchLinkStatus()
        .then(data => updateLinkStatus(data))
        .catch(error => {
            console.error('获取友链状态失败:', error);
            handleError();
        });
}

// 页面加载后立即执行
document.addEventListener('DOMContentLoaded', fetchAndUpdateStatus);

// 支持PJAX重新加载
document.addEventListener('pjax:complete', fetchAndUpdateStatus); 

再然后到_config.solitude.yml文件的body中引入该文件,并且在自定义CSS文件中添加代码

.site-card {
	position: relative
}

.flink-list-item {
	position: relative
}

.site-card-status {
	position: absolute;
	bottom: 0;
	right: 0;
	z-index: 10;
	padding: 3px 8px;
	border-radius: 8px 0 8px 0;
	font-size: 12px;
	font-weight: 500;
	color: #fff;
	background-color: rgba(0, 0, 0, 0.6);
	backdrop-filter: blur(4px);
	transition: all 0.3s ease
}

.site-card-status.status-loading {
	background-color: rgba(100, 100, 100, 0.8);
	animation: pulse 1.5s infinite
}

.site-card-status.status-normal {
	background-color: rgba(82, 196, 26, 0.9)
}

.site-card-status.status-slow {
	background-color: rgba(250, 173, 20, 0.9)
}

.site-card-status.status-error {
	background-color: rgba(255, 77, 79, 0.9)
}

@keyframes pulse {

	0%,
	100% {
		opacity: 1
	}

	50% {
		opacity: 0.5
	}
}

[data-theme="dark"] .site-card-status {
	background-color: rgba(255, 255, 255, 0.1);
	color: #fff
}

[data-theme="dark"] .site-card-status.status-loading {
	background-color: rgba(100, 100, 100, 0.8)
}

[data-theme="dark"] .site-card-status.status-normal {
	background-color: rgba(82, 196, 26, 0.8)
}

[data-theme="dark"] .site-card-status.status-slow {
	background-color: rgba(250, 173, 20, 0.8)
}

[data-theme="dark"] .site-card-status.status-error {
	background-color: rgba(255, 77, 79, 0.8)
}

.flink-templates {
	margin-top: 2rem;
	padding: 1.5rem;
	background: var(--efu-card-bg);
	border-radius: 12px;
	border: var(--style-border-always);
	box-shadow: var(--efu-shadow-border)
}

.flink-templates h3 {
	margin-bottom: 1rem;
	font-size: 1.2rem;
	font-weight: 600;
	color: var(--efu-fontcolor)
}

.template-buttons {
	display: flex;
	gap: 1rem;
	flex-wrap: wrap
}

.template-btn {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 0.75rem 1.5rem;
	border: none;
	border-radius: 8px;
	font-size: 14px;
	font-weight: 500;
	cursor: pointer;
	transition: all 0.3s ease;
	background: var(--efu-theme);
	color: #fff
}

.template-btn:hover {
	transform: translateY(-2px);
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15)
}

.template-btn i {
	font-size: 16px
}

.template-btn.markdown-btn {
	background: #10b981
}

.template-btn.markdown-btn:hover {
	background: #059669
}

[data-theme="dark"] .flink-templates {
	background: var(--efu-card-bg);
	border-color: var(--efu-border)
}

[data-theme="dark"] .template-btn {
	background: var(--efu-theme)
}

[data-theme="dark"] .template-btn.markdown-btn {
	background: #10b981
}

最后就是一键三连即可看到效果了

莫忘

君子喻以义,小人喻以利

本文是原创文章,采用 CC BY-NC-SA 4.0 协议,完整转载请注明来自 新锐博客