reactions counted multiple times? discord.js - javascript

I made a bot where if you type a command it will send a message and if you react to that message it will send another message but if i run the command again and react to the first message it will send the message two times how can i fix that?
client.on('messageReactionAdd', async (reaction, user)=>{
if(user.bot) return;
if (reaction.emoji.name === '⛔') {
clearInterval(my_interval);
clearTimeout(my_timeout);
const exampleEmbed1 = new Discord.MessageEmbed()
.setColor('#fefefe')
.setTitle(`Your record was ${index}s!`)
.setAuthor(message.author.tag, message.author.avatarURL())
.setDescription('Bot made by tempacc')
if(run){
message.channel.send(exampleEmbed1);
index = 0;
message.member.voice.channel.leave();
run = false;
}else if(!run){
message.channel.send('You must start a speedrun before running this command!');
}
}
})

I suggested that you should use a reaction collector instead, but I will include an example here along with docs for anyone else wondering.
const filter = (reaction, user) => {
return reaction.emoji.name === '👍'; // Check reaction was a 👍 and not anything else
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
However where time is, you can also pass max, maxUsers or maxEmojis into this data object, for example:
const collector = message.createReactionCollector(filter, { maxUsers: 1 });
You can find more about the reaction collector here and more about the options here

Related

Using a Reaction Collector on a message the bot sent

Been working on this bot for a bit, but I seem to be stumped. every time I run it, it says
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'createReactionCollector' of undefined
This is caused by
const collector = message.createReactionCollector(filter, { time: 15000 });
and i dont know how else to do this. Most of the other examples are either outdated or made for a particular purpose, making it hard to implement them into my code. I really appreciate any help you can provide!
if (command === 'ping') {
const pingEmbed = new Discord.MessageEmbed()
.setColor('#03cffc')
.setTitle('Ping!')
.setDescription(`${message.author.username} is playing a game! \n \n Playing With: \n ` + isPlaying);
message.channel.send(pingEmbed)
.then(sentEmbed => {
sentEmbed.react("👍")
}).then( async message => {
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = message.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
})}
You do not need to use two then methods. Simply one would be enough for your case. Instead of having to use another then method and passing in message, you can just replace message with sentEmbed.
Code:
if (command === 'ping') {
const pingEmbed = new Discord.MessageEmbed()
.setColor('#03cffc')
.setTitle('Ping!')
.setDescription(`${message.author.username} is playing a game! \n \n Playing With: \n ` + isPlaying);
message.channel.send(pingEmbed)
.then(sentEmbed => {
sentEmbed.react("👍")
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
const collector = sentEmbed.createReactionCollector(filter, { time: 15000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
})
}

discord.js How do you make a reaction collector

I am trying to make it so when you get to a certain amount of reactions my bot will send a message and if somebody can help here is my code
.then(function(sentMessage) {
sentMessage.react('👍').catch(() => console.error('emoji failed to react.')).message.reactions.cache.get('👍').count;
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
message.awaitReactions(filter, { max: 2, time: 00, errors: ['time'] })
.then(collected => console.log(collected.size))
.catch(collected => {
console.log(`After a minute, only ${collected.size} out of 4 reacted.`);
});
});
})
Instead of awaitReactions, you could also use createReactionCollector which is probably easier to use and its collector.on() listeners are more readable than awaitReactions's then() and catch() methods.
You won't need to use message.reactions.cache.get('👍').count to check the number of reactions, as the end event fires when you reached the maximum and you can send a message inside that.
Also, in your filter, you don't need to check if user.id === message.author.id as you will want to accept reactions from other users. However, you can check if !user.bot to make sure that you won't count the bot's reaction. You can also remove the time option if you don't want to limit the time your bot collects reactions.
Another error was that you called .awaitReactions() on the message itself not the sentMessage.
Check out the working code below:
// v12
client.on('message', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const MAX_REACTIONS = 2;
if (command === 'react') {
try {
// send a message and wait for it to be sent
const sentMessage = await message.channel.send('React to this!');
// react to the sent message
await sentMessage.react('👍');
// set up a filter to only collect reactions with the 👍 emoji
// and don't count the bot's reaction
const filter = (reaction, user) => reaction.emoji.name === '👍' && !user.bot;
// set up the collecrtor with the MAX_REACTIONS
const collector = sentMessage.createReactionCollector(filter, {
max: MAX_REACTIONS,
});
collector.on('collect', (reaction) => {
// in case you want to do something when someone reacts with 👍
console.log(`Collected a new ${reaction.emoji.name} reaction`);
});
// fires when the time limit or the max is reached
collector.on('end', (collected, reason) => {
// reactions are no longer collected
// if the 👍 emoji is clicked the MAX_REACTIONS times
if (reason === 'limit')
return message.channel.send(`We've just reached the maximum of ${MAX_REACTIONS} reactions.`);
});
} catch (error) {
// "handle" errors
console.log(error);
}
}
});
If you're using discord.js v13, there are a couple of changes:
you'll need to add the GUILD_MESSAGE_REACTIONS intents
the message event is now messageCreate
the collector's filter is inside the options object
// v13
const { Client, Intents } = require('discord.js');
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
],
});
const prefix = '!';
client.on('messageCreate', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const MAX_REACTIONS = 2;
if (command === 'react') {
try {
// send a message and wait for it to be sent
const sentMessage = await message.channel.send('React to this!');
// react to the sent message
await sentMessage.react('👍');
// set up a filter to only collect reactions with the 👍 emoji
// and don't count the bot's reaction
const filter = (reaction, user) => reaction.emoji.name === '👍' && !user.bot;
// set up the collecrtor with the MAX_REACTIONS
const collector = sentMessage.createReactionCollector({
filter,
max: MAX_REACTIONS,
});
collector.on('collect', (reaction) => {
// in case you want to do something when someone reacts with 👍
console.log(`Collected a new ${reaction.emoji.name} reaction`);
});
// fires when the time limit or the max is reached
collector.on('end', (collected, reason) => {
// reactions are no longer collected
// if the 👍 emoji is clicked the MAX_REACTIONS times
if (reason === 'limit')
return message.channel.send(`We've just reached the maximum of ${MAX_REACTIONS} reactions.`);
});
} catch (error) {
// "handle" errors
console.log(error);
}
}
});
And the result:
You want to check the collected.size with an if statement like so:
let amount = 4; // any integer
if (collected.size /* returns an integer */ === amount) {
console.log(`Got ${amount} reactions`)
}
Hope I got the issue right.
If I understand it correctly, then you can just change the parameters for the awaitMessage method. You can remove the time: 00, errors: ['time'] arguments since they're optional and keep the max: 2. That way, the function will only finish once there are 2 reactions (in this case).
I would recommend removing the user.id === message.author.id; from the filter since it seems like you want multiple users to react to the message.
For more information, you can check the discord.js guide or the documentation for awaitReactions.
Code:
message.channel.send("Message reacting to.").then(function (sentMessage) {
sentMessage.react('👍').catch(() => console.error('emoji failed to react.'));
const filter = (reaction, user) => {
return reaction.emoji.name === '👍';
};
message.awaitReactions(filter, { max: 2 })
.then(collected => console.log(collected.size))
});

How send DM message to the author of the reaction?

How can I make the bot to send a DM message to the users who clicked the reaction?
client.on("message", (msg) => {
if (msg.guild && msg.content.startsWith("!test")) {
client.channels.cache.get("813782841187631126").send("Test-1")
.then((sentMessage) => {
sentMessage.react('811140592762486805')
const filter = (r) => r.emoji.id == '811140592762486805';
const collector = sentMessage.createReactionCollector(filter, {time: 60000});
collector.on('collect', (r) => {
reaction.author.send("Test-2");
});
});
}
});
The collect event on ReactionCollector takes two parameters; reaction and user. You can simply use the send() method on the user to send them a DM.
Also, you should not collect the bot's reaction. You'll need to update your filter and add && !user.bot, so you won't try to send the bot a message.
const filter = (reaction, user) =>
reaction.emoji.id === '811140592762486805' && !user.bot;
const collector = sentMessage.createReactionCollector(filter, {
time: 60000,
});
collector.on('collect', (reaction, user) => {
user.send('Test-2');
});

How to get old message reactions

What I'm trying to do is to get username for users who reacts on that message. It's working good but when the bot restarts only new reactions work.
how to make it send all users reactions
client.on('ready', () => {
client.guilds.get('guild_id').channels.get('chnl_id').fetchMessage('msg_id');
});
client.on('messageReactionAdd', (reaction, user) => {
const { message} = reaction;
if(message.channel.id == 'chnl_id'){
if(reaction.emoji.name === "✅") {
message.guild.fetchMember(user.id).then(member => {
if(user.bot) return;
else {
message.channel.send(reaction.users.map(u => u.username.toString()))
}
})
}}});
If you have the message, then you can filter the reaction of that message by emojis:
const reaction = await message.reactions.cache.filter(r=> r.emoji.name === '✅').first().fetch();
Then you can fetch all reactions with that specific emoji:
await reaction.users.fetch();
Then you can filter from that if you want to (for example your own bot), with:
const filteredReactions = reaction.users.cache.filter(r=> !r.bot);
And don't forget to put these in an async function.

how do i make the bot do something after i react to its message?

I have tried to make the bot await a reaction from a user but I don't know how to set it up. I've tried this, I've also put the const filter in the first part but when it reacts to the message with 1️⃣ the bot says the reply.
message.channel.send(`the current number is: ${number}`).then(message => {
message.react('1️⃣')
message.react('2️⃣')
message.react('3️⃣')
});
const filter = (reaction, user) => {
return ['1️⃣', '2️⃣','3️⃣'].includes(reaction.emoji.name)
&& user.id === message.author.id;
}
message.awaitReactions(filter, { max: 1, time: 20000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '1️⃣') {
message.reply('you reacted with 1');
} else if (reaction.emoji.name === '2️⃣') {
message.reply('you reacted with 2');
} else {
message.reply('you reacted with 3');
}
})
.catch(collected => {
message.reply('game has ended');
});
Discord.js Client objects have the messageReactionAdd (along with Remove, RemoveAll and when a bot removes an emoji reaction) event trigger, which gives you a fairly simple solution.
let targetUser = "some-long-number";
// replace this with the author of the person who fires your
// reaction related command in your client.on('message') def.
client.on('messageReactionAdd', (reaction, user)) {
console.log('sample message to verify base functionality');
if (user != targetUser) return null;
switch (reaction.emoji.name) {
case "1️⃣":
message.reply("you reacted with 1️⃣");
break;
case "2️⃣":
message.reply("you reacted with 2️⃣");
break;
case "3️⃣":
message.reply("you reacted with 3️⃣");
break;
default:
// in case you want to log when they don't reply with the correct emoji.
break;
}
}
I've probably mistyped this somewhere, so feel free to correct me.
If message.reply() works, my first suggestion is to log the channel ID of the user's command in a global variable (such as channel-id), and use channel-id.send(content);.
I can't see the Emojis but I'll tell you how I do it (Note: I'm using an async function so I don't have to use plenty of callbacks, I just personally prefer it over .then chaining):
const msg = await message.channel.send(`the current number is: ${number}`);
await Promise.all([
message.react('1️⃣'),
message.react('2️⃣'),
message.react('3️⃣')
]);
const filter = (reaction, user) => ['1️⃣', '2️⃣','3️⃣'].includes(reaction.emoji.name) && user.id === message.author.id;
const collector = msg.createReactionCollector(filter, { time: 120000, max: 1 }); //setup here
collector.on('collect', async () => {
//... your logic after reaction here
});

Categories