import { SlashCommandBuilder, MessageFlags } from "discord.js" import type { ChatInputCommandInteraction, GuildMember } from "discord.js" import { joinVoiceChannel, createAudioPlayer, createAudioResource, AudioPlayerStatus, EndBehaviorType } from "@discordjs/voice" import { t } from "@/utils/i18n" export const data = new SlashCommandBuilder() .setName("speak") .setDescription("Make me talk over someone annoying in voice chat") .setNameLocalizations({ fr: "parle" }) .setDescriptionLocalizations({ fr: "Fais moi parler par dessus quelqu'un d'ennuyant dans le vocal" }) .addUserOption(option => option .setName("user") .setDescription("The person in question") .setNameLocalizations({ fr: "utilisateur" }) .setDescriptionLocalizations({ fr: "La personne en question" }) .setRequired(true) ) export async function execute(interaction: ChatInputCommandInteraction) { const guild = interaction.guild if (!guild) return const user = interaction.options.getUser("user", true) const member = await guild.members.fetch(user.id) const caller = interaction.member as GuildMember if (!caller.voice.channel) return interaction.reply({ content: t(interaction.locale, "salonpostam.parle.not_in_voice"), flags: MessageFlags.Ephemeral }) if (!member.voice.channel) return interaction.reply({ content: t(interaction.locale, "salonpostam.parle.member_not_in_voice"), flags: MessageFlags.Ephemeral }) if (caller.voice.channelId !== member.voice.channelId) return interaction.reply({ content: t(interaction.locale, "salonpostam.parle.not_same_channel"), flags: MessageFlags.Ephemeral }) await interaction.reply({ content: t(interaction.locale, "salonpostam.parle.will_speak_over"), flags: MessageFlags.Ephemeral }) /* // Searches for audio files uploaded in the channel const messages = await interaction.channel.messages.fetch({ limit: 10, cache: false }).filter(m => m.attachments.size > 0) const files = [] await messages.forEach(m => m.attachments.forEach(a => { if (a.contentType === 'audio/mpeg') files.push(a) })) if (files.size === 0) return interaction.editReply({ content: t(interaction.locale, "player.no_audio_found"), flags: MessageFlags.Ephemeral }) // Limit the number of files to the last 10 //files = files.sort((a, b) => b.createdTimestamp - a.createdTimestamp).first(10) // Ask the user to choose a file let file = await interaction.channel.send({ content: 'Choisissez un fichier audio :', files }) const filter = m => m.author.id === interaction.user.id && !isNaN(m.content) && parseInt(m.content) > 0 && parseInt(m.content) <= files.size const response = await interaction.channel.awaitMessages({ filter, max: 1, time: 30000, errors: ['time'] }) file = files.get(files.keyArray()[response.first().content - 1]) */ let playing = false const player = createAudioPlayer() player.on(AudioPlayerStatus.Idle, () => { playing = false }) const connection = joinVoiceChannel({ channelId: caller.voice.channelId ?? "", guildId: interaction.guildId ?? "", adapterCreator: guild.voiceAdapterCreator, selfDeaf: false }) connection.subscribe(player) const stream = connection.receiver.subscribe(user.id, { end: { behavior: EndBehaviorType.Manual } }) stream.on("data", () => { if (connection.receiver.speaking.users.has(user.id) && !playing) { playing = true const resource = createAudioResource("@/static/parle.mp3", { inlineVolume: true }) //const resource = createAudioResource(file.attachments.first().url, { inlineVolume: true }) if (resource.volume) resource.volume.setVolume(0.2) player.play(resource) } }) interaction.client.on("voiceStateUpdate", (oldState, newState) => { if (oldState.id === member.id && newState.channelId !== caller.voice.channelId ) { stream.destroy() connection.disconnect() } }) }