Files
CloudFlare-ImgBed/functions/utils/discordAPI.js

187 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Discord API 封装类
* 用于上传文件到 Discord 频道并获取文件
*/
export class DiscordAPI {
constructor(botToken) {
this.botToken = botToken;
this.baseURL = 'https://discord.com/api/v10';
this.defaultHeaders = {
'Authorization': `Bot ${this.botToken}`,
'User-Agent': 'DiscordBot (CloudFlare-ImgBed, 1.0)'
};
}
/**
* 发送文件到 Discord 频道
* @param {File|Blob} file - 要发送的文件
* @param {string} channelId - 频道 ID
* @param {string} fileName - 文件名
* @returns {Promise<Object>} API 响应结果
*/
async sendFile(file, channelId, fileName = '') {
const formData = new FormData();
// Discord 使用 files[0] 作为文件字段名
if (fileName) {
formData.append('files[0]', file, fileName);
} else {
formData.append('files[0]', file);
}
const response = await fetch(`${this.baseURL}/channels/${channelId}/messages`, {
method: 'POST',
headers: this.defaultHeaders,
body: formData
});
console.log('Discord API response:', response.status, response.statusText);
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(`Discord API error: ${response.status} - ${errorData.message || response.statusText}`);
}
const responseData = await response.json();
return responseData;
}
/**
* 从响应中提取文件信息
* @param {Object} responseData - Discord API 响应数据
* @returns {Object|null} 文件信息对象或 null
*/
getFileInfo(responseData) {
try {
if (!responseData || !responseData.id) {
console.error('Invalid Discord response:', responseData);
return null;
}
// Discord 消息中的附件在 attachments 数组中
if (responseData.attachments && responseData.attachments.length > 0) {
const attachment = responseData.attachments[0];
return {
message_id: responseData.id,
attachment_id: attachment.id,
file_name: attachment.filename,
file_size: attachment.size,
content_type: attachment.content_type,
url: attachment.url,
proxy_url: attachment.proxy_url
};
}
return null;
} catch (error) {
console.error('Error parsing Discord response:', error.message);
return null;
}
}
/**
* 获取消息信息(用于获取文件 URL
* @param {string} channelId - 频道 ID
* @param {string} messageId - 消息 ID
* @param {number} maxRetries - 最大重试次数(默认 3 次)
* @returns {Promise<Object|null>} 消息数据或 null
*/
async getMessage(channelId, messageId, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(`${this.baseURL}/channels/${channelId}/messages/${messageId}`, {
method: 'GET',
headers: this.defaultHeaders
});
// 429 速率限制:等待后重试
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
const waitTime = retryAfter ? parseFloat(retryAfter) * 1000 : 1000 * (attempt + 1);
console.warn(`Discord 429 rate limit, waiting ${waitTime}ms before retry ${attempt + 1}/${maxRetries}`);
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
}
if (!response.ok) {
console.error('Discord getMessage error:', response.status, response.statusText);
return null;
}
const messageData = await response.json();
return messageData;
} catch (error) {
console.error('Error getting Discord message:', error.message);
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 500 * (attempt + 1)));
continue;
}
return null;
}
}
return null;
}
/**
* 获取文件 URL
* @param {string} channelId - 频道 ID
* @param {string} messageId - 消息 ID
* @returns {Promise<string|null>} 文件 URL 或 null
*/
async getFileURL(channelId, messageId) {
const message = await this.getMessage(channelId, messageId);
if (message && message.attachments && message.attachments.length > 0) {
return message.attachments[0].url;
}
return null;
}
/**
* 获取文件内容
* @param {string} channelId - 频道 ID
* @param {string} messageId - 消息 ID
* @returns {Promise<Response>} 文件响应
*/
async getFileContent(channelId, messageId) {
const fileURL = await this.getFileURL(channelId, messageId);
if (!fileURL) {
throw new Error(`File URL not found for messageId: ${messageId}`);
}
const response = await fetch(fileURL);
return response;
}
/**
* 删除消息(用于删除文件)
* @param {string} channelId - 频道 ID
* @param {string} messageId - 消息 ID
* @returns {Promise<boolean>} 是否删除成功
*/
async deleteMessage(channelId, messageId) {
try {
const response = await fetch(`${this.baseURL}/channels/${channelId}/messages/${messageId}`, {
method: 'DELETE',
headers: this.defaultHeaders
});
// Discord 删除成功返回 204 No Content
if (response.status === 204 || response.ok) {
return true;
}
console.error('Discord deleteMessage error:', response.status, response.statusText);
return false;
} catch (error) {
console.error('Error deleting Discord message:', error.message);
return false;
}
}
}