- GuildPlayer: 타이머 레이스 컨디션 수정, 모든 타이머 정리 로직 통합 (clearAllTimers) - GuildPlayer: 이벤트 핸들러에 try-catch 추가 (end, exception, stuck) - GuildPlayer: start 이벤트에서 endTimer 정리, autoPlay tracks 길이 검증 추가 - RedisClient: player_seek, player_volume에 누락된 return ���가 - RedisClient: queue_remove 인덱스 검증 주석 명확화 - Handler: runCommand에 try-catch 추가하여 에러 시 사용자에게 응답 - Channel: getGuildById에 누락된 await 추가, getMemberById/getVoiceChannelById 안전한 에러 처리 - Command.d.ts: 잘못된 타입 ChatInputChatInputCommandInteraction → ChatInputCommandInteraction 수정 - join.ts: 채널 멘션 닫는 괄호 누락 수정 - shuffle.ts: 제네릭 타입 적용, 불필요한 5회 반복 제거 - import 경로 대소문자 수정 (Shuffle → shuffle) - Linux 호환 - YoutubeMusic/Spotify: 하드코딩된 IP를 환경변수로 분리 - console.log/error → Logger 통일 (YoutubeMusic, Button, channel) - interactionCreate: 전체 try-catch 추가, silent catch에 로깅 추가 - Database: schema 경로 __dirname 기반으로 수정, 컬럼 화이트리스트 추가 - 사용하지 않는 코드 정리 (axios 의존성, 주석처리된 user 관련 코드) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
79 lines
2.9 KiB
TypeScript
79 lines
2.9 KiB
TypeScript
import { Client, ClientEvents, ColorResolvable, EmbedBuilder, EmbedField, GatewayIntentBits, Message } from "discord.js";
|
|
import { Config } from "../utils/Config";
|
|
import { Logger } from "../utils/Logger";
|
|
|
|
export class BotClient extends Client {
|
|
public prefix = Config.prefix;
|
|
public color: ColorResolvable = Config.embedColor;
|
|
public constructor() {
|
|
super({
|
|
intents: [
|
|
GatewayIntentBits.Guilds,
|
|
GatewayIntentBits.GuildMembers,
|
|
GatewayIntentBits.GuildMessages,
|
|
GatewayIntentBits.MessageContent,
|
|
GatewayIntentBits.GuildVoiceStates,
|
|
],
|
|
});
|
|
}
|
|
|
|
public async start() {
|
|
this.login(Config.token);
|
|
}
|
|
|
|
/**
|
|
* 이벤트 핸들러 등록
|
|
*
|
|
* 지정한 이벤트가 발생했을때 해당 핸들러를 호출함
|
|
* * 'func'의 내용은 기본적으로 'client.on'을 따름
|
|
* * 'extra'를 입력할 경우 추가되어 같이 전달
|
|
*
|
|
* @example
|
|
* client.onEvent('ready', (client, info) => {
|
|
* Logger.ready(client?.user.username, '봇이 준비되었습니다.', info) // 출력: OOO 봇이 준비되었습니다. 추가 정보
|
|
* }, ['추가 정보']);
|
|
*
|
|
* @param event 이벤트명
|
|
* @param func 이벤트 핸들러 함수
|
|
* @param extra 추가로 전달할 목록
|
|
*/
|
|
public readonly onEvent = (event: keyof ClientEvents, func: Function, ...extra: any[]) => this.on(event, (...args) => func(...args, ...extra));
|
|
|
|
public mkembed(data: {
|
|
title?: string;
|
|
description?: string;
|
|
url?: string;
|
|
image?: string;
|
|
thumbnail?: string;
|
|
author?: { name: string, iconURL?: string, url?: string };
|
|
addFields?: EmbedField[];
|
|
timestamp?: number | Date | undefined | null;
|
|
footer?: { text: string, iconURL?: string };
|
|
color?: ColorResolvable;
|
|
}): EmbedBuilder {
|
|
if (!data.color) data.color = this.color;
|
|
const embed = new EmbedBuilder();
|
|
if (data.title) embed.setTitle(data.title);
|
|
if (data.description) embed.setDescription(data.description);
|
|
if (data.url) embed.setURL(data.url);
|
|
if (data.image) embed.setImage(data.image);
|
|
if (data.thumbnail) embed.setThumbnail(data.thumbnail);
|
|
if (data.author) embed.setAuthor({ name: data.author.name, iconURL: data.author.iconURL, url: data.author.url });
|
|
if (data.addFields) embed.addFields(data.addFields);
|
|
if (data.timestamp) embed.setTimestamp(data.timestamp);
|
|
if (data.footer) embed.setFooter({ text: data.footer.text, iconURL: data.footer.iconURL });
|
|
if (data.color) embed.setColor(data.color);
|
|
return embed;
|
|
}
|
|
|
|
public msgDelete(message: Message, time: number, customTime?: boolean): void {
|
|
setTimeout(async () => {
|
|
try {
|
|
const msg = await message.fetch(true).catch(() => undefined);
|
|
if (msg?.deletable) msg.delete().catch((err) => {
|
|
Logger.warn(`[BotClient] 메세지 삭제 실패: ${String(err)}`);
|
|
});
|
|
} catch {}
|
|
}, Math.max(100, time * (customTime ? 1 : 6000)));
|
|
}
|
|
} |