refactor: 改用 Imgur 图床上传图片

This commit is contained in:
yhh
2025-12-04 09:56:10 +08:00
parent 17f6259f43
commit 566e1977fd

View File

@@ -810,9 +810,12 @@ export class ForumService {
// 图片上传 | Image Upload // 图片上传 | Image Upload
// ===================================================== // =====================================================
/** Imgur Client ID (匿名上传) | Imgur Client ID (anonymous upload) */
private readonly IMGUR_CLIENT_ID = '546c25a59c58ad7';
/** /**
* 上传图片到 GitHub 仓库 * 上传图片到 Imgur 图床
* Upload image to GitHub repository * Upload image to Imgur
* @param file 图片文件 | Image file * @param file 图片文件 | Image file
* @param onProgress 进度回调 | Progress callback * @param onProgress 进度回调 | Progress callback
* @returns 图片 URL | Image URL * @returns 图片 URL | Image URL
@@ -821,72 +824,54 @@ export class ForumService {
file: File, file: File,
onProgress?: (progress: number) => void onProgress?: (progress: number) => void
): Promise<string> { ): Promise<string> {
const token = this.currentUser?.accessToken;
if (!token) {
throw new Error('Not authenticated');
}
// 验证文件类型 | Validate file type // 验证文件类型 | Validate file type
const allowedTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp']; const allowedTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp'];
if (!allowedTypes.includes(file.type)) { if (!allowedTypes.includes(file.type)) {
throw new Error('Only PNG, JPEG, GIF, and WebP images are allowed'); throw new Error('Only PNG, JPEG, GIF, and WebP images are allowed');
} }
// 限制文件大小 (5MB) | Limit file size (5MB) // 限制文件大小 (10MB - Imgur 限制) | Limit file size (10MB - Imgur limit)
const maxSize = 5 * 1024 * 1024; const maxSize = 10 * 1024 * 1024;
if (file.size > maxSize) { if (file.size > maxSize) {
throw new Error('Image size must be less than 5MB'); throw new Error('Image size must be less than 10MB');
} }
onProgress?.(10); onProgress?.(10);
// 生成唯一文件名 | Generate unique filename
const ext = file.name.split('.').pop() || 'png';
const timestamp = Date.now();
const randomStr = Math.random().toString(36).substring(2, 8);
const fileName = `${timestamp}-${randomStr}.${ext}`;
const filePath = `forum-images/${fileName}`;
onProgress?.(20);
// 读取文件为 base64 | Read file as base64 // 读取文件为 base64 | Read file as base64
const base64Content = await this.fileToBase64(file); const base64Content = await this.fileToBase64(file);
onProgress?.(40); onProgress?.(30);
// 使用 GitHub REST API 上传文件 | Upload file using GitHub REST API // 使用 Imgur API 上传 | Upload using Imgur API
const response = await fetch( const response = await fetch('https://api.imgur.com/3/image', {
`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/contents/${filePath}`, method: 'POST',
{ headers: {
method: 'PUT', 'Authorization': `Client-ID ${this.IMGUR_CLIENT_ID}`,
headers: { 'Content-Type': 'application/json'
'Authorization': `Bearer ${token}`, },
'Content-Type': 'application/json', body: JSON.stringify({
'Accept': 'application/vnd.github.v3+json' image: base64Content,
}, type: 'base64'
body: JSON.stringify({ })
message: `Upload forum image: ${fileName}`, });
content: base64Content,
branch: 'master'
})
}
);
onProgress?.(80); onProgress?.(80);
if (!response.ok) { if (!response.ok) {
const errorData = await response.json().catch(() => ({})); const errorData = await response.json().catch(() => ({}));
console.error('[ForumService] Upload failed:', errorData); console.error('[ForumService] Imgur upload failed:', errorData);
throw new Error(`Failed to upload image: ${response.status}`); throw new Error(`Failed to upload image: ${response.status}`);
} }
const data = await response.json(); const data = await response.json();
onProgress?.(100); onProgress?.(100);
// 返回 raw URL | Return raw URL if (!data.success || !data.data?.link) {
// 使用 jsdelivr CDN 加速 | Use jsdelivr CDN for acceleration throw new Error('Imgur upload failed: invalid response');
const cdnUrl = `https://cdn.jsdelivr.net/gh/${REPO_OWNER}/${REPO_NAME}@master/${filePath}`; }
return cdnUrl;
return data.data.link;
} }
/** /**