204 lines
8.2 KiB
TypeScript
204 lines
8.2 KiB
TypeScript
import {
|
|
SlashCommandBuilder,
|
|
PermissionFlagsBits,
|
|
ChatInputCommandInteraction,
|
|
ChannelType,
|
|
EmbedBuilder,
|
|
TextChannel
|
|
} from 'discord.js';
|
|
import { prisma } from '../database';
|
|
import { SupportedLocale, t } from '../i18n';
|
|
import { logger } from '../utils/logger';
|
|
|
|
export default {
|
|
data: new SlashCommandBuilder()
|
|
.setName('voice')
|
|
.setDescription('Manage temporary voice channels.')
|
|
.setDescriptionLocalizations({
|
|
ko: '임시 음성 채널 설정을 관리합니다.',
|
|
})
|
|
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
|
// --- Setup Subcommands ---
|
|
.addSubcommandGroup(group =>
|
|
group
|
|
.setName('setup')
|
|
.setDescription('Configure the voice generator channel.')
|
|
.setDescriptionLocalizations({ ko: '음성 생성기 채널을 설정합니다.' })
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('set')
|
|
.setDescription('Set an existing voice channel as a Generator')
|
|
.setDescriptionLocalizations({ ko: '기존 음성 채널을 생성기로 설정합니다' })
|
|
.addChannelOption(option =>
|
|
option.setName('channel')
|
|
.setDescription('The voice channel to act as the Generator')
|
|
.setDescriptionLocalizations({ ko: '생성기로 사용할 음성 채널' })
|
|
.setRequired(true)
|
|
.addChannelTypes(ChannelType.GuildVoice)
|
|
)
|
|
.addChannelOption(option =>
|
|
option.setName('category')
|
|
.setDescription('(Optional) The category where temp channels will be created')
|
|
.setDescriptionLocalizations({ ko: '(선택) 임시 채널이 생성될 카테고리' })
|
|
.setRequired(false)
|
|
.addChannelTypes(ChannelType.GuildCategory)
|
|
)
|
|
)
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('create')
|
|
.setDescription('Create a new voice channel and set it as a Generator')
|
|
.setDescriptionLocalizations({ ko: '새 음성 채널을 만들고 생성기로 설정합니다' })
|
|
.addStringOption(option =>
|
|
option.setName('name')
|
|
.setDescription('The name of the new generator voice channel')
|
|
.setDescriptionLocalizations({ ko: '새 생성기 음성 채널의 이름' })
|
|
.setRequired(true)
|
|
)
|
|
.addChannelOption(option =>
|
|
option.setName('category')
|
|
.setDescription('(Optional) The category where the new channel will be created')
|
|
.setDescriptionLocalizations({ ko: '(선택) 새 채널이 생성될 카테고리' })
|
|
.setRequired(false)
|
|
.addChannelTypes(ChannelType.GuildCategory)
|
|
)
|
|
)
|
|
)
|
|
// --- Config Subcommands ---
|
|
.addSubcommandGroup(group =>
|
|
group
|
|
.setName('config')
|
|
.setDescription('Manage default settings for temporary channels.')
|
|
.setDescriptionLocalizations({ ko: '임시 채널의 기본 설정을 관리합니다.' })
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('name')
|
|
.setDescription('Set the default naming template for new temp channels.')
|
|
.setDescriptionLocalizations({ ko: '임시 채널의 기본 이름 템플릿을 설정합니다.' })
|
|
.addStringOption(option =>
|
|
option.setName('template')
|
|
.setDescription('Template using {{username}} placeholder')
|
|
.setDescriptionLocalizations({ ko: '{{username}}을 포함한 이름 템플릿' })
|
|
.setRequired(true)
|
|
)
|
|
)
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('limit')
|
|
.setDescription('Set the default user limit for new temp channels.')
|
|
.setDescriptionLocalizations({ ko: '임시 채널의 기본 인원 제한을 설정합니다.' })
|
|
.addIntegerOption(option =>
|
|
option.setName('limit')
|
|
.setDescription('User limit (0-99, 0 = unlimited)')
|
|
.setDescriptionLocalizations({ ko: '인원 제한 (0-99, 0 = 무제한)' })
|
|
.setRequired(true)
|
|
.setMinValue(0)
|
|
.setMaxValue(99)
|
|
)
|
|
)
|
|
.addSubcommand(subcommand =>
|
|
subcommand
|
|
.setName('status')
|
|
.setDescription('View current guild voice settings.')
|
|
.setDescriptionLocalizations({ ko: '현재 서버의 음성 설정을 확인합니다.' })
|
|
)
|
|
),
|
|
|
|
async execute(interaction: ChatInputCommandInteraction, locale: SupportedLocale) {
|
|
const group = interaction.options.getSubcommandGroup();
|
|
const subcommand = interaction.options.getSubcommand();
|
|
const guildId = interaction.guildId!;
|
|
|
|
try {
|
|
// --- SETUP GROUP ---
|
|
if (group === 'setup') {
|
|
const category = interaction.options.getChannel('category');
|
|
|
|
if (subcommand === 'set') {
|
|
const channel = interaction.options.getChannel('channel', true);
|
|
await prisma.voiceGenerator.upsert({
|
|
where: { channelId: channel.id },
|
|
update: { categoryId: category?.id || null, guildId },
|
|
create: { channelId: channel.id, guildId, categoryId: category?.id || null }
|
|
});
|
|
return interaction.reply({
|
|
content: t(locale, 'commands.voiceSetup.setSuccess', { channel: `${channel}` }),
|
|
ephemeral: true
|
|
});
|
|
}
|
|
|
|
if (subcommand === 'create') {
|
|
const name = interaction.options.getString('name', true);
|
|
const newChannel = await interaction.guild!.channels.create({
|
|
name,
|
|
type: ChannelType.GuildVoice,
|
|
parent: category?.id || null,
|
|
});
|
|
await prisma.voiceGenerator.create({
|
|
data: { channelId: newChannel.id, guildId, categoryId: category?.id || null }
|
|
});
|
|
return interaction.reply({
|
|
content: t(locale, 'commands.voiceSetup.createSuccess', { channel: `${newChannel}` }),
|
|
ephemeral: true
|
|
});
|
|
}
|
|
}
|
|
|
|
// --- CONFIG GROUP ---
|
|
if (group === 'config') {
|
|
if (subcommand === 'name') {
|
|
const template = interaction.options.getString('template', true);
|
|
await prisma.voiceGuildConfig.upsert({
|
|
where: { guildId },
|
|
update: { defaultNameTemplate: template },
|
|
create: { guildId, defaultNameTemplate: template }
|
|
});
|
|
return interaction.reply({
|
|
content: t(locale, 'commands.voiceConfig.setSuccess'),
|
|
ephemeral: true
|
|
});
|
|
}
|
|
|
|
if (subcommand === 'limit') {
|
|
const limit = interaction.options.getInteger('limit', true);
|
|
await prisma.voiceGuildConfig.upsert({
|
|
where: { guildId },
|
|
update: { defaultUserLimit: limit },
|
|
create: { guildId, defaultUserLimit: limit }
|
|
});
|
|
return interaction.reply({
|
|
content: t(locale, 'commands.voiceConfig.setSuccess'),
|
|
ephemeral: true
|
|
});
|
|
}
|
|
|
|
if (subcommand === 'status') {
|
|
const config = await prisma.voiceGuildConfig.findUnique({ where: { guildId } });
|
|
const embed = new EmbedBuilder()
|
|
.setTitle(t(locale, 'commands.voiceConfig.statusTitle'))
|
|
.setColor(0x5865F2)
|
|
.addFields(
|
|
{
|
|
name: t(locale, 'commands.voiceConfig.templateLabel'),
|
|
value: `\`${config?.defaultNameTemplate || t(locale, 'voice.defaultRoomName')}\``,
|
|
inline: true
|
|
},
|
|
{
|
|
name: t(locale, 'commands.voiceConfig.limitLabel'),
|
|
value: t(locale, 'commands.voiceConfig.limitValue', { limit: String(config?.defaultUserLimit ?? 0) }),
|
|
inline: true
|
|
}
|
|
);
|
|
return interaction.reply({ embeds: [embed], ephemeral: true });
|
|
}
|
|
}
|
|
} catch (error) {
|
|
logger.error('Error in voice command', error);
|
|
return interaction.reply({
|
|
content: t(locale, 'errors.E3003.userMessage'),
|
|
ephemeral: true
|
|
});
|
|
}
|
|
},
|
|
};
|