| 34 | } |
| 35 | |
| 36 | export class GitHubAPI { |
| 37 | private static readonly REPO_OWNER = 'chokcoco'; |
| 38 | private static readonly REPO_NAME = 'iCSS'; |
| 39 | private static readonly BASE_URL = 'https://api.github.com'; |
| 40 | |
| 41 | // 获取 GitHub Token |
| 42 | private static getGitHubToken(): string | undefined { |
| 43 | return process.env.GITHUB_TOKEN; |
| 44 | } |
| 45 | |
| 46 | // 构建请求头 |
| 47 | private static getHeaders(): HeadersInit { |
| 48 | const headers: HeadersInit = { |
| 49 | 'Accept': 'application/vnd.github.v3+json', |
| 50 | 'User-Agent': 'iCSS-Website' |
| 51 | }; |
| 52 | |
| 53 | const token = this.getGitHubToken(); |
| 54 | if (token) { |
| 55 | headers['Authorization'] = `token ${token}`; |
| 56 | } |
| 57 | |
| 58 | return headers; |
| 59 | } |
| 60 | |
| 61 | // 从 issue 内容中提取图片 |
| 62 | private static extractImageFromBody(body: string): string | undefined { |
| 63 | if (!body) return undefined; |
| 64 | |
| 65 | // 匹配 Markdown 图片  |
| 66 | const markdownImageMatch = body.match(/!\[.*?\]\((https?:\/\/[^)]+\.(?:png|jpg|jpeg|gif|webp))\)/); |
| 67 | if (markdownImageMatch) { |
| 68 | return markdownImageMatch[1]; |
| 69 | } |
| 70 | |
| 71 | // 匹配 HTML 图片标签 <img src="..."> |
| 72 | const htmlImageMatch = body.match(/<img[^>]+src\s*=\s*["'](https?:\/\/[^"']+\.(?:png|jpg|jpeg|gif|webp))["'][^>]*>/); |
| 73 | if (htmlImageMatch) { |
| 74 | return htmlImageMatch[1]; |
| 75 | } |
| 76 | |
| 77 | return undefined; |
| 78 | } |
| 79 | |
| 80 | // 从 issue 内容中提取分类 |
| 81 | private static extractCategoryFromBody(body: string): string | undefined { |
| 82 | if (!body) return undefined; |
| 83 | |
| 84 | // 匹配标题中的分类标记,如 【动画】、【布局】等 |
| 85 | const categoryMatch = body.match(/【([^】]+)】/); |
| 86 | if (categoryMatch) { |
| 87 | return categoryMatch[1]; |
| 88 | } |
| 89 | |
| 90 | // 匹配标签中的分类 |
| 91 | const tagMatch = body.match(/标签[::]\s*([^\n\r]+)/); |
| 92 | if (tagMatch) { |
| 93 | return tagMatch[1].trim(); |
nothing calls this directly
no outgoing calls
no test coverage detected