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 }; }