노드가 CONNECTED 상태가 아닐 때 joinVoiceChannel이 throw 되어 fire-and-forget handleMessage에서 처리되지 않은 Promise 거부로 번지던 문제 수정. - LavalinkManager.hasReadyNode() 추가 - channelJoin에서 노드 미연결 시 안내 임베드 반환 + join try/catch - messageCreate의 handleMessage 호출에 .catch 추가 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
117 lines
4.0 KiB
TypeScript
117 lines
4.0 KiB
TypeScript
import { Message, ChatInputApplicationCommandData, Guild, ChatInputCommandInteraction, EmbedBuilder, ApplicationCommandOptionType, ChannelType } from "discord.js";
|
|
import { client, lavalinkManager } from "../index";
|
|
import { Command } from "../types/Command";
|
|
import { GuildPlayer } from "../classes/GuildPlayer";
|
|
import { getTextChannelAndMsg } from "../utils/music/Channel";
|
|
import { Logger } from "../utils/Logger";
|
|
|
|
/** join 명령어 */
|
|
export default class implements Command {
|
|
/** 해당 명령어 설명 */
|
|
name = "join";
|
|
visible = true;
|
|
aliases: string[] = [];
|
|
description: string = "음성채널 참가";
|
|
metaData: ChatInputApplicationCommandData = {
|
|
name: this.name,
|
|
description: this.description,
|
|
options: [
|
|
{
|
|
type: ApplicationCommandOptionType.Channel,
|
|
name: "channel",
|
|
description: "등록할 채널 (선택)",
|
|
channel_types: [ChannelType.GuildVoice],
|
|
},
|
|
{
|
|
type: ApplicationCommandOptionType.String,
|
|
name: "channel_id",
|
|
description: "채널 ID 또는 #멘션 (선택)",
|
|
},
|
|
]
|
|
};
|
|
|
|
/** 실행되는 부분 */
|
|
async slashRun(interaction: ChatInputCommandInteraction) {
|
|
const channel = interaction.options.getChannel("channel");
|
|
const channelId = interaction.options.getString("channel_id");
|
|
await interaction.editReply({ embeds: [ (await channelJoin(interaction.guild, channel?.id || channelId)).embed ] });
|
|
return;
|
|
}
|
|
async messageRun(message: Message) {
|
|
if (message.channel?.type !== ChannelType.GuildText) return;
|
|
return;
|
|
// return await message.channel.send({ content: "예시 명령어" }).then(m => client.msgDelete(m, 5));
|
|
}
|
|
}
|
|
|
|
export async function channelJoin(guild: Guild | null, voiceChannelId: string | null): Promise<{
|
|
embed: EmbedBuilder;
|
|
player?: GuildPlayer;
|
|
}> {
|
|
if (!guild) return { embed: client.mkembed({
|
|
title: "guild를 가져올수 없습니다.",
|
|
color: "DarkRed",
|
|
}) };
|
|
const { channel, msg, reason } = await getTextChannelAndMsg(guild);
|
|
if (reason || !channel || !msg) return { embed: client.mkembed({
|
|
title: reason ?? "오류발생",
|
|
color: "DarkRed",
|
|
}) };
|
|
|
|
if (!voiceChannelId) return { embed: client.mkembed({
|
|
title: "채널 아이디 가져오기 오류",
|
|
color: "DarkRed",
|
|
}) };
|
|
const voiceChannel = guild.channels.cache.get(voiceChannelId.replace(/\<|\#|\!|\>/g,"").trim());
|
|
if (!voiceChannel?.id) return { embed: client.mkembed({
|
|
title: `${voiceChannelId} 채널 가져오기 오류`,
|
|
color: "DarkRed",
|
|
}) };
|
|
if (voiceChannel.type !== ChannelType.GuildVoice) return { embed: client.mkembed({
|
|
title: `<#${voiceChannelId}> 음성 채널이 아닙니다.`,
|
|
color: "DarkRed",
|
|
}) };
|
|
|
|
let player = lavalinkManager.getPlayer(guild.id);
|
|
if (player) return { embed: client.mkembed({ title: `이미 <#${player.voiceChannelId}> 참가중입니다.` }), player };
|
|
|
|
// 연결 가능한 Lavalink 노드가 없으면 joinVoiceChannel이 throw 되어 unhandledRejection으로 번짐.
|
|
// 노드 미연결 시 사용자에게 안내만 하고 종료.
|
|
if (!lavalinkManager.hasReadyNode()) {
|
|
return { embed: client.mkembed({
|
|
title: "음악 서버에 연결할 수 없습니다.",
|
|
description: "잠시 후 다시 시도해주세요.",
|
|
color: "DarkRed",
|
|
}) };
|
|
}
|
|
|
|
let voicePlayer;
|
|
try {
|
|
voicePlayer = await lavalinkManager.shoukaku.joinVoiceChannel({
|
|
guildId: guild.id,
|
|
channelId: voiceChannel.id,
|
|
shardId: guild.shardId,
|
|
deaf: true,
|
|
mute: false,
|
|
});
|
|
} catch (err) {
|
|
Logger.error(`[channelJoin] 음성채널 참가 실패: ${String(err)}`);
|
|
return { embed: client.mkembed({
|
|
title: "음성채널 참가에 실패했습니다.",
|
|
description: "잠시 후 다시 시도해주세요.",
|
|
color: "DarkRed",
|
|
}) };
|
|
}
|
|
|
|
player = new GuildPlayer(
|
|
guild,
|
|
voicePlayer,
|
|
voiceChannel.id,
|
|
channel,
|
|
msg,
|
|
);
|
|
lavalinkManager.addPlayer(guild.id, player);
|
|
return { embed: client.mkembed({
|
|
title: `<#${voiceChannelId}> 참가 완료`,
|
|
}), player };
|
|
} |