Discord.js V12 Message Collector "bug"? - javascript

I am making a roster command, and this is my code so far, the error is when it comes to the admin it bugs out like in the picture and it doesn't continue... It also saves all of the answers in a file.
So an admin does $roster setup and it starts saving replies for the names of each file. This is the only part I've done for now, so the setup. And I am getting that bug there, there's no error in the console.
client.on('message', async message => {
if (message.content.startsWith(prefix + "roster")) {
if (!message.member.hasPermission('ADMINISTRATOR')) return message.channel.send('You do not have that permission! :x:').then(message.react(':x:'))
if (message.author.bot){}
else {
!fs.existsSync(`./roster/` + message.guild.id) && fs.mkdirSync(`./roster/` + message.guild.id, { recursive: true })
const args = message.content.slice(prefix.length + 7).split(/ +/)
let uReply = args[0];
if(!uReply) return message.channel.send("Please use the following options: `setup`, `send`, `add` or `remove`!")
//SETUP
if(uReply === "setup") {
const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 10000 });
message.channel.send("Please write the exact role name of leader role (with emojis if it has).")
collector.on('collect', message => {
let leaderRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Leader`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the leader role is called \`${leaderRole}\`.`)
collector.off
message.channel.send("Now, whats the role name of co-leader or co-owner role (with emojis if it has)?")
collector.on('collect', message => {
let coleaderRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Co-Leader`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the co-leader/co-owner role is called \`${coleaderRole}\`.`)
collector.off
message.channel.send("Now, whats the role name of admin role (with emojis if it has)?")
collector.on('collect', message => {
let adminRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Admin`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the admin role is called \`${adminRole}\`.`)
collector.off
message.channel.send("Awesome, now whats the role name of staff role (with emojis if it has)?")
collector.on('collect', message => {
let staffRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Staff`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the staff role is called \`${staffRole}\`.`)
collector.off
message.channel.send("Cool, now whats the role name of tiny-staff role (with emojis if it has)?")
collector.on('collect', message => {
let tinyStaffRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Tiny-Staff`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the tiny-staff role is called \`${tinyStaffRole}\`.`)
collector.off
message.channel.send("Just a few more, now whats the role name of higher ranked members role (with emojis if it has)?")
collector.on('collect', message => {
let HigherRankedRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `HigherRanked`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the higher ranked members role is called \`${HigherRankedRole}\`.`)
collector.off
message.channel.send("Last one, whats the role name of the normal members role (with emojis if it has)?")
collector.on('collect', message => {
let NormalMembersRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `NormalMembers`+".txt", message.content, (err) => console.error);
message.channel.send(`Awesome, the normal members role is called \`${NormalMembersRole}\`.`)
message.channel.send("That's it for setup.")
collector.off
})})})})})})})
}
}
}});
Picture:

I believe that the error comes from the original MessageCollector listener not being properly disabled, so the original listener still triggers for each additional message.
It looks like you tried to stop the original listener with collector.off, but because this is a statement instead of a function call, it doesn't do anything. Furthermore, if it did function, it would end the parent collector and none of the subsequent collector.on callbacks would work.
Instead, I would replace the collector.on functions with collector.once and remove the collector.off statements. Changing it to collector.once automatically ends the listener after it receives the first event, which is what you want in this scenario. If you wanted to receive more than one event, you'd have to use something else.
For example, the listener would look something like this:
collector.once('collect', message => {
let leaderRole = message.content
fs.writeFileSync(`./roster/${message.guild.id}/`+ `Leader`+".txt", message.content, (err) => console.error);
message.channel.send(`Ok, the leader role is called \`${leaderRole}\`.`)
/* ... Rest of code ... */
}

Related

Discord js bot: Cannot send DM to users with specific role

I seem to be having serious trouble sending DM's to all users with a specific role.
Here is my bot code:
bot.on('message', async message => {
members = message.guild.roles.cache.find(role => role.id === "12345678998765").members.map(m => m.user.id);
members.forEach(member_id => {
sleep(5000).then(() => {
message.users.fetch(member_id, false).then((user) => {
user.send("some message");
});
});
});
});
This code gives me the error:
Cannot read properties of null (reading 'roles')
on this line:
members = message.guild.roles.cache.find(role => role.id === ....
However that is not the issue. When I comment out the sleep command to send the message and output the member roles using:
members.forEach(member_id => {
console.log(member_id)
//sleep(5000).then(() => {
// bot.users.fetch(member_id, false).then((user) => {
// user.send("some message");
// });
//});
});
I get a list returned in the console of all the user ID's.. So it must be returning the roles.
How do I send a message to all users with a specific role ID ?? I want to be able to loop through them and put a wait in to reduce the API requests and spam trigger.
To fix your first issue, message.guild will be null in DM. Make sure it isn't DM, or if it has to be, choose a guild with client.guilds.cache.get("id").
bot.on("message", async message => {
let { guild } = message
if (!guild) guild = bot.guilds.cache.get("id")
//...
})
To fix your other issue, you can run GuildMember#send() rather than getting the IDs and fetching the users
bot.on("message", async message => {
let { guild } = message
if (!guild) guild = bot.guilds.cache.get("id")
let members = guild.roles.cache.get("12345678998765").members
// I used .get here because it's getting by ID
members.forEach(member => {
sleep(5000).then(() => member.send("some message"));
});
})
The above code will get all the GuildMembers and loop through every one of them, "sleeping" for 5 seconds (if the sleep parameter is milliseconds) and send the member a DM

Unable to find a role by its name

I'm trying to make a command where you can set up an LFG role (LFG = looking for game).
Right now, I need the bot to find a role by its name, but it doesn't work. I have no idea why, I have tried many other thing like finding the role by its ID or structuring the code differently but nothing... Heres is the code:
collector1.on('collect', () => {
// Si l'utilisateur a cliqué sur 1️⃣ LFG
message.reactions.removeAll();
const embed1 = new MessageEmbed()
.setTitle(
`**--------------------LFG role configuration--------------------**`,
)
.addField(
`You clicked on 1️⃣`,
`Send in the next 30 the name of the new LFG role.`,
true,
)
.addField(
`Missclicked?`,
`Wait 30 seconds for the bot to send a timeout message and try again.`,
true,
);
let filter = (m) => m.author.id === message.author.id;
m.edit(embed1).then(() => {
message.channel
.awaitMessages(filter, {
max: 1,
time: 30000,
errors: ['time'],
})
.then((message) => {
message.reactions.removeAll();
message = message.first();
let role = message.guild.roles.cache.find((r) => r.name === message);
message.channel.send(`Alright, The new lfg role is ${role}!`);
})
.catch((collected) => {
message.channel.send('Timeout.');
});
});
});
Also, I have a second problem which is the bot doesn't remove all the reactions.
message is not a string- it's a Message object. I think you meant message.content
let role = message.guild.roles.cache.find((r) => r.name === message.content);
Also, I have a second problem which is the bot doesn't remove all the reactions
Maybe you meant m.reactions.removeAll()?
To find a role by name you can simply use
message.guild.roles.find(role => role.name === "Rolename");

Detect Reaction on discord.js

I am making a discord bot, and I have a problem with a waifu command.
With this command the bot sends an embed, and I want to detect when someone reacts to this embed. I tried this code but nothing happens.
const Discord = require("discord.js");
const axios = require("axios")
const Client = new Discord.Client;
module.exports = {
name : 'waifu',
description : "waifu command",
execute(message, args) {
Client.on('messageReactionAdd', (reaction, user) => {
message.channel.send("Reacted")
})
axios.get("https://api.waifu.pics/sfw/waifu")
.then((res) => {
let wembed = new Discord.MessageEmbed()
.setTitle(`Voici votre waifu ${message.author.username}`)
.setImage(res.data.url)
message.channel.send(wembed)
.then(function (message) {
message.react("❤")
Client.on('messageReactionAdd', (reaction, user) => {
console.log("reacted")
})
})
})
.catch((err) => {
console.error("ERR: ", err)
})
}
}
You can't add a messageReactionAdd listener inside your message listener. You can however set up a reaction collector using createReactionCollector for example, like in my example below:
const { MessageEmbed } = require('discord.js');
const axios = require('axios')
module.exports = {
name: 'waifu',
description: 'waifu command',
execute(message, args) {
axios
.get('https://api.waifu.pics/sfw/waifu')
.then((res) => {
let wembed = new MessageEmbed()
.setTitle(`Voici votre waifu ${message.author.username}`)
.setImage(res.data.url);
// make sure you use a different var name here
// like msg instead of message
message.channel.send(wembed).then((msg) => {
msg.react('❤');
// set up a filter to only collect reactions with the ❤ emoji
let filter = (reaction, user) => reaction.emoji.name === '❤';
let collector = msg.createReactionCollector(filter);
collector.on('collect', (reaction, user) => {
// in case you want to do something when someone reacts with ❤
console.log('reaction added');
});
collector.on('remove', (reaction, user) => {
// in case you want to do something when someone removes their reaction
console.log('reaction removed');
});
});
})
.catch((err) => {
console.error('ERR: ', err);
});
},
};
A couple things here.
First, you defined message twice; once as the message initiating the command that originated from your command handler, and once as the message the bot sent. You need to rename one of these or else various unexpected issues may arise.
Second, you should never define your client twice. Instead, you should reuse the client. To do this, you can either export it to your command handler the same way you export message and args, or you can access it via <message>.client and use it the same way you did here.

Bot reacting to emojis

So, I got my code and it works just as I want it to. the message pops up changes everything, it's perfect.
Now I want to add so the bot knows when I react to its message and then does something else. What I mean is: bot sends a message with reacts, and whenever some user clicks the reaction something happens, but I have no idea how to do that.
I've tried many things like if (reaction.emoji.name === ':bomb:'), but multiple errors popped out and I didn't know how to fix that. Here's the code:
const Discord = require('discord.js');
const { prefix, token } = require('./config.json');
var lastbuffer;
lastbuffer = 0;
const client = new Discord.Client();
client.once('ready', () => {
console.log('Ready!');
});
client.on('message', message => {
if(message.content.startsWith(`${prefix}start`)){
message.delete()
setInterval(function(){
lastbuffer++;
const Buffer = new Discord.MessageEmbed()
.setColor('#8300FF')
.setTitle("**It's time to check buffers!**")
.setDescription("**It's been **" + "`" + lastbuffer + " Hour" + "`" + "** since last buffercheck, <#&675688526460878848>**." + " **Check now!**")
.setThumbnail('https://art.pixilart.com/88534e2f28b65a4.png')
.setFooter('WEEEEEWOOOOO')
.setTimestamp();
client.channels.cache.get("700296799482675230").send(Buffer).then(msg => {
msg.react('✅');
msg.react('💣');
msg.delete({timeout: 4000})
});
}, 5000)
}
});
client.login(token);
You are going to have to use a ReactionCollector using the createReactionCollector() method.
You can follow this guide to under ReactionCollectors better
You need to use a reaction collector.
client.channels.cache.get("700296799482675230").send(Buffer).then(async msg => {
// I'm using await here so the emojis react in the right order
await msg.react('✅');
await msg.react('💣');
msg.awaitReactions(
// Discord.js v12:
/* ({emoji}, user) => ['✅', '💣'].includes(emoji.name) && user.id === message.author.id,
{max: 1, time: 4000, errors: ['time']} */
// Discord.js v13:
{
// only collect the emojis from the message author
filter: ({emoji}, user) => ['✅', '💣'].includes(emoji.name) && user.id === message.author.id,
// stop collecting when 1 reaction has been collected or throw an error after 4 seconds
max: 1,
time: 4000,
errors: ['time']
}
)
.then(collected => {
const reaction = collected.first()
// do something
})
.catch(() => {
// I'm assuming you want to delete the message if the user didn't react in time
msg.delete()
})
What this code does:
Sends the embed (Buffer) to the channel with the id 700296799482675230
Reacts with the ✅ and then the 💣 emojis on the message with the embed
Waits for a ✅ or 💣 reaction from the author of the original message
If the user reacts within 4 seconds, runs the // do something part
If the user does not react within 4 seconds, deletes the message with the embed

How do you add a role based on a message reaction?

Is there anything remotely wrong with this code?
no errors pop up and there isn't a reaction once the bot sends the messages.
any help would be appreciated, thank you in advance!
const a = msg.guild.roles.get('666712822985654322'); //Verified User
// the role constants are in the same chronological order as below.
const filter = (reaction,user) => ['668236468384169986'].includes(reaction.emoji.name);
const embed = new Discord.RichEmbed()
.setColor(0x00FF00)
.setTitle('Rules')
.setDescription(`
In order to gain access to the rest of the server you must read and abide by these rules:
By reacting with :white_check_mark: you agree to these rules
Roles:
:white_check_mark: ${a.toString()}`)
.setThumbnail(msg.author.avatarURL)
.addField('Rule #1:You do not talk about fight club', 'Second Rule: You do not TALK about fight club')
.setFooter("Use \'!command list\' to get aquainted with Peb 3000");
msg.channel.send(embed).then(async message => {
await message.react('668236468384169986'); //white check mark
message.awaitReaction(filter, {})
.then(collected =>{
const reaction = collected.first();
switch(reaction.emoji.name) {
case('\:white_check_mark:'):
message.member.addRole(a).catch(err => {
console.log(err);
return message.channel.send(`Error adding you to this role: **${err.message}**`);
});
message.channel.send(`You have been added to the **${a.name}** role!`).then(m => m.delete(3000));
break;
}
}).catch(collected => {
return msg.collected.send(`I couldn't add you to this role!`)
})
});
I'd recommend reading both An Idiot's Guide - Using Emojis as well as Discord.js Guide - Reactions, as your current approach for Unicode emojis won't work.
In your case, :white_check_mark: should be ✅ or an equivalent.
The collected options will triggeret when collector end collect, you no provide any options to stop collector, so its will never happen.
The 1 way to give member role on react follow this code. But when bot restart, you need again use this command and create collector.
const roleToAdd = msg.guild.roles.get('666712822985654322'); //Verified Role
if(!roleToAdd) return
let embed = new Discord.RichEmbed()
.setColor(0x00FF00)
.setTitle('Rules')
.setDescription(`
In order to gain access to the rest of the server you must read and abide by these rules:
By reacting with :white_check_mark: you agree to these rules
Roles:
:white_check_mark: ${a.toString()}`)
.setThumbnail(msg.author.avatarURL)
.addField('Rule #1:You do not talk about fight club', 'Second Rule: You do not TALK about fight club')
.setFooter("Use \'!command list\' to get aquainted with Peb 3000");
msg.channel.send(embed).then(message => {
const filter = (reaction, user) => reaction.emoji.name === '✅' && user.id === msg.author.id && reaction.message.id = message.id
const collector = message.createReactionCollector(filter, {});
collector.on('collect', r => {
if(r.emoji.name === '✅') {
let member = message.guild.members.get(reaction.users.last().id)
member.addRole(roleToAdd)
.then( member => {
message.channel.send(`You have been added to the **${roleToAdd.name}** role!`).then(m => m.delete(3000));
})
.catch(console.error)
}
})
collector.on('end', collected => console.log(`Collected ${collected.size} items`));
})
The way number 2 its listen reactionadd event. After restart its will work.
bot.on('messageReactionAdd', (reaction, user) => {
if(reaction.message.id === 'YOUR MESSAGE ID' && reaction.emoji.name === 'youreactionname') {
let meber = reaction.message.guild.members.get(user.id)
member.addRole('yourRole')
}
.catch(console.error)
});

Categories

Resources