"mute" command gives random output - javascript

if(command === "mute"){
const target = message.mentions.users.first();
if (target) {
if (!message.member.hasPermission("ADMINISTRATOR")) {
return message.reply("Unauthorized");
}
let muted = client.settings.get(message.guild.id, 'mute')
let muteRole = message.guild.roles.cache.find(role => role.name === muted);
let memberTarget = message.guild.members.cache.get(target.id);
let rolelist = memberTarget.roles.cache
.map(r => r)
if (!args[1]) {
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> has been muted`);
return
}
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> will be muted for ${ms(ms(args[1]))}`);
setTimeout(function () {
memberTarget.roles.add(rolelist);
memberTarget.roles.remove(muteRole);
}, ms(args[1]));
} else {
message.channel.send('User not found!');
}
So I have this mute command which removes all your roles, gives you the muteRole, when time is up, it gives back your previous roles and removes the muteRole. The problem I'm having is that it sometimes removes all your roles and doesn't give you the muteRole, other times it doesn't remove the muteRole when the time is up. Sometimes it removes all your roles and doesn't give you the
muteRole and when the times up it doesn't give your roles back...
Basically the outcome is always random. So my question is how do I make it consistent?

The methods .add() and .remove() return a Promise so you should try using await / .then().
If you do it with this, the next function or .then() will not be executed until the promise is completely processed.
Example:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'));
Now you're nearly finished. The last thing you need is the .catch() block, because if the code above fails / throws an error you should catch that:
.catch(err => console.log(`An error occured: ${err}`))
Final result:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'))
.catch(err => console.log(`An error occured: ${err}`));
References
GuildMemberRoleManager (Discord.js)
Promises
Handle promises
Await

Related

(Discord Bot) Get message that follows command prefix

I'm trying to reference the previous message sent by a client using discord.js
How would I go about getting the last message sent?
client.on("messageCreate", (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 === 'set-reminder'){
channelName = client.channels.cache.find(channel => channel.name === "spam");
message.channel.send("Command Works");
channelName.messages.fetch({ limit: 1 }).then(messages => {
// find "command works" message (previous message from client)
let lastMessage = messages.first();
console.log(lastMessage.content);
})
}
})```
The message.channel.send function is async
You can await the send function or use .then
The send function also returns the message, you don't need a query to get it
await
let message = await message.channel.send("Command Works");
console.log(message.content);
then
message.channel.send("Command Works").then((message) => {
console.log(message.content);
});
(async means not-synchronous : you have to wait to get its result)

How to make a reaction disappear after a certain amount of reactions?

I want to make a poll command, where I use the command, and when the reaction reaches a certain amount of reactions it (the reaction) gets deleted. That would be useful to see who wins if you understand me.
That's what I'm using right now for only adding a reaction.
bot.on('message', msg => {
if(msg.content === "memes"){
msg.react("🤏🏾")
}
})
You can use reaction collectors to collect user reactions on a message. The collector has options like maxUsers that you can use to set the maximum number of users to react. Once it's reached, the collector.on('end') fires, so you can use it to get the number of users reacted, etc.
You can remove the reactions using message.reactions.removeAll();
Check the snippet below:
if (message.content === 'memes') {
const EMOJI = '🤏🏾';
const filter = (reaction, user) =>
reaction.emoji.name === EMOJI && !user.bot;
const collector = message.createReactionCollector(filter, {
// optional, the maximum time in ms the collector collects reactions
time: 10000,
// maximum number of users to react
// it includes the bot's reaction too
maxUsers: 3,
});
message.react(EMOJI);
collector.on('collect', (reaction, user) => {
// it fires every time someone reacts to the message
console.log('collected', reaction);
});
collector.on('end', async (collected, reason) => {
const reaction = collected.get(EMOJI);
if (!reaction) {
return message.channel.send('Oops, there were no reactions');
}
// it includes the bot too
const allUsers = await reaction.users.fetch();
// collection of users who reacted to the message, bot removed
const users = allUsers.filter((user) => user != client.user);
message.channel.send(
`Poll has ended because of ${reason}. Received ${users.size} reactions.`
);
message.channel.send(
`Users reacted: ${users.array().join(', ')}`
);
// remove reactions
message.reactions.removeAll();
});
}
If you want to have an array of emojis, you can use an EMOJIS array instead:
if (message.content === 'memes') {
const EMOJIS = ['🤏🏾', '😱'];
const filter = (reaction, user) =>
EMOJIS.includes(reaction.emoji.name) && !user.bot;
const collector = message.createReactionCollector(filter, {
time: 10000,
maxUsers: 3,
});
EMOJIS.forEach((emoji) => message.react(emoji));
collector.on('collect', (reaction, user) => {
// it fires every time someone reacts to the message
});
collector.on('end', async (collected, reason) => {
if (!collected.size) {
message.reactions.removeAll();
return message.channel.send('Oops, there were no reactions');
}
// you can use the collected reactions any way you want
console.log(collected);
// remove reactions
message.reactions.removeAll();
});
}

Adding a global timer for tmi.js integrated discord.js

I'm trying to do a discord bot that listens to multiple twitch chat for commands, then run them on discord, using both tmi.js and discord.js. Currently it is working, but I can't seem to add a global cooldown on the commands itself to prevent spamming. At first I've tried adding a cd timer to each command, but I'm unable to get it working, hence the decision to try to make a global cd but still to no avail. Am I doing something wrongly?
twitch.on('message', (channel, tags, message, self) => {
if(!message.startsWith(prefix) || self) return;
const args = (message.slice(prefix.length).trim().split(/ +/));
const commandName = args.shift().toLowerCase();
if (!twitch.commands.has(commandName)) return;
const command = twitch.commands.get(commandName);
}
try {
command.execute(bot, botChannel, vcChannel, isReady);
} catch (error){
console.error(error);
}
});
just to update, I basically took a leaflet from async await functions here: https://stackoverflow.com/a/54772517/14637034
Then, I modified the code as such:
const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => {
setTimeout(() => {
cb();
resolve();
}, timeout);
});
const doStuffAsync = async () => {
await setAsyncTimeout(() => {
isReady = true;
console.log(isReady);
}, 10000);};
twitch.on('message', (channel, tags, message, self) => {
if(!message.startsWith(prefix) || self) return;
const args = (message.slice(prefix.length).trim().split(/ +/));
const commandName = args.shift().toLowerCase();
if (!twitch.commands.has(commandName)) return;
if (isReady){
const command = twitch.commands.get(commandName);
isReady = false;
try {
command.execute(bot, botChannel, vcChannel);
} catch (error){
console.error(error);
}
doStuffAsync();
}
});
Seemed to work for now, as 10s is a long enough time for bot to leave discord properly without causing timeout. I'm still open to better suggestions for optimization though!

Discord.js add role by reacting to message

The following code wont work as I expected. I want a User to react with a checkmark and then log something in the console. Instead of that the bot activates the function by itself and then the function never gets called again.
client.once('ready', () => {
console.log('Ready!');
const exampleEmbed = <unimportant>;
client.channels.cache.get("771041812638728235").send(exampleEmbed).then((message) => {
message.react('✅');
message.createReactionCollector(r => r.emoji.name == '✅')
.on('collect', r => {
console.log("nice");
});
});
});
It might be because the reaction collector is created before the message.react() method finishes executing, causing it to activate on itself. You could either use async/await or a then() callback to make sure the reaction has finished, or simply add a line making sure the user is not a bot in your collector filter.
// method 1:
client.channels.cache
.get('771041812638728235')
.send(exampleEmbed)
.then(async (message) => {
// ^^^^^
// make sure the function is async
await message.react('✅');
message
.createReactionCollector((r) => r.emoji.name == '✅')
.on('collect', (r) => {
console.log('nice');
});
});
// method 2:
client.channels.cache
.get('771041812638728235')
.send(exampleEmbed)
.then(message) => {
// .then() callback
message.react('✅').then(() =>
message
.createReactionCollector((r) => r.emoji.name == '✅')
.on('collect', (r) => {
console.log('nice');
}););
});
// method 3:
client.channels.cache
.get('771041812638728235')
.send(exampleEmbed)
.then((message) => {
message.react('✅');
message
// make sure the user who reacted isn't a bot
.createReactionCollector((r, u) => r.emoji.name == '✅' && !user.bot)
.on('collect', (r) => {
console.log('nice');
});
});

Discord.js Bot giveaway command : .array() is not a function

I am trying to make a Discord.js giveaway command that send an embed, save it to the variable embedSent, collect the reactions after the TimeOut with the reactions.get() method, convert them to an array with array() then filter them with .filter(). The problem is at the Array() step where I keep getting the error TypeError: peopleReactedBot.array is not a function.
Here is the part of my code :
embedSent.react("🎉");
setTimeout(function () {
try {
const peopleReactedBot = embedSent.reactions.cache.get("🎉").users.fetch();
const peopleReacted = peopleReactedBot.array().filter(u => u.id !== client.author.id);
message.channel.send(peopleReacted)
} catch(e) {
return message.channel.send("An error has occured : `"+e+"`");
}
}, time);
I use Discord.js v12.
user.fetch() returns a Promise, so you might want to switch to an asynchronous function and await for the promise to complete, like so :
setTimeout(async () => {
try {
const peopleReactedBot = await embedSent.reactions.cache.get("🎉").users.fetch();
const peopleReacted = peopleReactedBot.array().filter(u => u.id !== client.author.id);
message.channel.send(peopleReacted)
} catch(e) {
return message.channel.send("An error has occurred : `"+e+"`");
}
}, time);

Categories