How to make a reaction disappear after a certain amount of reactions? - javascript

I want to make a poll command, where I use the command, and when the reaction reaches a certain amount of reactions it (the reaction) gets deleted. That would be useful to see who wins if you understand me.
That's what I'm using right now for only adding a reaction.
bot.on('message', msg => {
if(msg.content === "memes"){
msg.react("🤏🏾")
}
})

You can use reaction collectors to collect user reactions on a message. The collector has options like maxUsers that you can use to set the maximum number of users to react. Once it's reached, the collector.on('end') fires, so you can use it to get the number of users reacted, etc.
You can remove the reactions using message.reactions.removeAll();
Check the snippet below:
if (message.content === 'memes') {
const EMOJI = '🤏🏾';
const filter = (reaction, user) =>
reaction.emoji.name === EMOJI && !user.bot;
const collector = message.createReactionCollector(filter, {
// optional, the maximum time in ms the collector collects reactions
time: 10000,
// maximum number of users to react
// it includes the bot's reaction too
maxUsers: 3,
});
message.react(EMOJI);
collector.on('collect', (reaction, user) => {
// it fires every time someone reacts to the message
console.log('collected', reaction);
});
collector.on('end', async (collected, reason) => {
const reaction = collected.get(EMOJI);
if (!reaction) {
return message.channel.send('Oops, there were no reactions');
}
// it includes the bot too
const allUsers = await reaction.users.fetch();
// collection of users who reacted to the message, bot removed
const users = allUsers.filter((user) => user != client.user);
message.channel.send(
`Poll has ended because of ${reason}. Received ${users.size} reactions.`
);
message.channel.send(
`Users reacted: ${users.array().join(', ')}`
);
// remove reactions
message.reactions.removeAll();
});
}
If you want to have an array of emojis, you can use an EMOJIS array instead:
if (message.content === 'memes') {
const EMOJIS = ['🤏🏾', '😱'];
const filter = (reaction, user) =>
EMOJIS.includes(reaction.emoji.name) && !user.bot;
const collector = message.createReactionCollector(filter, {
time: 10000,
maxUsers: 3,
});
EMOJIS.forEach((emoji) => message.react(emoji));
collector.on('collect', (reaction, user) => {
// it fires every time someone reacts to the message
});
collector.on('end', async (collected, reason) => {
if (!collected.size) {
message.reactions.removeAll();
return message.channel.send('Oops, there were no reactions');
}
// you can use the collected reactions any way you want
console.log(collected);
// remove reactions
message.reactions.removeAll();
});
}

Related

(Discord Bot) Get message that follows command prefix

I'm trying to reference the previous message sent by a client using discord.js
How would I go about getting the last message sent?
client.on("messageCreate", (message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'set-reminder'){
channelName = client.channels.cache.find(channel => channel.name === "spam");
message.channel.send("Command Works");
channelName.messages.fetch({ limit: 1 }).then(messages => {
// find "command works" message (previous message from client)
let lastMessage = messages.first();
console.log(lastMessage.content);
})
}
})```
The message.channel.send function is async
You can await the send function or use .then
The send function also returns the message, you don't need a query to get it
await
let message = await message.channel.send("Command Works");
console.log(message.content);
then
message.channel.send("Command Works").then((message) => {
console.log(message.content);
});
(async means not-synchronous : you have to wait to get its result)

I got problems with my reaction collector for my discord bot

i recently made a discord bot and added a special function that makes the bot collect a specific emoji in order to switch a page in an embed menu in dms of the bot. But it turned out to not really work so im asking here if someone can help me solve this.
const filter = (reaction, user) => {
return ['➡️'].includes(reaction.emoji.name) && user.id !== client.user.id;
};
const collector = message.createReactionCollector(filter, { time: 60000 });
collector.on('collect', (reaction, user) => {
console.log(`Collected ${reaction.emoji.name} from ${user.tag}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});

"mute" command gives random output

if(command === "mute"){
const target = message.mentions.users.first();
if (target) {
if (!message.member.hasPermission("ADMINISTRATOR")) {
return message.reply("Unauthorized");
}
let muted = client.settings.get(message.guild.id, 'mute')
let muteRole = message.guild.roles.cache.find(role => role.name === muted);
let memberTarget = message.guild.members.cache.get(target.id);
let rolelist = memberTarget.roles.cache
.map(r => r)
if (!args[1]) {
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> has been muted`);
return
}
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> will be muted for ${ms(ms(args[1]))}`);
setTimeout(function () {
memberTarget.roles.add(rolelist);
memberTarget.roles.remove(muteRole);
}, ms(args[1]));
} else {
message.channel.send('User not found!');
}
So I have this mute command which removes all your roles, gives you the muteRole, when time is up, it gives back your previous roles and removes the muteRole. The problem I'm having is that it sometimes removes all your roles and doesn't give you the muteRole, other times it doesn't remove the muteRole when the time is up. Sometimes it removes all your roles and doesn't give you the
muteRole and when the times up it doesn't give your roles back...
Basically the outcome is always random. So my question is how do I make it consistent?
The methods .add() and .remove() return a Promise so you should try using await / .then().
If you do it with this, the next function or .then() will not be executed until the promise is completely processed.
Example:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'));
Now you're nearly finished. The last thing you need is the .catch() block, because if the code above fails / throws an error you should catch that:
.catch(err => console.log(`An error occured: ${err}`))
Final result:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'))
.catch(err => console.log(`An error occured: ${err}`));
References
GuildMemberRoleManager (Discord.js)
Promises
Handle promises
Await

Adding a global timer for tmi.js integrated discord.js

I'm trying to do a discord bot that listens to multiple twitch chat for commands, then run them on discord, using both tmi.js and discord.js. Currently it is working, but I can't seem to add a global cooldown on the commands itself to prevent spamming. At first I've tried adding a cd timer to each command, but I'm unable to get it working, hence the decision to try to make a global cd but still to no avail. Am I doing something wrongly?
twitch.on('message', (channel, tags, message, self) => {
if(!message.startsWith(prefix) || self) return;
const args = (message.slice(prefix.length).trim().split(/ +/));
const commandName = args.shift().toLowerCase();
if (!twitch.commands.has(commandName)) return;
const command = twitch.commands.get(commandName);
}
try {
command.execute(bot, botChannel, vcChannel, isReady);
} catch (error){
console.error(error);
}
});
just to update, I basically took a leaflet from async await functions here: https://stackoverflow.com/a/54772517/14637034
Then, I modified the code as such:
const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => {
setTimeout(() => {
cb();
resolve();
}, timeout);
});
const doStuffAsync = async () => {
await setAsyncTimeout(() => {
isReady = true;
console.log(isReady);
}, 10000);};
twitch.on('message', (channel, tags, message, self) => {
if(!message.startsWith(prefix) || self) return;
const args = (message.slice(prefix.length).trim().split(/ +/));
const commandName = args.shift().toLowerCase();
if (!twitch.commands.has(commandName)) return;
if (isReady){
const command = twitch.commands.get(commandName);
isReady = false;
try {
command.execute(bot, botChannel, vcChannel);
} catch (error){
console.error(error);
}
doStuffAsync();
}
});
Seemed to work for now, as 10s is a long enough time for bot to leave discord properly without causing timeout. I'm still open to better suggestions for optimization though!

Removing just one reaction from message (Discord.js)

I am creating an embed where you can navigate through pages by reacting. By following a tutorial I came up with this but here's the problem: it removes all reactions of the same kind when the user react to it (basically If I react with ❤️, the bot removes either my reaction and theirs, letting ⚙️ be the only reaction available)
let embed= new Discord.MessageEmbed()
.setTitle(Title)
.setURL(url)
.setThumbnail(image)
const filter1 = (reaction, user) => reaction.emoji.name === '⚙️' && user.id === message.author.id
const filter2 = (reaction, user) => reaction.emoji.name === '❤️' && user.id === message.author.id
let msg = await message.channel.send(embed)
await msg.react('⚙️')
await msg.react('❤️')
const collector1= await msg.createReactionCollector(filter1, {time: 60000})
const collector2= await msg.createReactionCollector(filter2, {time: 60000})
collector1.on('collect', async r => {
embed.setDescription('Page 1')
r.remove(message.author.id) // <<== This removes also the bot reaction
msg.edit(embed)
})
collector2.on('collect', async r => {
embed.setDescription('Page 2')
r.remove(message.author.id) // <<== This removes also the bot reaction
msg.edit(embed)
})
Hopefully, you understood my problem, I just wanted to have the bot removing my reaction, not all.
According to the docs, MessageReaction.remove() removes the entire reaction, not just 1 user. If you call the remove() function on the ReactionUserManager, you can remove 1 user from the reaction.
Take a look at the example code below and give it a try.
collector1.on('collect', async (reaction, user) => {
embed.setDescription('Page 1');
reaction.users.remove(user);
msg.edit(embed);
});

Categories