Invites command bot reply sending message multiple times - javascript

I am using the invite tracker from the WOK tutorials, and even though the code works perfectly fine, and im using a command handler that has 0 issues, for some reason, the bot replies with multiple messages instead of 1 as seen in this image:
Here is the code that I used for the invites command:
const Discord = require("discord.js")
module.exports = {
commands: 'invites',
callback: (message) => {
const { guild } = message
guild.fetchInvites().then((invites) => {
const inviteCounter = {}
invites.forEach((invite) => {
const { uses, inviter } = invite
const { username, discriminator } = inviter
const name = `${username}#${discriminator}`
inviteCounter[name] = (inviteCounter[name] || 0) + uses
})
let replyText = ''
const sortedInvites = Object.keys(inviteCounter).sort((a, b) => inviteCounter[b] - inviteCounter[a])
for (const invite of sortedInvites) {
const count = inviteCounter[invite]
replyText += `\n${invite} has invited ${count} member(s)!`
const embed = new Discord.MessageEmbed()
embed.setTitle('Invites: ')
embed.setDescription(replyText)
message.reply(embed)
}
})
}
}
Fyi last time i posted this i forgot to post the code so yeah that was dumb my bad.

This is because you have message.reply in a for...of loop.
for (const invite of sortedInvites) {
const count = inviteCounter[invite]
replyText += `\n${invite} has invited ${count} member(s)!`
const embed = new Discord.MessageEmbed()
embed.setTitle('Invites: ')
embed.setDescription(replyText)
message.reply(embed) //here
}
You probably meant to put it outside of the loop so that it sends the resulting embed after all the iterations.

Related

members map with a limit per page

how could I make a member limit on a page? for example: only 10 members would appear on the first page, and to see the second page you would have to react with ⏩
const { MessageEmbed } = require('discord.js');
module.exports.run = async (client, message, args) => {
const role = message.mentions.roles.first() || message.guild.roles.cache.get(args[0]) || message.guild.roles.cache.find(r => r.name === args.slice(0).join(" "));
const embed = new MessageEmbed()
.setTitle(`Members with a role`)
.addFields(
{ name: 'alphabetical list', value: `\`\`\`fix\n${message.guild.roles.cache.get(role.id).members.map(m => m.user.tag.toUpperCase()).sort().join('\n') || 'none'}\`\`\``}
)
return message.channel.send(embed);
}
I would get the list of users as an array, then use slice to return a portion of the array. In your case I would do:
//Get a list of all user tags
const list = msg.guild.roles.cache.get(role.id).members.map(m => m.user.tag.toUpperCase()).sort();
//Let the user define the starting page
var pageNum = (parseInt(args[0]) * 10) - 10;
//Set a default option
if (!pageNum) {
pageNum = 0;
};
//Get 10 members, starting at the defined page
//Ex: if args[0] was "2", it would give you entries 10-19 of the array
var userList = list.slice(pageNum, pageNum + 9).join("\n");
Now that you can get users based off of a page number, you just need a way to set it! createReactionCollector is what you're looking for in this case. The discordjs.guide website has a great example of this that we can modify to fit our needs:
//Only respond to the two emojis, and only if the member who reacted is the message author
const filter = (reaction, user) => ["◀️", "▶️"].includes(reaction.emoji.name) && user.id === msg.author.id;
//Setting the time is generally a good thing to do, so that your bot isn't constantly waiting for new reactions
//It's set to 2 minutes in this case, which should be plenty of time
const collector = msg.createReactionCollector(filter, {
time: 120000
});
collector.on('collect', (reaction, user) => {
//Do stuff here
});
//We can just return when the reactor ends, send a message that the time is up, whatever we want!
collector.on('end', collected => {
return msg.channel.send("I'm done looking for reactions on the message!");
});
Now that we can get users and await reactions, we only need to put everything together. I would put the list retrieval in a seperate function that you can call easily:
//Initially take the page number from user input if requested
var page = parseInt(args[0]);
if (!page) {
page = 1;
};
//Send the message in a way that lets us edit it later
const listMsg = await msg.channel.send("This is what will be reacted to!");
//React in order
await listMsg.react("◀️");
await listMsg.react("▶️");
const filter = (reaction, user) => ["◀️", "▶️"].includes(reaction.emoji.name) && user.id === msg.author.id;
const collector = listMsg.createReactionCollector(filter, {
time: 120000
});
collector.on('collect', (reaction, user) => {
reaction.emoji.reaction.users.remove(user.id);
switch (reaction.emoji.name) {
case "◀️":
//Decrement the page number
--page;
//Make sure we don't go back too far
if (page < 1) {
page = 1;
};
listMsg.edit(getUsers(page));
break;
case "▶️":
//Increment the page number
++page;
listMsg.edit(getUsers(page));
break;
};
});
collector.on('end', collected => {
return msg.channel.send("I'm done looking for reactions on the message!");
});
function getUsers(n) {
const list = msg.guild.roles.cache.get(role.id).members.map(m => m.user.tag.toUpperCase()).sort();
//Take the page from the function params
var pageNum = (n * 10) - 10;
if (!pageNum) {
pageNum = 0;
};
return list.slice(pageNum, pageNum + 9).join("\n");
};
That's pretty much it! Obviously you'll have to tweak this to fit your own bot, but this code should be a great starting point.

Trying to show off emoji when it's added using Discord.js

Currently I'm trying to add something to my bot to display text and a preview when an emoji is added.
I was pretty close, but it appears the emoji doesn't exist on the server during the emojiCreate event.
my code (which is a mess) looks like this currently:
var latestEmojiName = "";
let announcementChannel = "";
client.on("emojiCreate", emoji => {
announcementChannel = emoji.guild.channels.find(x => x.id === "625678148440162314");
announcementChannel.send("new emoji has been added:");
latestEmojiName = emoji.name;
newEmojiFollowup1();
});
function newEmojiFollowup1() {
setTimeout(newEmojiFollowup2, 2000);
}
function newEmojiFollowup2() {
announcementChannel.send(client.guilds.find(x => x.id === "607642928872947724").emojis.find(x => x.name === latestEmojiName));
}
Ok, I added the following listener to one of my bots and it worked. Also, there is no need to look-up the guild because you do not need a timeout. The emoji object has all you need already.
You need to send: <:${emoji.name}:${emoji.id}>
Also, use let instead of var to resolve scoping issues and there is no need for all the "follow-on functions.
// Verified with discord.js#11.5.1
const channelId = "625678148440162314" // e.g. Channel: #general
client.on("emojiCreate", emoji => {
const channel = emoji.guild.channels.find(x => x.id === channelId)
channel.send("A new emoji has been added:")
channel.send(`<:${emoji.name}:${emoji.id}>`)
})
You can also send a rich-embed message:
// Verified with discord.js#11.5.1
const channelId = "625678148440162314" // e.g. Channel: #general
client.on("emojiCreate", emoji => {
const channel = emoji.guild.channels.find(x => x.id === channelId)
const embed = new RichEmbed()
.setTitle("A new emoji has been added!")
.setColor(0x222222)
.setDescription("Preview:")
embed.addField(`:${emoji.name}:`, `<:${emoji.name}:${emoji.id}>`, true)
channel.send(embed)
})

Discord help command - args.join isn't a function

with my discord bot I am working on a help command.
My command list file which the help command accesses is:
{
"Help": {
"name":"Help",
"group":"User",
"desc":"Displays a list of commands",
"usage":"help [group OR command]"
},
"Purge": {
"name":"Purge",
"group":"Admin",
"desc":"Deletes a specified number of messages",
"usage":"Purge <amount>"
}
}
These just define group, name, and usage of the commands. The code for the help command so far is:
const Discord = require('discord.js');
const bot = new Discord.Client();
const client = new Discord.Client();
const weather = require('weather-js');
const fs = require('fs');
const commands = JSON.parse(fs.readFileSync('Storage/commands.json', 'utf8'))
const token = "<my token>"
const prefix = 'cb!';
bot.on('message', message => {
// Variables
let msg = message.content.toUpperCase();
let sender = message.author;
let cont = message.content.slice(prefix.length).split(" ");
let args = cont.shift().toLowerCase();
if (message.content.startsWith(prefix+'help')) {
console.log('ok i hate this')
const embed = new Discord.RichEmbed()
.setColor(0x1D82B6)
let commandsFound = 0;
for (var cmd in commands) {
if (commands[cmd].group.toUpperCase() === 'USER') {
commandsFound++
embed.addField(`${commands[cmd].name}`, `**Description:** ${commands[cmd].desc}\n**Usage:** ${prefix + commands[cmd].usage}`);
}
}
embed.setFooter(`Currently showing user commands. To view another group do ${prefix}help [group / command]`)
embed.setDescription(`**${commandsFound} commands found** - <> means required, [] means optional`)
message.author.send({embed})
message.channel.send({embed: {
color: 0x1D82B6,
description: `**Check your DMs ${message.author}!**`
}})
} else {
// Variables
let groupFound = '';
for (var cmd in commands) {
if (args.join(" ").trim().toUpperCase() === commands[cmd].group.toUpperCase()) {
groupFound = commands[cmd].group.toUpperCase();
break;
}
}
if (groupFound != '') {
for (var cmd in commands) {
const embed = new Discord.RichEmbed()
.setColor(0x1D82B6)
let commandsFound = 0;
if (commands[cmd].group.toUpperCase() === groupFound) {
commandsFound++
embed.addField(`${commands[cmd].name}`, `**Description:** ${commands[cmd].desc}\n**Usage:** ${prefix + commands[cmd].usage}`);
}
}
embed.setFooter(`Currently showing ${groupFound} commands. To view another group do ${prefix}help [group / command]`)
embed.setDescription(`**${commandsFound} commands found** - <> means required, [] means optional`)
message.author.send({embed})
message.channel.send({embed: {
color: 0x1D82B6,
description: `**Check your DMs ${message.author}!**`
}})
}
}
});
If I were to type "cb!help admin" I would get this error in the console
if (args.join(" ").trim().toUpperCase() === commands[cmd].group.toUpperCase()) {
^
TypeError: args.join is not a function
What might I do to fix this? I've also tried if (args[0].join... but that doesn't work.
As always, thanks for taking the time to read this. I'm basing this off of out dated code so there are maybe some other errors. I'm trying too fix them all.
args has one definition in your code sample:
let args = cont.shift().toLowerCase();
This makes args a string - string do not have the method join() as join() is part of the Array prototype chain, which strings do not inherit from. shift() will return the first element of the cont array, so you may just want to call args.toUpperCase(), although I would recommend renaming your variables to make the meaning of what args is clearer.
You should try to swap your two variables at the top so that
let args = message.content.slice(prefix.length).split(' ');
let cont = args.shift().toLowerCase();
Then just put args in your if statement
if (args[0].toUpperCase === commands[cmd].group.toUpperCase) { /* Your code... */ }
Your args are already stored in an array so there is no need to trim them and the join function is also therefore not needed.
Hope this helps!
your missing client, insert client, message, args

ReferenceError: message is not defined - Welcome Message - embed

So I was playing with my welcome message and wanted to make it an embed, I ended up re-writing it all to work with the embed, however after I finished, I got the error message is not defined.
var welcomePath = './Storage/welcome.json';
var welcomeRead = fs.readFileSync(welcomePath);
var welcomeFile = JSON.parse(welcomeRead);
client.on('guildMemberAdd', (member) => {
var serverId = member.guild.id;
if (!welcomeFile[serverId]) {
console.log('Welcome is disabled!');
} else {
let welcomeChannel = welcomeFile[serverId].channel,
let setChannel = message.guild.channels.find(channel => channel.name === welcomeChannel);
const embed = new Discord.RichEmbed()
.setTitle("Test")
.setAuthor("Test")
.setColor(3447003)
.setDescription("Test")
.setThumbnail(message.author.avatarURL);
member.guild.channels.get(setChannel).send({
embed
});
}
});
The error pertains to this line
let setChannel = message.guild.channels.find(channel => channel.name === welcomeChannel);
I do really want to learn JS, and keep finding myself hitting this brick walls where I need to simply ask for help. I am also unsure if you fix my message is not defined that my code will actually do anything.
message is not defined, you should look for member.
let setChannel = member.guild.channels.find(channel => channel.name === welcomeChannel);
client.on('guildMemberAdd', (member) => {
var serverId = member.guild.id;
if (!welcomeFile[serverId]) {
console.log('Welcome is disabled!')
} else {
let welcomeChannel = welcomeFile[serverId].channel
let setChannel = member.guild.channels.find(channel => channel.name === welcomeChannel);
const embed = new Discord.RichEmbed()
.setTitle("Test")
.setAuthor("Test")
.setColor(3447003)
.setDescription("Test")
.setThumbnail(message.author.avatarURL)
member.guild.channels.get(setChannel).send({embed});
}
})

How do I add variable `XP` to `userData.XP` for my Discord.js bot?

So I have looked around but almost none of it is for Discord and included HTML which I can't use for Discord Bots. Here is what I am trying to do: Make an XP bot so that I can do an interesting Discord Game. Here I want XP to end up getting +10 when I say !killSlime but the output ends up as 0. If anyone could help with this I would Greatly Appreciate it. Also I do realize that only one person can use this bot. That is on purpose so that I can test and edit without my friends asking what is going on here.
const Discord = require("discord.js");
const bot = new Discord.Client();
const fs = require('fs');
let XP = JSON.parse(fs.readFileSync('./XP.json', 'utf8'));
bot.on("message", msg => {
let prefix = "!";
console.log(0)
if(!msg.content.startsWith(prefix)) return;
console.log(0.1)
if(msg.author.id != "235144525763444736") return;
console.log("help command")
if (msg.content.startsWith(prefix + "help")) {
msg.reply("Here are my commands: !help,")
}
let userData = XP[msg.author.id];
if (!userData) userData = {XP: 0, level: 0};
let curLevel = Math.floor(0.1 * Math.sqrt(userXP));
if (curLevel > userData.level) {
userData.level = curLevel;
msg.reply('You have lvled ^ to lvl **${curLevel}**!');
}
console.log("level")
if (msg.content.startsWith(prefix + "level")) {
msg.reply(`You are lvl ${userData.level}, with ${userData.XP} XP Right Now.`);
}
if (!XP[msg.author.id]) XP[msg.author.id] = {XP: 0, level: 0}
console.log("Slime")
if (msg.content.startsWith(prefix + "killSlime")) {
userData.XP += 10
msg.channel.sendMessage(`${msg.author} has killed a Slime!`)
}
console.log(XP)
fs.writeFile('./XP.json', JSON.stringify(XP), console.error);
});
I Forgot this:
let userData = XP[msg.author.id];
if (!userData) userData = {XP: 0, level: 0};

Categories

Resources