elpideus
elpideus

Reputation: 125

DiscordJs & distube - Why can't I do anything after I play music?

I am using DiscordJs and distube to create a bot for my discord server. I am using slash commands. The problem is that I can't execute any command (so I cannot even execute /stop or play another song) after I play a song. This is my code:

const {SlashCommandBuilder} = require("@discordjs/builders");

module.exports = {
    data: new SlashCommandBuilder()
        .setName("play")
        .setDescription("Play a song.")
        .addStringOption(option => option.setName("song").setDescription("The song link or name.").setRequired(true)),
    async execute(interaction) {
        interaction.reply({content: 'Music started.', ephemeral: true});
        const {member, channel, client} = interaction;
        await client.distube.play(member.voice.channel, interaction.options.get("song").value, {textChannel: channel, member: member});
    }
}

My command handler:

const fs = require("fs");
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');

const clientId = '12345678';
const guildId = '12345678';

module.exports = (client) => {
    client.handleCommands = async (commandsFolder, path) => {
        client.commandArray = [];
        for (const folder of commandsFolder) {
            const commandFiles = fs.readdirSync(`${path}/${folder}`).filter(file => file.endsWith('.js'));
            for (const file of commandFiles) {
                const command = require(`../commands/${folder}/${file}`);
                await client.commands.set(command.data.name, command);
                client.commandArray.push(command.data.toJSON());
            }
        }
        const rest = new REST({ version: '9' }).setToken("sometextthatidontwanttoshow");

        await (async () => {
            try {
                console.log('Started refreshing application commands.');

                await rest.put(
                    Routes.applicationGuildCommands(clientId, guildId),
                    {body: client.commandArray},
                );

                console.log('Successfully reloaded application commands.');
            } catch (error) {
                console.error(error);
            }
        })();
    }
}

And this is the function that "creates" the commands:

module.exports = {
    name: "interactionCreate",
    async execute(interaction, client) {
        if (!interaction.isCommand()) return;
        const command = client.commands.get(interaction.commandName);
        if (!command) return;
        try {
            await command.execute(interaction);
        } catch (error) {
            console.error(error);
            await interaction.reply({
                content: "There was an error while executing this command.",
                ephemeral: true
            })
        }
    }
}

And this is my index file

const {Client, Intents, Collection} = require("discord.js");
const fs = require("fs");

const client = new Client({intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_VOICE_STATES]});
client.commands = new Collection();

const {DisTube} = require("distube");
client.distube = new DisTube(client, {
    emitNewSongOnly: true,
    leaveOnFinish: false,
    emitAddSongWhenCreatingQueue: false
});
module.exports = client;

const functions = fs.readdirSync("./src/functions").filter(file => file.endsWith(".js"));
const eventFiles = fs.readdirSync("./src/events").filter(file => file.endsWith(".js"));
const commandsFolders = fs.readdirSync("./src/commands");

(async () => {
    for (const file of functions) {
        require(`./src/functions/${file}`)(client);
    }
    client.handleEvents(eventFiles, "./src/events");
    client.handleCommands(commandsFolders, "./src/commands");
    await client.login('mybeautifultoken')
})();

Any help is highly appreciated. Thanks in advance.

Upvotes: 1

Views: 867

Answers (1)

nacairns
nacairns

Reputation: 232

Okay, I believe the issue lies in the fact that you're awaiting your command.execute(). I believe behind the scenes what this is doing is that its creating a promise that resolves once your discord bot's music finishes playing.

While its correct to use these functions asynchronously, when you call it like this it actually blocks all the other similar asynchronous functions (slash commands) from occurring until this one resolves. Let me know if this fixes it.

module.exports = {
    name: "interactionCreate",
    async execute(interaction, client) {
        if (!interaction.isCommand()) return;
        const command = client.commands.get(interaction.commandName);
        if (!command) return;
        try {
            command.execute(interaction); //removed await
        } catch (error) {
            console.error(error);
            await interaction.reply({
                content: "There was an error while executing this command.",
                ephemeral: true
            })
        }
    }
}

index edits

 await client.handleEvents(eventFiles, "./src/events");
 await client.handleCommands(commandsFolders, "./src/commands");

Upvotes: 1

Related Questions