Bot replying multiple times when triggered by reaction - node.js

Right now I am making a discord bot (in version 12 of discord.js).
It works like this:
Someone sends and insult
If the insult is included in a list (stored in insultes.json) the bot send a message and adds a reaction
If we add the same reaction the bot sends another message
The problem I'm facing is that if I keep adding the reaction the bot keeps replying 2, 3, 4 times and so on: every time (n) I check the reaction it replies with n+1 messages.
This is the code:
bot.on('message', message => {
const insulte = require('./insultes.json');
for (let p = 0; p < insulte.length; p++) {
// Check if the insult is in the list and make sure it's not from the bot itself
if (message.content.toLowerCase().includes(insulte[p]) && message.author.id !== "711337757435363468") {
message.channel.send("First message").then(messageReaction => {
messageReaction.react("➡️");
});
bot.on('messageReactionAdd', (reaction, user) => {
if (reaction.emoji.name === "➡️" && user.id !== "711337757435363468") {
message.channel.send("Additional message");
}
});
}
}
});

I think your problem comes from the fact that you're using bot.on('messageReactionAdd', ...: that means that every time you run that part of the code the code will add another listener that adds up to the ones that you used before.
Also, that code will trigger when a reaction to any message is added, not just the one you sent.
From your question, I don't understand if the bot is supposed to reply with one message every time you hit the reaction on that message, or just do it once and then ignore the message. I'll assume it's the latter.
Here's my take on this:
bot.on('message', message => {
const insults = require('./insultes.json')
if (insults.some(i => message.content.toLowerCase().includes(i)) && message.author.id !== "711337757435363468") {
message.channel.send("First message").then(myMsg=> {
myMsg.react("➡️");
let reactionFilter = (reaction, user) => reaction.emoji.name === '➡️' && user.id !== "711337757435363468"
myMsg.awaitReactions(reactionFilter, { max: 1 }).then(() => {
myMsg.channel.send('Additional message')
})
});
}
})
As you can see, I'm using Array.some() to check whether any insult is in the message, instead of a for loop. I'm using Message.awaitReactions() to fetch the first reaction and respond to that: after that, the bot will just ignore any other reaction on that message, but will still work on others.
Feel free to let me know if something is not clear or doesn't work :)

Related

Check if value is equal to another value

What i am after:
I am developing a discord.js (V14) bot at the moment. The idea is the following. If a member executes the following / command:
/mute target:#member time:1d reason:spamming
Check if target:#member is equal to the bot it self.
My issue:
The below code should in theory (to my knownledge) be enough to check if the target:#member is equal to discord bot. However, my code completely skips that step. Even if i verify via console.log that both values are equal.
The Code:
10258xxxx - console.log(user.id);
10258xxxx - console.log(interaction.guild.members.me.id);
module.exports = {
data: new SlashCommandBuilder()
.setName("mute")
.setDescription("Mute a member.")
.addUserOption(option =>
option.setName("target")
.setDescription("Select the user you wish to mute.")
)
.addStringOption(option =>
option.setName("time")
.setDescription("How long should the mute last?")
)
.addStringOption(option =>
option.setName("reason")
.setDescription("What is the reason of the mute?")
),
async execute(interaction) {
const user = options.getUser("target");
if (user.id === interaction.guild.members.me.id){
return interaction.reply("I can't mute my self.");
}
return interaction.reply("Success");
}
I believe you should use interaction.options.getUser().
const user = interaction.options.getUser('target')
if(user.id == interaction.guild.members.me.id) return await interaction.reply('I can\'t mute myself');
await interaction.reply('Success!'); // don't use return here
Not completely familiar with discord, but it looks like you might need to add the await keyword
return await interaction.reply("I can't mute my self.");
Without going into detail of how async await works, what you could test is the following to see that the line is running:
if (user.id === interaction.guild.members.me.id){
console.log("Can you see me?");
return interaction.reply("I can't mute my self.");
}
If you can see the log, what is happening is the code stops running before waiting for the async function to finish. If you want to understand this better, learn more about async await!

How to make Discord.js bot fetch last attachment on channel

I'm trying to make my Discord bot send the last attachment on the channel but I'm having problem with sending it.
When I use "m.attachments.first().url" it says "Unhandled promise rejection", and when I use "m.attachments.first()" it says "Cannot send an empty message".
if (message.content.toLowerCase() === 'test'){
message.channel.messages.fetch().then(messages => {
const firstAttachment = messages.filter((m) => m.attachments.first().url);
message.channel.send(firstAttachment);
})}
EDIT: I tried a lot of different things but the only that gave me some result was this (the result was "undefined"):
if (message.content.toLowerCase() === 'test'){
message.channel.messages.fetch().then(messages => {
const att = messages.filter(m => m.attachments.size > 0);
message.channel.send(`${att.first().attachments.url}`)
})}
You were so close with your second piece of code! You just need to add another .first() after attachments.
message.channel.messages.fetch().then(messages => {
const att = messages.filter(m => m.attachments.size > 0);
message.channel.send(att.first().attachments.first().url);
});
You'll likely also want to make sure att actually has a value before sending a message, otherwise you'll get errors.

Discord.js sending message upon voice channel joining is not working

so what my bot is meant to do is that when someone joins a certain channel, it will send a message to log channel "SomeGuy123 joined the channel!". So I was constructing it for like an hour, and now I resolved all the errors, but it doesnt say anything, nor it doesnt give any errors. I can send the whole code if you want. Here is just the part about sending the message upon joining:
client.on("voiceStateUpdate", (oldState, newState) => {
const newUserChannel = newState.ChannelID;
const oldUserChannel = oldState.ChannelID
const textChannel = newState.guild.channels.cache.get('715141269395079208')
if(newUserChannel === '715141827644358707') {
textChannel.send(`${newState.user.username} (${newState.id}) has joined the channel`)
} else if (oldUserChannel === '715141827644358707' && newUserChannel !== '715141827644358707') {
textChannel.send(`${newState.user.username} (${newState.id}) has left the channel`)
}
})
Thank you in advance.
https://discord.js.org/#/docs/main/stable/class/Client?scrollTo=e-voiceStateUpdate
https://discord.js.org/#/docs/main/stable/class/VoiceState
<VoiceState>.ChannelID is undefined, its <VoiceState>.channelID, javascript is not pascal case except in classes

How can i check if a person has went online, offline, etc. in discord.js?

const channel = client.channels.cache.get('<channelid>');
const person1 = client.users.cache.get('<userid>');
const person = client.users.cache.get('<userid>');
client.on('message', message =>{
client.on('presenceUpdate', () =>{
if(person1.user.presence.status === 'dnd' || person1.user.presence.status === 'online'){
channelforstatus.send('person1 is now online');
}
else if(peron1.user.presence.status === 'offline' || person1.user.presence.status === 'idle'){
channel.send('person1 is offline');
}
client.on('message', message => {
client.on('presenceUpdate', () =>{
if(person.user.presence.status === 'dnd' || person.user.presence.status === 'online'){
channel.send('person is now on');
}
else if(person.user.presence.status === 'offline' || person.user.presence.status === 'idle'){
channel.send('person is now off');
}
});
});
});
});
This is what I've tried and the .send() the function is not working. I've looked everywhere and found nothing that could help me with this problem. I just need it so it checks every time if a specific person has went online, offline, etc. And sends a message to a specific channel.
First of all, one rule to abide with is that event listeners should always be in top level of your code and never nested. (Else you are subject to memory leaks and other issues like duplicated and unintended code execution).
client.on("message", (message) => {
...
});
client.on('presenceUpdate', (oldPresence, newPresence) => {
...
});
Now when looking at presenceUpdate event and Presence object documentation you can manage to see if a status evolved like that :
client.on('presenceUpdate', (oldPresence, newPresence) => {
let member = newPresence.member;
// User id of the user you're tracking status.
if (member.id === '<userId>') {
if (oldPresence.status !== newPresence.status) {
// Your specific channel to send a message in.
let channel = member.guild.channels.cache.get('<channelId>');
// You can also use member.guild.channels.resolve('<channelId>');
let text = "";
if (newPresence.status === "online") {
text = "Our special member is online!";
} else if (newPresence.status === "offline") {
text = "Oh no! Our special member is offline.";
}
// etc...
channel.send(text);
}
}
});
Be aware that presenceUpdate event is fire by EACH guild the user and bot share, meaning that if user status change and share two guilds with your bot, this code will be executed twice.
In case you use presence but get offline instead of the user being online I spent like.. 2 whole days looking for the answer so ill share it anywayz
Common mistakes on presence.status is forgetting to check these stuff at the the developer applications. which i have no idea what means
A screenshot
now on your message (command handler) function.. if you have one
message.guild.members.cache.get('userId').presence.status
or
${message.author.username} is now ${message.author.presence.status};
Ill update this if I found out how to presence all the users instead of just one
my first post... I SHALL REMEMBER THIS xD
To get the presence, you can use user.presence, which will get all kinds of info about the user, but you only need user.presence.clientStatus.desktop
so your code would, for example, be
bot.on('presenceUpdate', () =>{
let person1 = bot.users.cache.get('USERID')
console.log(person1.presence.clientStatus.desktop)
if(person1.presence.clientStatus.desktop === 'dnd' || person1.presence.clientStatus.desktop === 'online'){
channel.send('person1 is now online');
}
else if(person1.presence.clientStatus.desktop === 'offline' || person1.presence.clientStatus.desktop === 'idle'){
channel.send('person1 is offline');
}
})

Discord bot JS Can someone explain what happened and how to prevent it?

When code is:
client.on('message', msg => {
const args = msg.content;
const command = args.toLowerCase()
if (command === 'frick'){
msg.reply('Sorry Sir this is a Christian server so no swearing! >:(');
}
});
message is sent normally
and when I added 'shit' to it
client.on('message', msg => {
const args = msg.content;
const command = args.toLowerCase()
if (command === 'frick' || 'shit'){
msg.reply('Sorry Sir this is a Christian server so no swearing! >:(');
}
});
this was a result
it just looped
and I know I can add a line which ignores bots but I want it to be active for bots as well
Your if statement always evaluates to true, because you are essentially checking if ('shit'), which is truthy because its length is greater than 0.
You aren't ignoring bot messages. So you're creating an infinite loop where bot sends message -> bot receives own message -> bot sends message -> bot receives own message -> ....
To fix 1, make sure you write your if statements properly:
if (command === 'frick' || command === 'shit') {
And to fix 2, you can add a simple if to the start of your message handler to check if the author is a bot:
if (msg.author.bot) {
return;
}
To make it even shorter you could do:
if (command === ('frick' || 'shit')) {

Resources