I'm trying to do a bot to verify members on a special guild.
They need to send "verify" into a specific channel, then they have to answer several questions. However, the collector doesn't seem to work properly. Nothing shows in console.
client.on('messageCreate', async message => {
if(message.author.id === botId) return;
if(message.channel.type != "dm") {
if(message.channelId == verifyChannelId && message.content == "verify") {
let appChannel = (await message.author.send('Hello, I\'m gonna asking you a few questions..')).channel;
appChannel.send('Are you on european server? (Yes/No)');
const filter = m => (appChannel.type === "dm");
const collector = appChannel.createMessageCollector({ filter, time: 15000 });
collector.on('collect', m => {
console.log(`Collected ${m.content}`);
});
collector.on('end', collected => {
console.log(`Collected ${collected.size} items`);
});
message.delete({ timeout: 1000 });
} else {
message.delete({ timeout: 1000 });
}
}
});
There are a couple of errors with this. First, you're using v13 of discord.js and as MrMythical mentioned in their comment, channel types are now uppercase, so checking if(message.channel.type != "dm") won't do much as it will always return true. Checking if (appChannel.type === "dm") won't work either as it will always returns false. And I'm not even sure why you'd check if the appChannel's type is DM anyway, it can't be anything else. Your filter should probably check if the answer is yes or no.
Another error is that you haven't enabled the DIRECT_MESSAGES intents. Without it, your createMessageCollector won't work in DM channels. Check out the working code below:
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.DIRECT_MESSAGES,
],
});
// ...
client.on('messageCreate', async (message) => {
// it could be if (message.author.bot) return;
if (message.author.id === botId) return;
if (message.channel.type === 'DM') return;
if (message.channelId !== verifyChannelId) return;
if (message.content.toLowerCase() === 'verify') {
let sentMessage = await message.author.send(
"Hello, I'm gonna asking you a few questions..",
);
let dmChannel = sentMessage.channel;
dmChannel.send('Are you on a European server? (Yes/No)');
const filter = (m) => ['yes', 'no'].includes(m.content.toLowerCase());
const collector = dmChannel.createMessageCollector({
filter,
// max: 1,
time: 15000,
});
collector.on('collect', (m) => {
console.log(`Collected ${m.content}`);
});
collector.on('end', (collected) => {
console.log(`Collected ${collected.size} items`);
});
}
// delete the message even if it wasn't "verify"
message.delete({ timeout: 1000 });
});
Related
I'm pretty trash at coding so I need a little bit of help. I'm trying to code my discord bot to delete someone's messages for one minute after they click a react emoji. It sounds simple but for my tiny pea brain, it's not. This is what I have got so far. It deletes all messages from different users and guilds it's in, forever. I want it so it only delete messages in one channel for one minute.
client.once('message', async userMessage => {
if (userMessage.content.startsWith(''))
{
botMessage = await userMessage.channel.send('Who here likes goats?')
await botMessage.react("👍")
await botMessage.react("👎")
const filter = (reaction, user) => {
return (
["👍", "👎"].includes(reaction.emoji.name) && user.id === userMessage.author.id
);
};
botMessage
.awaitReactions(filter, { max: 1, time: 60000, errors: ["time"] })
.then((collected) => {
const reaction = collected.first();
if (reaction.emoji.name === "👎") {
userMessage.channel.send(`${userMessage.author}, how dare you. I guess no on here likes me. Hmmm, because of that I shall now eat all your messages! BAAAAAHAHAHHAHAHA!`)
setTimeout(() => {
client.on("message", async msg => {
if (author.msg.content.startsWith("")) {
userMessage.channel = await msg.delete();
}
});
}, 2000);
} else {
userMessage.reply("Thanks!");
}
})
.catch((_collected) => {
userMessage.channel.send("Hehe")
});
}
});
Btw, the code is in discord.js!
Your problem is this chunk of code
setTimeout(() => {
client.on("message", async msg => {
if (author.msg.content.startsWith("")) {
userMessage.channel = await msg.delete();
}
});
}, 2000);
This is not how you use events.
A) Your message event is nested within another which could cause memory leaks.
B) To get the content you need to use msg.content, author.msg Is not a thing.
C) I assume your intention here: msg.content.startsWith("") is to always fire the if statement, in that case why not do if (true).
Here's how I would do it:
Create a Set in the namespace which will hold id's of users who's messages should be deleted
const toDelete = new Set();
If they react with a 👎 add them to the set.
if (reaction.emoji.name === "👎") {
userMessage.channel.send('Your message here');
if (!toDelete.has(userMessage.author.id)) {
toDelete.add(userMessage.author.id);
}
}
On each message event check if the author of the message has their id in the set, If so delete their message
client.once('message', async userMessage => {
if (toDelete.has(userMessage.author.id)) {
return userMessage.delete()
.catch(console.error);
}
if (userMessage.content.startsWith('')) {
// Rest of your code
I think your problem in understanding how everything works.
I took everything from discord.js documentation.
Type reaction command to see how it works.
const Discord = require("discord.js");
require("dotenv").config();
const TOKEN = process.env.TOKEN||"YOUR TOKEN";
const PREFIX = process.env.PREFIX||"YOUR PREFIX";
const bot = new Discord.Client();
bot.on("ready", async function(e) {
console.log("Loaded!");
})
bot.on("message", async function(message) {
if (message.author.bot) return;
if (!message.content.startsWith(PREFIX)) return;
let args = message.content.slice(PREFIX.length).trim().split(/\s+/);
let command = args.splice(0, 1).toString().toLowerCase();
if (command == "reaction") {
message.delete();
let msg = await message.channel.send("Click on the reaction");
await msg.react("👍");
await msg.react("👎");
let filter = (reaction, user) => {
return ["👍", "👎"].includes(reaction.emoji.name) && user.id == message.author.id;
}
msg.awaitReactions(filter, {max: 1, time: 10000, errors: ["time"]}).then(collected => {
let reaction = collected.first();
if (reaction.emoji.name == "👎") {
return message.channel.send("downvote");
}
return message.channel.send("upvote");
}).catch(e => {
message.channel.send("user didn't vote");
})
}
})
bot.login(TOKEN);
My Discord bot (Discord.js) isn't replying correctly to the command.
when it asks "How is your day", and a user responds, the output is only from the "good response". So like, when you say that you had a bad day it'll respond: "That's great to hear!".
here is the code for my discord bot:
module.exports= {
name: 'hello',
description: "Greet the Best Maid from Genshin!",
execute(message, args){
let filter = m => m.author.id === message.author.id;
message.channel.send("Hi! I am Noelle, maid of the Knights of Favonius. It's a pleasure to meet you, how was your day?"). then(() => {
message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] })
.then(message => {
message = message.first()
if (message.content == 'Good', 'Great', 'Ok', 'Fine') {
const replies = ["That's GREAT to hear!", "Ohhh, how exciting!", "I hope that your days will continue to be wonderful"]
message.replytext = Math.floor((Math.random()*replies.length) + 0);
message.channel.send(replies[message.replytext]);
} else if (message.content == 'Bad', 'Tired', 'Depressing') {
const replies = ["That's really unfortunate", "Oh my, it will get better", "I hope that your days will become fantastic onwards", "Would you like some tea to get rid off some stress?"]
message.replytext = Math.floor((Math.random()*replies.length) + 0);
message.channel.send(replies[message.replytext]);
} else {
message.channel.send("I don't seem to understand")
}
})
.catch(collected => {
message.channel.send("It seems like you don't want to talk about it. I am free anytime if you want to talk about it. ^-^");
});
})
}
}
here below is the "main.js"
const Discord = require('discord.js');
const client = new Discord.Client();
const prefix = '>'
const fs = require('fs');
client.commands = new Discord.Collection();
const commandFiles = fs.readdirSync('./commands/').filter(file => file.endsWith('.js'));
for(const file of commandFiles){
const command = require(`./commands/${file}`);
client.commands.set(command.name, command);
}
client.once('ready', () => {
console.log('How may I be of assistance?');
});
client.on('message', 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 === 'hello'){
client.commands.get('hello').execute(message, args);
} else if (command == ''){
client.commands.get('').execute(message, args);
} else if (command == ''){
client.commands.get('').execute(message, args);
} else if (command == ''){
client.commands.get('').execute(message, args);
} else if (command == ''){
client.commands.get('').execute(message, args);
}
});
client.login(Token)
Your issue is in your if statement.
if (message.content == 'Good', 'Great', 'Ok', 'Fine')
This will always return true, because the comma operator returns the value of the last operand which is the string 'fine'. Strings in Javascript are truthy so this will always return true.
For a quick fix you can use the or statement
if (message.content == 'Good' || message.content == 'Great' || message.content == 'Ok' || message.content == 'Fine')
Or if you want a more extendable option you can store all your good responses in a set, and then check that the set contains the option.
const goodResponses = new Set{['Good', 'Great', 'Ok', 'Fine']};
if(goodResponses.has(message.content){
... }
You will also have to do the same thing for the bad responses.
The , operator in js chains multiple expressions together and returns the value of the last one which in this case is the string 'Fine'. 'Fine' is truthy, so your first if is always true.
To see if the message is contained in a list of words, your can instead use includes with an array:
if (['Good', 'Great', 'Ok', 'Fine'].includes(message.content)) {
}
The above solution is still case sensitive, so you could optionally compare the lowercased message instead:
if (['good', 'great', 'ok', 'fine'].includes(message.content.toLowerCase())) {
}
But it will still only match if the message is "Good" with no other words or characters. You can also make it check each word in the message (removing any non-letter or whitespace characters) to see if any of them match:
// separated into a function so its reusable
const matchesAny = (str, words) => {
const cleanedStringParts = str.toLowerCase().replace(/[^\w\s]/g, '').split(/\s+/g)
return words.some(word => cleanedStringParts.includes(word))
}
const options = ['good', 'great', 'ok', 'fine']
console.log('Good', matchesAny('Good', options))
console.log('good', matchesAny('good', options))
console.log('Good!', matchesAny('Good!', options))
console.log('>>good', matchesAny('>>good', options))
console.log('im doing good!', matchesAny('im doing good!', options))
console.log('bad', matchesAny('bad', options))
console.log('>bad', matchesAny('>bad', options))
console.log('foo', matchesAny('foo', options))
It can be used as
const matchesAny = (str, words) => {
const cleanedStringParts = str.toLowerCase().replace(/[^\w\s]/g, '').split(/\s+/g)
return words.some(word => cleanedStringParts.includes(word))
}
module.exports = {
name: 'hello',
execute: (message, args) {
const filter = m => m.author.id === message.author.id;
message.channel.send("How was your day?").then(() => {
message.channel.awaitMessages(filter, { max: 1, time: 15000, errors: ['time'] })
.then(async messages => {
const response = messages.first()
if (matchesAny(response.content, ['good', 'great'])) {
// reply
} else if (matchesAny(response.content, ['bad', 'tired'])) {
// reply
} else {
await message.channel.send("I don't seem to understand")
}
})
.catch(async collected => {
await message.channel.send("It seems like you don't want to talk about it");
});
})
}
}
I want people to be able to react to a message and then be contacted by the bot with 3 questions. The problem is that it skips all questions for its own and answers it for its own.
I would be happy if you can describe the problem to me well so that it no longer occurs. Here is my code:
client.on('messageReactionAdd', async (reaction, user) => {
if (reaction.message.partial) await reaction.message.fetch();
if (reaction.partial) await reaction.fetch();
if (user.bot) return;
if (reaction.message.channel.id === '809490905236373558') {
if (reaction.emoji.name === '✅') {
const questions = [`Test1`, `Test2`, `Test3`];
const dmChannel = await reaction.message.guild.members.cache
.get(user.id)
.send('**Beantworte die Fragen du keks**');
const collector = dmChannel.channel.createMessageCollector(() => true);
let i = 0;
const res = [];
dmChannel.channel.send(questions[0]);
collector.on('collect', async (msg) => {
if (questions.length == i) return collector.stop('MAX');
const answer = msg.content;
res.push({ question: questions[i], answer });
i++;
if (questions.length == i) return collector.stop('MAX');
else {
dmChannel.channel.send(questions[i]);
}
});
collector.on('end', async (collected, reason) => {
if (reason == 'MAX') {
const data = reaction.message.guild.channels.cache.find(
(ch) =>
ch.name.toLowerCase() == 'apply-final-bewerbungen' &&
ch.type == 'text',
);
await data.send(
`${reaction.message.member || reaction.message.author} (${
reaction.message.author.tag
}) hat eine Bewerbung abgegeben!\n\n${res
.map((d) => `**${d.question}** \n ${d.answer}`)
.join('\n\n')}`,
);
}
});
}
}
});
It sends all questions without waiting because you don't check if the incoming message in your message collector is coming from the member. As the bot sends the first question, there is an incoming message your collector catches (the bot's message) and it sends the next ones till it reaches the end.
You can check if the msg.author is a bot in your collector and stop responding if it is. The following should work:
collector.on('collect', async (msg) => {
if (msg.author.bot) return;
if (questions.length == i) return collector.stop('MAX');
Currently, I am using Discord.js to make a bot.
client.on('message', (message) => {
if (message.content === '$wa') {
message.channel.send({ embed: exampleEmbed }).then((embedMessage) => {
embedMessage.react('❤️');
embedMessage
.awaitReactions(
(filter = (reaction, user) => {
return reaction.emoji.name === '❤️' && user.id === message.author.id;
}),
{ max: 2, time: 60000, errors: ['time'] }
)
.then((collected) => {
const reaction = collected.first();
if (reaction.emoji.name === '❤️') {
message.channel.send(
':sparkling_heart: **Hanno** and **Roronoa Zoro** are now married! :sparkling_heart:'
);
}
});
});
}
});
If I type $wa the bot shows some embed. But the thing is that it automatically adds a heart to the embed. I want that if I click the heart as well (for a total count of 2 hearts) it executes the if statement at the bottom.
I've tried multiple methods but none worked. This is also my first time with Discord.js
You need to account for the bots own reaction. I recommend redoing your filter implementation to something like this.
The key takeaway is that you have to add !user.bot to the filter so that the bot's own reaction is ignored
const filter = (reaction, user) => {
return reaction.emoji.name === "❤️" && user.id === message.author.id && !user.bot
}
embedMessage.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
Please try this:
client.on('message', message => {
if (message.content === '$wa') {
message.channel.send({ embed: exampleEmbed }).then(embedMessage => {
embedMessage.react('❤️');
embedMessage.awaitReactions(filter = (reaction, user) => {
return reaction.emoji.name === '❤️' && user.id === message.author.id;
},
{ max: 1, time: 60000, errors: ['time'] }).then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '❤️') {
message.channel.send(':sparkling_heart: **Hanno** and **Roronoa Zoro** are now married! :sparkling_heart:');
}
}).catch(() => {
// user didn't react with ❤️ in given time (here: 60 secs)
message.channel.send('no reaction in time');
});
});
}
});
I changed the max value to 1 and also added a catch block to catch a UnhandledPromiseRejectionWarning. If you don't do so in the future, it might exit the program with an error. You can of course execute whatever you like when the user didn't react to the embedMessage in time.
I am unable to collect a DM in discord.js when i try to use discord message collector
i have tried changing "message.channel" to message.author but it won't work
const collector = new discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 30000 });
collector.on('collect', message => {
if (message.content == strng) {
message.channel.send(`Successfully Verified User: <#${message.author.id}>`).then(m => {
m.delete(30000)
message.member.addRole('470615991555063808')
}).catch(err => console.log(err));
}
})
expected: user DMs bot with correct string and it verifies them
actual: user has to put the string in the same channel as the user originally said !verify
The user has to put the string in the same channel because you're collecting messages in said channel with message.channel as the first MessageCollector argument.
Instead, what you could do is open a DMChannel with the user and return it with .then() like so:
message.author.createDM().then(dmchannel => {
const collector = new discord.MessageCollector(dmchannel, m => m.author.id === message.author.id, { time: 30000 });
collector.on('collect', m => {
if (m.content == strng) {
message.channel.send(`Successfully Verified User: <#${message.author.id}>`)
.then(m => {
m.delete(30000)
message.member.addRole('470615991555063808')}).catch(err => console.log(err))}
})
})
i have worked it out...
i used
message.author.createDM().then(c => {
var verified = new discord.RichEmbed()
.setTitle("Verification Started")
.addField("**User**", `${message.author}`, false)
.setFooter("Goriko Bot")
.setColor(0xfffb00)
.setTimestamp();
message.guild.channels.get('470619175547830315').send(verified).catch(err => console.log(err));
console.log("DM Created")
c.send(verifyEmbed)
console.log(`Embed Sent to ${message.author.tag}`)
const filter = m => m.content.includes("~");
const collector = c.createMessageCollector(filter, { time: 30000 })
console.log("Collector Created")
collector.on('collect', m => {
console.log('Reply Collected')
if (m.content === strng) {
console.log('Success')
c.send("Successfully Verified")
if (message.channel.type == "dm") return;
message.member.addRole('470615991555063808').catch(err => console.log(err));
var successEmbed = new discord.RichEmbed()
.setTitle("Verification Successful")
.addField("**User**", `${message.author}`, true)
.addField("**String**", `\`\`${strng}\`\``, true)
.setFooter("Goriko Bot")
.setColor(0x00ff00)
.setTimestamp();
message.guild.channels.get('470619175547830315').send(successEmbed).catch(err => console.log(err));
} else {
var failEmbed = new discord.RichEmbed()
.setTitle("Verification Failed")
.addField("**User:**", `${message.author}`, true)
.addField("**Correct Token:**", `${strng}`, true)
.addField("**Token Given:**", `${m.content}`, true)
.setColor(0xff0000)
.setFooter("Goriko Bot")
.setTimestamp();
message.guild.channels.get('470619175547830315').send(failEmbed).catch(err => console.log(err));
m.reply("Invalid Token! Please Try Again")
}
})
})