docs: 替换 GitHub 图片资源链接为代理链接
This commit is contained in:
parent
1e0949703f
commit
1015736635
@ -62,6 +62,7 @@ export default async ({ mode }) => {
|
|||||||
targetUrl: '/issues',
|
targetUrl: '/issues',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
githubProxy: 'https://cloudflare-github-proxy.hanxi-info.workers.dev/proxy',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -11,55 +11,56 @@ interface ReplaceRule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface GitHubIssuesPluginOptions {
|
interface GitHubIssuesPluginOptions {
|
||||||
repo: string; // GitHub repository info in the format 'owner/repo'
|
repo: string; // GitHub repository info in the format 'owner/repo'
|
||||||
token: string;
|
token: string;
|
||||||
replaceRules: ReplaceRule[];
|
replaceRules: ReplaceRule[];
|
||||||
|
githubProxy: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAllIssues(repo: string, token: string): Promise<any[]> {
|
async function fetchAllIssues(repo: string, token: string): Promise<any[]> {
|
||||||
const maxRetries = 3; // 最大重试次数
|
const maxRetries = 3; // 最大重试次数
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
const allIssues: any[] = [];
|
const allIssues: any[] = [];
|
||||||
let page = 1;
|
let page = 1;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
while (attempt < maxRetries) {
|
while (attempt < maxRetries) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`https://api.github.com/repos/${repo}/issues`, {
|
const response = await axios.get(`https://api.github.com/repos/${repo}/issues`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `token ${token}`
|
Authorization: `token ${token}`
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
page: page,
|
page: page,
|
||||||
per_page: 100 // 每页最多返回100条记录
|
per_page: 100 // 每页最多返回100条记录
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 如果没有更多问题了,退出循环
|
// 如果没有更多问题了,退出循环
|
||||||
if (response.data.length === 0) {
|
if (response.data.length === 0) {
|
||||||
return allIssues;
|
return allIssues;
|
||||||
}
|
}
|
||||||
|
|
||||||
allIssues.push(...response.data);
|
allIssues.push(...response.data);
|
||||||
page++; // 下一页
|
page++; // 下一页
|
||||||
attempt = 0; // 重置尝试次数
|
attempt = 0; // 重置尝试次数
|
||||||
break; // 退出尝试循环
|
break; // 退出尝试循环
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.status === 503) {
|
if (error.response && error.response.status === 503) {
|
||||||
console.error(`服务不可用, 正在重试...`);
|
console.error(`服务不可用, 正在重试...`);
|
||||||
attempt++;
|
attempt++;
|
||||||
const waitTime = Math.pow(2, attempt) * 1000; // 指数等待时间
|
const waitTime = Math.pow(2, attempt) * 1000; // 指数等待时间
|
||||||
await new Promise(resolve => setTimeout(resolve, waitTime));
|
await new Promise(resolve => setTimeout(resolve, waitTime));
|
||||||
} else {
|
} else {
|
||||||
throw error; // 如果不是503错误,抛出错误并停止重试
|
throw error; // 如果不是503错误,抛出错误并停止重试
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attempt >= maxRetries) {
|
if (attempt >= maxRetries) {
|
||||||
throw new Error('最大重试次数已达,请检查 API 状态(可能是请求过于频繁)');
|
throw new Error('最大重试次数已达,请检查 API 状态(可能是请求过于频繁)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchIssueComments(repo: string, issueNumber: number, token: string): Promise<any[]> {
|
async function fetchIssueComments(repo: string, issueNumber: number, token: string): Promise<any[]> {
|
||||||
@ -111,69 +112,69 @@ async function fetchIssueComments(repo: string, issueNumber: number, token: stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearDirectory(dir: string) {
|
function clearDirectory(dir: string) {
|
||||||
if (fs.existsSync(dir)) {
|
if (fs.existsSync(dir)) {
|
||||||
fs.readdirSync(dir).forEach((file) => {
|
fs.readdirSync(dir).forEach((file) => {
|
||||||
const filePath = path.join(dir, file);
|
const filePath = path.join(dir, file);
|
||||||
if (fs.lstatSync(filePath).isDirectory()) {
|
if (fs.lstatSync(filePath).isDirectory()) {
|
||||||
clearDirectory(filePath); // 递归清理子目录
|
clearDirectory(filePath); // 递归清理子目录
|
||||||
fs.rmdirSync(filePath);
|
fs.rmdirSync(filePath);
|
||||||
} else {
|
} else {
|
||||||
fs.unlinkSync(filePath); // 删除文件
|
fs.unlinkSync(filePath); // 删除文件
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log(`Cleared directory: ${dir}`);
|
console.log(`Cleared directory: ${dir}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyReadmeFile(source: string, destination: string) {
|
function copyReadmeFile(source: string, destination: string) {
|
||||||
if (fs.existsSync(source)) {
|
if (fs.existsSync(source)) {
|
||||||
fs.copyFileSync(source, destination);
|
fs.copyFileSync(source, destination);
|
||||||
console.log(`Copied README.md from ${source} to ${destination}`);
|
console.log(`Copied README.md from ${source} to ${destination}`);
|
||||||
} else {
|
} else {
|
||||||
console.error(`README.md not found at ${source}`);
|
console.error(`README.md not found at ${source}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function GitHubIssuesPlugin(options: GitHubIssuesPluginOptions): Plugin {
|
export default function GitHubIssuesPlugin(options: GitHubIssuesPluginOptions): Plugin {
|
||||||
const { repo, token, replaceRules } = options;
|
const { repo, token, replaceRules, githubProxy } = options;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'vitepress-plugin-github-issues',
|
name: 'vitepress-plugin-github-issues',
|
||||||
|
|
||||||
async buildStart() {
|
async buildStart() {
|
||||||
try {
|
try {
|
||||||
const issues = await fetchAllIssues(repo, token);
|
const issues = await fetchAllIssues(repo, token);
|
||||||
|
|
||||||
console.log(`Fetched ${issues.length} issues from GitHub`); // Log the number of issues fetched
|
console.log(`Fetched ${issues.length} issues from GitHub`); // Log the number of issues fetched
|
||||||
|
|
||||||
const docsDir = path.join(process.cwd(), 'issues');
|
const docsDir = path.join(process.cwd(), 'issues');
|
||||||
|
|
||||||
// 清空 issues 目录
|
// 清空 issues 目录
|
||||||
clearDirectory(docsDir);
|
clearDirectory(docsDir);
|
||||||
|
|
||||||
// Create a directory to store markdown files if it doesn't exist
|
// Create a directory to store markdown files if it doesn't exist
|
||||||
if (!fs.existsSync(docsDir)) {
|
if (!fs.existsSync(docsDir)) {
|
||||||
fs.mkdirSync(docsDir);
|
fs.mkdirSync(docsDir);
|
||||||
console.log(`Created docs directory: ${docsDir}`);
|
console.log(`Created docs directory: ${docsDir}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拷贝 ../README.md 文件到当前目录
|
// 拷贝 ../README.md 文件到当前目录
|
||||||
const readmeSource = path.join(process.cwd(), '../README.md');
|
const readmeSource = path.join(process.cwd(), '../README.md');
|
||||||
const readmeDestination = path.join(docsDir, 'index.md');
|
const readmeDestination = path.join(docsDir, 'index.md');
|
||||||
copyReadmeFile(readmeSource, readmeDestination);
|
copyReadmeFile(readmeSource, readmeDestination);
|
||||||
|
|
||||||
for (const issue of issues) {
|
for (const issue of issues) {
|
||||||
// 仅处理包含 "文档" 标签的 issue
|
// 仅处理包含 "文档" 标签的 issue
|
||||||
const hasDocumentLabel = issue.labels.some(label => label.name === '文档');
|
const hasDocumentLabel = issue.labels.some(label => label.name === '文档');
|
||||||
if (hasDocumentLabel) {
|
if (hasDocumentLabel) {
|
||||||
const title = issue.title.replace(/[\/\\?%*:|"<>]/g, '-');
|
const title = issue.title.replace(/[\/\\?%*:|"<>]/g, '-');
|
||||||
const fileName = `${issue.number}.md`;
|
const fileName = `${issue.number}.md`;
|
||||||
|
|
||||||
// 获取评论数据
|
// 获取评论数据
|
||||||
const comments = await fetchIssueComments(repo, issue.number, token);
|
const comments = await fetchIssueComments(repo, issue.number, token);
|
||||||
|
|
||||||
let content =
|
let content =
|
||||||
`---
|
`---
|
||||||
title: ${issue.title}
|
title: ${issue.title}
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -185,44 +186,52 @@ ${issue.body}
|
|||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// 插入评论
|
// 插入评论
|
||||||
if (comments.length > 0) {
|
if (comments.length > 0) {
|
||||||
comments.forEach((comment, index) => {
|
comments.forEach((comment, index) => {
|
||||||
content += `
|
content += `
|
||||||
### 评论 ${index + 1} - ${comment.user.login}
|
### 评论 ${index + 1} - ${comment.user.login}
|
||||||
|
|
||||||
${comment.body}
|
${comment.body}
|
||||||
|
|
||||||
---
|
---
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
content += "没有评论。\n";
|
content += "没有评论。\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceRules.forEach(({ baseUrl, targetUrl }) => {
|
replaceRules.forEach(({ baseUrl, targetUrl }) => {
|
||||||
// 将 baseUrl 转换为正则表达式,匹配后接的路径部分
|
// 将 baseUrl 转换为正则表达式,匹配后接的路径部分
|
||||||
const pattern = new RegExp(`${baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}(/\\d+)`, 'g');
|
const pattern = new RegExp(`${baseUrl.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}(/\\d+)`, 'g');
|
||||||
// 替换为目标 URL
|
// 替换为目标 URL
|
||||||
content = content.replace(pattern, `${targetUrl}$1.html`);
|
content = content.replace(pattern, `${targetUrl}$1.html`);
|
||||||
});
|
});
|
||||||
|
|
||||||
content += `[链接到 GitHub Issue](${issue.html_url})\n`
|
content = content.replace(
|
||||||
|
/(https:\/\/github\.com\/([^\/]+\/[^\/]+\/assets\/[^\s]+)/g,
|
||||||
|
(match, p1) => {
|
||||||
|
const proxyUrl = `${githubProxy}/${p1}`; // 使用传入的 base URL
|
||||||
|
return proxyUrl;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const filePath = path.join(docsDir, fileName);
|
content += `[链接到 GitHub Issue](${issue.html_url})\n`
|
||||||
|
|
||||||
fs.writeFileSync(filePath, content, { encoding: 'utf8' });
|
const filePath = path.join(docsDir, fileName);
|
||||||
console.log(`Created file: ${filePath}`); // Log each created file
|
|
||||||
} else {
|
|
||||||
console.log(`Skipped issue: ${issue.title}`); // Log skipped issues
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Successfully created markdown files from GitHub issues.`);
|
fs.writeFileSync(filePath, content, { encoding: 'utf8' });
|
||||||
} catch (error) {
|
console.log(`Created file: ${filePath}`); // Log each created file
|
||||||
console.error('Error fetching GitHub issues:', error);
|
} else {
|
||||||
}
|
console.log(`Skipped issue: ${issue.title}`); // Log skipped issues
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
console.log(`Successfully created markdown files from GitHub issues.`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching GitHub issues:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user