Bot does not finish playing audio before leaving - audio

So this discord bot is meant to simply join the voice channel of whoever inputs the command, play an audio file, and leave once done.
The bot successfully joins the voice channel, begins to play the audio, and just before it finishes, it leaves. It isn't the bot leaving before the audio file is done, since it still cut off at the same point after removing the bot's ability to leave. This is my code:
const Discord = require("discord.js");
const client = new Discord.Client();
var isReady = true;
client.on("ready", () => {
console.log("I am ready!");
});
client.on("message", (message) => {
if (isReady && message.content.startsWith("!gtab")) {
isReady = false;
var voiceChannel = message.member.voiceChannel;
voiceChannel.join().then(connection => {
const dispatcher = connection.playFile('./getthatassbanned.mp3', {});
dispatcher.on("end", end => {
message.channel.send("Get that ass banned.");
voiceChannel.leave();
isReady = true;
});
}).catch(err => console.log(err));
}
});
I've been slamming my head against this issue for many hours now, and I just cannot seem to pin down why it's happening. Any help is appreciated!

The problem may just be the connection. Try putting voiceChannel.leave() inside of a setTimeout function.
Example:
setTimeout(function(){
voiceChannel.leave()
}, 2000)

Related

Message.awaitReactions in a DM to user not collecting Discord.js v13

I am currently writing a bot that acts like a timeclock for a friend of mine. Currently I am trying to get the bot to message someone if they have been clocked in for more than 2 hours and have not "refreshed" their clock in time. More of just a reminder of, "hey did you forget to clock out".
Currently the bot sends a correct DM with the correct reaction to the user identified. However, it never detects when a user reacts to that message. My onMessageReactionAdd event fires, but i have blocked that if it is in a DM channel because I would like to perform a task if the user doesnt respond in time(clock them out). I would only like to collect the refresh attached to this method so I can keep methods separate.
I am suspecting i am awaiting on the wrong message, or not understanding exactly what is going on after reading through other answers.
const refresh = require('../database/checkRefresh');
const refrechClockin = require('../commands/refreshClockin');
module.exports = async (client) =>{
let users = [];
const res = refresh.execute()
.then(res => {
console.log(`refresh query executed`);
if(res.rows.length > 0){
res.rows.forEach(row => {
users.push(row.user_id);
})
}
})
.then( () => {
console.log(`users from refresh query: ${JSON.stringify(users)}`);
users.forEach(user => {
console.log(`user_id: ${user}`);
client.users.fetch(user)
.then((user) => {
var message = user.send('Did you forget to clock out? If you are still working click the little bell, after 5 minutes you will be clocked out.')
.then((message, user) => {
message.react('🔔');
const filter = (reaction, user) => reaction.emoji.name === '🔔';
message.awaitReactions(filter, {max:2, time: 5000})
.then(collected => {
console.log(`inside of new then method`);
console.log(`collected: ${JSON.stringify(collected)}`);
})
.catch(console.error)
});
});
});
});
}
After looking through other answers, I double checked my Intents and they seem to be correct.
const client = new Client({
intents: [Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Intents.FLAGS.DIRECT_MESSAGES,
Intents.FLAGS.DIRECT_MESSAGE_REACTIONS,
Intents.FLAGS.DIRECT_MESSAGE_TYPING,
],
partials: ['MESSAGE', 'CHANNEL', 'REACTION']
});
UPDATE
I opted to change to a reactionCollector on the message. At first I was still having the same issue. After many console.logs, both in the filter and in the collector events, I discovered that my filter would not properly match the emoji that was being used. I even printed the reaction that was used(the bell) to console and copied from there to insert in the comparison and still will not match.
I would like to ultimately only allow them to respond using the bell, but for now I am ok with it. I have attached a default reaction from the bot so hopefully they see that and just click it. putting my updated code below. If anyone has any idea why I could not get the compare to work it would help. All of my other emoji comparisons are working correctly in my commands.
const refresh = require('../database/checkRefresh');
const refrechClockin = require('../commands/refreshClockin');
module.exports = async (client) =>{
let users = [];
const res = refresh.execute()
.then(async res => {
console.log(`refresh query executed`);
if(res.rows.length > 0){
res.rows.forEach(row => {
users.push(row.user_id);
})
}
})
.then( async () => {
console.log(`users from refresh query: ${JSON.stringify(users)}`);
users.forEach(user => {
console.log(`user_id: ${user}`);
client.users.fetch(user)
.then(async (user) => {
var message = await user.send('Did you forget to clock out? If you are still working click the little bell, after 5 minutes you will be clocked out.');
message.react('🔔');
const filter = (reaction, user) => {
console.log(`reaction: ${JSON.stringify(reaction)}`);
console.log(`Reaction Emoji: ${reaction.emoji.name}`);
return (user.bot === false);
};
const collector = message.createReactionCollector({ filter, max: 1, time: 45_000 });
collector.on('collect', r => console.log(`Collected ${r.emoji.name}`));
collector.on('end', collected => console.log(`Collection ended with ${collected.size} Collected items`));
});
});
});
}

Running different discord.js bot instances in the same NodeJS project

I am trying to create a project that serves different bots (with different tokens) at the same time. My guess is that you would have to recall "client.login(token)" twice. I am busy testing this and did not yet finish it, but will come back once completed.
Does anyone have some advice on running multiple NodeJS bot instances in the same file, in the same project? Is this even possible? Help is greatly appreciated.
I have also tried to imagine what this would be like:
const {Client} = require('discord.js');
const bot1 = new Client();
const bot2 = new Client();
//bot1 does something
//bot2 does something
bot1.login('token1');
bot2.login('token2');
Thank you and have a good day.
I can confirm that this works. Here is my code:
const Discord = require('discord.js');
const client1 = new Discord.Client();
const client2 = new Discord.Client();
const CONFIG = require('./config.json');
client1.once('ready', () => {
console.log('Bot 1 ready.');
});
client2.once('ready', () => {
console.log('Bot 2 ready.');
});
client1.on('message', message => {
if (message.content === 'Hello!') {
message.channel.send('Hello');
console.log('Bot 1 said hello.');
}
});
client2.on('message', message => {
if (message.content === 'Hello!') {
message.channel.send('world!');
console.log('Bot 2 said hello.');
}
});
client1.login(CONFIG.token1);
client2.login(CONFIG.token2);
Here is the Console log:
Bot 2 ready.
Bot 1 ready.
Bot 1 said hello.
Bot 2 said hello.
Interestingly, whether Bot 1 or Bot 2 responds first varies, so you might want to take that into consideration.
In fact, this even works with 3 bots, and it should work with any number of bots!
const Discord = require('discord.js');
const client1 = new Discord.Client();
const client2 = new Discord.Client();
const client3 = new Discord.Client();
const CONFIG = require('./config.json');
client1.once('ready', () => {
console.log('Bot 1 ready.');
});
client2.once('ready', () => {
console.log('Bot 2 ready.');
});
client3.once('ready', () => {
console.log('Bot 3 ready.');
});
client1.on('message', message => {
if (message.content === 'Hello!') {
message.channel.send('Hello1');
console.log('Bot 1 said hello.');
}
});
client2.on('message', message => {
if (message.content === 'Hello!') {
message.channel.send('Hello2');
console.log('Bot 2 said hello.');
}
});
client3.on('message', message => {
if (message.content === 'Hello!') {
message.channel.send('Hello3');
console.log('Bot 3 said hello.');
}
});
client1.login(CONFIG.token1);
client2.login(CONFIG.token2);
client3.login(CONFIG.token3);
And here is the console log for that:
Bot 1 ready.
Bot 3 ready.
Bot 2 ready.
Bot 2 said hello.
Bot 3 said hello.
Bot 1 said hello.
However with a more in depth project, I would advise (for commands and such) using different files for the 2 bots as I think the code would get messy and hard to read quickly, even if you use the same index.js file.
Hope this helps!

I am trying to make a Discord bot that boosts your server every two hours

So what I am trying to do is when the bot is added into your Discord server the bot says "!d bump" exactly every two hours? This is what I have so far
const Discord = require('discord.js');
const client = new Discord.Client();
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', msg => {
if (msg.content === 'ping') {
msg.reply('pong');
}
});
client.on('message', msg => {
if (msg.content === '*invite') {
msg.reply('invite');
}
});
client.login('token');
EDIT: Also, I am not userbotting and this is a problem because I can't get the bot to only say the phrase and not pinging someone
As others have stated in the comments, bots are often ignored by other bots and as such the sent command will be ignored.
But here's a possible approach using setInterval or setTimeout:
function sendBump() {
const channels = ...; // Fetch the channels you want to send the message to
// Few different types of loops, choose the one must suitable/you know best
channel.send('!d bump');
}
client.on('ready', () => {
setInterval(() => sendBump(), 7200000); // Call the method every two hours
});

Configure and Manage array of Discord.js clients in NodeJS

EDIT: Please ignore... I've realised I've got discord wrong and it's all a moot point. A single discord client can handle any and all guilds that are connected to it.
Some time back I wrote a discord Bot in NodeJS.
It was very successful and I was asked to deploy it against another Discord server.
To expedite things I simply cloned it and edited a few settings and fired up a second instance on the server.
I have to do some changes to it to integrate with a different data source and the nature of the change make it practical to combine the 2 into one bot servicing 1 to n discord servers.
The relevant setup code at the moment looks like...
const Discord = require('discord.js');
const client = new Discord.Client();
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', msg => {
// Handle the message
}
function setupDiscord(auth) {
console.log("in setupDiscord");
if (!issetup) {
issetup = true;
console.log("connecting to discord");
client.login(auth.token).then(result => {
console.log("Connected");
isConnected = true;
})
.catch(error => {
console.log("Error connecting");
console.log(error.message);
});
}
return (new Date).getTime();
}
At this point the single instance of the client is logged in.
But I now need an array of clients. (THIS IS PSEUDO CODE!!!)
var config = ['token1', 'token2', 'token3'];
const Discord = require('discord.js');
var clients = [];
config.forEach(function(token) {
var client = new Discord.Client();
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', msg => {
// Handle the message
}
function setupDiscord(auth) {
console.log("in setupDiscord");
if (!issetup) {
issetup = true;
console.log("connecting to discord");
client.login(auth.token).then(result => {
console.log("Connected");
isConnected = true;
})
.catch(error => {
console.log("Error connecting");
console.log(error.message);
});
}
return (new Date).getTime();
}
client.setupDiscord(token);
clients.push(client);
});
Am I on the right track or is this doomed to fail?
Note: I am going to try what I've put above and regardless of whether it works or not I would appreciate people comments on a better way to do it.
Thanks
I realised I had gotten discord wrong and it's all a moot point.
A single discord client can handle any and all guilds that are connected to it.

Populate unpopulated reaction.users

On a messageReactionAdd event, one of the parameters is a MessageReaction. From that reaction, I do message.reaction to find the message that the reaction is from. I want to use that message to find all the reactions that the parameters user has reacted to on that message.
However, one obstacle is that when the bot restarts, it seems as though the message.reactions is not fully populated, and the data needs to be fetched. I need the users of a looped reaction, but I'm struggling on that part.
I have tried:
await message.reactions.reduce((p, c) => c.fetchUsers(), 0);
// I had thought this would of cached the users of every reaction on the message, but that did not work.
// next
message.reactions.forEach((x, y) => {
x.fetchUsers();
});
// this was also the same train of thought, but still to no avail.
What I mean by that users are not in the message.reaction.users object, I mean this:
// the bot restarts - and a reaction is added
console.log(reaction.users);
// outputs: Collection [Map] {}
// this is supposed to be populated with many users, but it's empty
// however, if I add ANY reaction again, not doing anything else
// it outputs a Collection with many users in it, which is expected
I have no idea how to do this.
Edit: relevant code
// raw.js (the raw event)
const events = {
MESSAGE_REACTION_ADD: 'messageReactionAdd',
};
const Discord = require('discord.js');
module.exports = async (client, event) => {
if (!events.hasOwnProperty(event.t)) return;
const { d: data } = event;
const user = client.users.get(data.user_id);
if (!user) return;
const channel = client.channels.get(data.channel_id);
if (!channel) return;
if (channel.messages.has(data.message_id)) return;
const message = await channel.fetchMessage(data.message_id);
const emojiKey = (data.emoji.id) ? `${data.emoji.name}:${data.emoji.id}` : data.emoji.name;
let reaction = message.reactions.get(emojiKey);
if (!reaction) {
const emoji = new Discord.Emoji(client.guilds.get(data.guild_id), data.emoji);
reaction = new Discord.MessageReaction(message, emoji, 1, data.user_id === client.user.id);
}
client.emit(events[event.t], reaction, user);
};
// messageReactionAdd.js (the messageReactionAdd event)
module.exports = async (client, reaction, user) => {
const message = reaction.message;
if (!message)
return;
//await message.reactions.reduce((p, c) => c.fetchUsers(), 0);
message.reactions.forEach((x,y) => {
x.fetchUsers();
});
reactions = await message.reactions.filter(r => r.users.has(`${user.id}`));
console.log(reactions);
};
This code is what fixed this problem for me.
// raw.js event file
await reaction.message.reactions.forEach(r => {
r.fetchUsers({before: `${reaction.message.author.id}`});
});
// emit the messageReactionAdd event
// messageReactionAdd.js event file
// the message.reactions.users should be populated, which I can use
reactions = await reaction.message.reactions.filter(r => r.users.has(`${reaction.message.author.id}`));
I had used this code in the wrong events which made no logical sense which made the results that I had thought was invalid.

Resources