I created a discord bot with the goal to generate reactive embeds with emoji-buttons. My problem is all the embeds created with the bot are modified simultaneously once a 'button' is pressed.
Below a pseudo-code of my bot:
const raidEmbed = new Discord.MessageEmbed() //create the embed
//some code to fill the embed
message.channel.send(raidEmbed).then(embedMessage => {
embedMessage.react('❌')
.then(()=>embedMessage.react('⭕')
//more react to create all the 'buttons'
client.on('messageReactionAdd', (reaction, user) => {
//some code to do stuff when the right 'button' is pressed
//then reset the button with this code:
if (user.id !== client.user.id) {
reaction.users.remove(user.id);
}
const newEmbed = new Discord.MessageEmbed()
//code to create the new embed
embedMessage.edit(newEmbed);
}
})
I don't understand why all my embeds are linked together and how to fix this issue.
Your embeds are not all linked together. The issue here is that you are using a global event to check for reactions. This is the part of your code that is the issue:
client.on('messageReactionAdd', (reaction, user) => {
//some code to do stuff when the right 'button' is pressed
//then reset the button with this code:
if (user.id !== client.user.id) {
reaction.users.remove(user.id);
}
const newEmbed = new Discord.MessageEmbed()
//code to create the new embed
embedMessage.edit(newEmbed);
}
What this part of your code is doing is whenever a reaction is added to any message, all of your embeds are edited. This means that even adding a reaction to a message that is not an embed will cause all of your embeds to be modified. messageReactionAdd is a global event, meaning it applies to all messages, not just your embed messages.
The best solution is to use a reaction collector instead of a reaction event. Reaction collectors are created on specific messages, so only the embed you reacted on will be modified.
Here is an example with your code, it may not necessarily be a working example but it should give you a general idea of how to accomplish this:
const raidEmbed = new Discord.MessageEmbed() //create the embed
//some code to fill the embed
message.channel.send(raidEmbed).then(embedMessage => {
embedMessage.react('❌')
.then(()=>embedMessage.react('⭕')
//more react to create all the 'buttons'
const filter = (reaction, user) => (r.emoji.name == "❌" || r.emoji.name == "⭕") && user.id === message.author.id;
const collector = embedMessage.createReactionCollector(filter, { time: 15000 });
collector.on('collect', reaction => {
//some code to do stuff when the right 'button' is pressed
//then reset the button with this code:
reaction.users.remove(message.author.id);
const newEmbed = new Discord.MessageEmbed()
//code to create the new embed
embedMessage.edit(newEmbed);
}
})
You can also use the filter to narrow down which users' reactions should be collected as well as what specific reactions you want to collect.
Related
So i need a bot that tracks another bot's status. like if its online it will say in a channel (with an embed) "The Bot Is Online" And The Same if it goes offline and whenever someone does !status {botname} it shows the uptime/downtime of the bot and 'last online' date
if someone can make it happen i will really appricate it!
also i found this github rebo but it dosen't work, it just says the bot is online and whenever i type !setup {channel} it turns off
The Link to the Repo: https://github.com/sujalgoel/discord-bot-status-checker
Also uh it can be any language, i don't really want to add anything else 😅.
Again, Thanks!
First of all, you would need the privileged Presence intent, which you can enable in the Developer Portal.
Tracking the bot's status
In order to have this work, we have to listen to the presenceUpdate event in discord.js. This event emits whenever someone's presence (a.k.a. status) updates.
Add this in your index.js file, or an event handler file:
// put this with your other imports (and esm equivalent if necessary)
const { MessageEmbed } = require("discord.js");
client.on("presenceUpdate", async (oldPresence, newPresence) => {
// check if the member is the bot we're looking for, if not, return
if (newPresence.member !== "your other bot id here") return;
// check if the status (online, idle, dnd, offline) updated, if not, return
if (oldPresence?.status === newPresence.status) return;
// fetch the channel that we're sending a message in
const channel = await client.channels.fetch("your updating channel id here");
// create the embed
const embed = new MessageEmbed()
.setTitle(`${newPresence.member.displayName}'s status updated!`)
.addField("Old status", oldPresence?.status ?? "offline")
.addField("New status", newPresence.status ?? "offline");
channel.send({ embeds: [embed] });
});
Now, whenever we update the targeted bot's status (online, idle, dnd, offline), it should send the embed we created!
!status command
This one will be a bit harder. If you don't have or want to use a database, we will need to store it in a Collection. The important thing about a Collection is that it resets whenever your bot updates, meaning that even if your bot restarts, everything in that Collection is gone. Collections, rather than just a variable, allows you to store more than one bot's value if you need it in the future.
However, because I don't know what you want or what database you're using, we're going to use Collections.
In your index.js file from before:
// put this with your other imports (and esm equivalent if necessary)
const { Collection, MessageEmbed } = require("discord.js");
// create a collection to store our status data
const client.statusCollection = new Collection();
client.statusCollection.set("your other bot id here", Date.now());
client.on("presenceUpdate", async (oldPresence, newPresence) => {
// check if the member is the bot we're looking for, if not, return
if (newPresence.member !== "your other bot id here") return;
// check if the status (online, idle, dnd, offline) updated, if not, return
if (oldPresence?.status === newPresence.status) return;
// fetch the channel that we're sending a message in
const channel = await client.channels.fetch("your updating channel id here");
// create the embed
const embed = new MessageEmbed()
.setTitle(`${newPresence.member.displayName}'s status updated!`)
.addField("Old status", oldPresence?.status ?? "offline")
.addField("New status", newPresence.status ?? "offline");
channel.send({ embeds: [embed] });
// add the changes in our Collection if changed from/to offline
if ((oldPresence?.status === "offline" || !oldPresence) || (newPresence.status === "offline")) {
client.statusCollection.set("your other bot id here", Date.now());
}
});
Assuming that you already have a prefix command handler (not slash commands) and that the message, args (array of arguments separated by spaces), and client exists, put this in a command file, and make sure it's in an async/await context:
// put this at the top of the file
const { MessageEmbed } = require("discord.js");
const bot = await message.guild.members.fetch("your other bot id here");
const embed = new MessageEmbed()
.setTitle(`${bot.displayName}'s status`);
// if bot is currently offline
if ((bot.presence?.status === "offline") || (!bot.presence)) {
const lastOnline = client.statusCollection.get("your other bot id here");
embed.setDescription(`The bot is currently offline, it was last online at <t:${lastOnline / 1000}:F>`);
} else { // if bot is not currently offline
const uptime = client.statusCollection.get("your other bot id here");
embed.setDescription(`The bot is currently online, its uptime is ${uptime / 1000}`);
};
message.reply({ embeds: [embed] });
In no way is this the most perfect code, but, it does the trick and is a great starting point for you to add on. Some suggestions would be to add the tracker in an event handler rather than your index.js file, use a database rather than a local Collection, and of course, prettify the embed messages!
is there any way to put the user who created the channel in .setAuthor? I searched in https://discord.js.org/#/docs/main/stable/class/GuildChannel but found nothing
client.on("channelCreate", function(channel) {
const logchannel = channel.guild.channels.cache.find(ch => ch.name === "logchannel")
if (!logchannel) return
const embed = new Discord.MessageEmbed()
.setTitle("Channel created)
.setDescription(`Channel <#${channel.id}> has created.`)
.setTimestamp()
.setAuthor(//user who created the channel)
logchannel.send(embed)
})
I think it's best to use the AuditLogs, you may want to take a look at it.
I am new to Discord js and I am trying to make my bot move all users that react to an embed into a certain voice channel. Currently, it takes whoever wrote the message and moves them to the specified voice channel.I tried many combinations of user.id, guild.member, etc. What would I put before the .setVoiceChannel? I am confused as to what message.member is other than the person that wrote the message. Thank you!
collector.on('collect', (reaction, user) => {
if (reaction.emoji.name == reactionControls.VOID) {
const channel = message.guild.channels.find('name', 'Void 1');
message.member.setVoiceChannel(channel);
}
});
message.member does refer to the user who execute the command, if you want the member who reacted you will have to convert user using <GuildMember>.fetchMember, the only issue now is that the collect event doesn't give the parameter of user in v11.5.1 so you will need to just use collector.users.last() to get the last reactor
collector.on('collect', async (reaction) => {
if (reaction.emoji.name == reactionControls.VOID) {
const channel = message.guild.channels.find('name', 'Void 1');
const user = collector.users.last();
const member = await message.guild.fetchMember(user);
member.setVoiceChannel(channel);
}
});
This is my first time using js. I need to ban a certain word in a certain channel. I don't want the message to be deleted if it is not in the specific channel.
For Example:
I want to ban the word "goodbye" in the #greeting channel
BUT
I don't want to ban the word "goodbye" In the #farewell channel
How would I go about this?
Thanks.
By the way I wanted to use example code, but none of it made any sense.
I wrote a simple example for you on how to achieve this:
const Discord = require("discord.js");
const Client = new Discord.Client();
const ForbiddenWords = {
"ChannelID": ["goodbaye", "bye"] // Greeting channel
};
Client.on("ready", () => {
console.log(`${Client.user.tag} is ready!`);
});
Client.on("message", (message) => { // Fired when the bot detects a new message.
if (message.author.bot) {return false}; // Checking if the message author is a bot.
if (ForbiddenWords[message.channel.id]) { // Checking if the current channel has any forbidden words in the ForbiddenWords Object
if (ForbiddenWords[message.channel.id].some(word => message.content.toString().toLowerCase().includes(word))) { // Checking if the message contains any forbidden words
message.delete(); // Deleting the message.
};
};
});
Client.login(process.env.DISCORD_AUTH_TOKEN);
I'm writing a discord bot using discord.js, and I've recently added a //translate command that utilizes the Google Translate API to translate between all the languages supported by Google Translate. I want to add the ability to quickly re-translate the translation back into English using reactions, and I want the bot to check if 1 person has reacted to the post with the provided reaction, and if they have, re-translate the translation back to English.
I'm really close, but I've run into the problem that I can't get the bot to check if it itself sent the reaction, so it auto-retranslates back to English because it's detecting it's own reaction. I want for it to only re-translate when A PERSON reacts, and only ONCE.
I'm not super familiar with this area of discord.js yet, so I can't really figure out how to do it.
Here is the code:
if (msg.content.startsWith(`${prefix}translate`) || msg.content.startsWith(`${prefix}t`)) {
const text = args.slice(1).join(` `);
if (!text) return msg.channel.send(`Nothing to translate provided! Languages codes are at https://cloud.google.com/translate/docs/languages !\n Command syntax: \`${prefix}translate\` or \`${prefix}t\` [text] [language code]`);
const text1 = text.substring(0, text.length - 2)
const target = text.substring(text.length - 2, text.length) || languages
translate
.translate(text1, target)
.then(results => {
const translation = results[0];
msg.channel.send(`Translation: ${translation}`).then(sentText => {
sentText.react(`🔀`);
const filter = (reaction, user) => {
return ['🔀'].includes(reaction.emoji.name);
};
sentText.awaitReactions(filter, { max: 2, time: 5000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '🔀' && sentText.react.me === false) {
const target = `en`
translate
.translate(text1, target)
.then(results => {
const translation = results[0];
msg.channel.send(`Translation: ${translation}`);
})
.catch(err => {
console.log(err);
})
}
})
})
})
//code for command continues below this line, but it is irrelevant to what I'm trying to achieve
Expected result: Bot re-translates back to English if a user reacts with the provided reaction, and only once.
Actual result: Bot does nothing, or, if I remove the && sentText.react.me === false, the bot re-translates back to English because it's detecting its own reaction.
Any help would be appreciated!
In your filter, you can check to make sure the user isn't the client, like so...
const filter = (reaction, user) => reaction.emoji.name === '🔀' && user.id !== client.user.id;
That way, only reactions that are not added by the client are collected.
You'll have to change your max option in the collector to 1, since the client's own reaction won't be collected. You can also remove the if statement comparing reaction.emoji.name.