How do you turn on and off a bots reactions? - bots

I've been working on a bot (using js) that reacts to every message sent and I've been trying to give it on and off commands. Is there a way to have on and off commands when it comes to reactions from bots?
This is what I have:
top:
var emojissetting = 0
on / off (tried with changing the variable to 0 or 1):
if (msg === prefix + 'START'){
emojisetting = 1;
message.channel.send("Snoopy is now reading the chat. :book:");
}
if (msg === prefix + 'STOP'){
emojisetting = 0;
message.channel.send("Snoopy has stopped reading the chat. :blue_book:");
}
bottom:
bot.on('message', message => {
if(emojisetting = 0){
if (message) {
return;
}
}
if(emojisetting = 1){
if (message) {
emojirandom = emojisnop[Math.floor(Math.random() * emojisnop.length)]
message.react(emojirandom)
}
}
});

First of all, if your bot is going to run in more than one server, it's probably gonna get API banned because you would exceed the rate-limit of adding reactions to messages, if I remember correctly the limit is probably 1 reaction every 0.25 seconds.
Anyway, what you did is correct but it will only work for one server, because 'emojisetting' is a global variable of the bot. You could create an array of objects to store that setting for each server, for example:
emojisettings = [
{
guildID = 5365657435245;
enabled = true;
}
guildID = 3543265356345;
enabled = false;
}
]
In this example we stored two settings for two different servers, identified by their IDs. Also we used true and false instead of 0/1 because it's more ideal and easy to handle.
Then we will need to let users handle this setting with a command, for example:
if (msg === prefix + 'START' || msg === prefix + 'STOP'){
//Define if enabling or not the bot
let enabling = true;
if(msg === prefix + 'STOP') enabling = false;
//Let's get the guild ID from the msg
let guildID = msg.guild.ID;
//Find the corresponding object in the array of the settings
let index = emojisettings.findIndex(element => element.guildID === guildID);
//If we found the guild setting
if(index >-1){
emojisettings[index].enabled = enabling;
}
//If not found that means the guild isn't stored in the array, so we need to create a new object for it
else{
emojisettings = emojisettings.push({guildID = msg.guild.ID, enabled = enabling});
}
//Reply to the message
if(enabling) message.channel.send("Snoopy is now reading the chat. :book:");
else message.channel.send("Snoopy is not reading the chat. :book:");
}
Keep in mind that this settings will be lost if the bot gets stopped, so if the bot stops running all this settings will be lost, so if you want to keep this setting forever you will need a database, I would suggest you mongoDB, but there are many others and if your bot is not in many servers you can even use a simple json file even if not optimal and risky sometimes.
After that we can simply check if the setting is enabled and if so react to the message:
bot.on('message', message => {
//Check if message was received in a server and not in DMs
if(message.channel.type !== 'text') return;
//Check if the setting is enabled for the server where you received the message
let enabled = emojisettings.find(element => element.guildID === message.guild.ID).enabled;
//If setting is enabled, react to the message
if (enabled) {
emojirandom = emojisnop[Math.floor(Math.random() * emojisnop.length)]
message.react(emojirandom)
}
}
});

Related

Check if a user tag is real discord.js

So I'm making a discord bot with a website. There is a form on the website, it requires you to put your discord tag (user#0000). So what i want to do is when you submit it, it checks if submitted tag is a real user.
Couldn't find anything.
Thanks.
Edit: Here is the post code
const fs = require("fs")
module.exports = (req,res,client) => {
let db = require("./feedback.json")
let d = true
let user = client.users.cache.find(u => u.tag == req.body.user) // What i tried
if (user == undefined) {
d = false
} else {
db.forEach((e) => {
if (e.dcName == req.body.dcName) {
d = false
}
})
}
if (d == true) {
db.push(req.body)
}
fs.writeFile("./webserver/feedback.json", JSON.stringify(db), (err) => {
if (err) throw err
})
if (d == true) {
res.redirect("/feedback?msg=0")
} else {
res.redirect("/feedback?msg=1")
}
}
There's no way to check whether your specified user tag is real unless that user is in the bot cache. You might want to request they put a user ID (and then fetch with client.users.fetch, which will always give you the user object if the user ID is real).
I can't rewrite your code without more information, however, please look into client.users.fetch() so you can make sure that if your user uses the bot, the bot has the user cached.

Trying To Get Bot To Post In Specific Channel Based Off A JSON File

The bot will save the data to the JSON file but I can't figure out how to call that data back so the bot remembers the correct channel to post the message in.
bot.on("message" , (message) =>{
if (message.content.startsWith ("!config enable")) {
editedmessage = message.content.slice (15);
bot.msgs = {
channelName: editedmessage
}
fs.writeFile ("./storage/clanConfig.json", JSON.stringify (bot.msgs, null, 4), (err) => {
if (err) throw err;})
message.channel.send ("channel saved");
}
let channel = (channelName);
let counter = 0;
if(++counter === 10){
bot.channels.cache.get(channelName).send(`10 messages were sent`)
counter = 0;
}
});
I would make these changes.
Move counter outside of the event handler.
You don't want to set the counter to 0 with every message anyway.
Use message.content.split(/\s+/)[2] to get the channel name from the message.
This is lenient against extra spaces ("!config enable bla bla") and only takes the first word after "enable".
Add a function that determines if a new channel name is even valid.
Don't accept user input blindly, always do a validity check.
Use writeFileSync to write the config to disk.
With a file this small there won't be any noticeable delay, and it makes sure that there is no race condition (otherwise the .send() could happen before the config file has finished writing).
Use the config variable bot.msgs.channelName directly when you need it, instead of maintaining a separate channelName variable.
Code:
bot.msgs = {
channelName: "last channel from config file, otherwise default value"
};
var counter = 0;
bot.on("message", message => {
if (message.content.startsWith("!config enable")) {
let newChannel = message.content.split(/\s+/)[2];
if (isValid(newChannel)) {
bot.msgs.channelName = newChannel;
fs.writeFileSync("./storage/clanConfig.json", JSON.stringify(bot.msgs, null, 4)
message.channel.send("channel saved");
counter = 0;
}
}
if (++counter === 10) {
bot.channels.cache.get(bot.msgs.channelName).send(`10 messages were sent to {bot.msgs.channelName}.`)
counter = 0;
}
});

Discord.js sending message upon voice channel joining is not working

so what my bot is meant to do is that when someone joins a certain channel, it will send a message to log channel "SomeGuy123 joined the channel!". So I was constructing it for like an hour, and now I resolved all the errors, but it doesnt say anything, nor it doesnt give any errors. I can send the whole code if you want. Here is just the part about sending the message upon joining:
client.on("voiceStateUpdate", (oldState, newState) => {
const newUserChannel = newState.ChannelID;
const oldUserChannel = oldState.ChannelID
const textChannel = newState.guild.channels.cache.get('715141269395079208')
if(newUserChannel === '715141827644358707') {
textChannel.send(`${newState.user.username} (${newState.id}) has joined the channel`)
} else if (oldUserChannel === '715141827644358707' && newUserChannel !== '715141827644358707') {
textChannel.send(`${newState.user.username} (${newState.id}) has left the channel`)
}
})
Thank you in advance.
https://discord.js.org/#/docs/main/stable/class/Client?scrollTo=e-voiceStateUpdate
https://discord.js.org/#/docs/main/stable/class/VoiceState
<VoiceState>.ChannelID is undefined, its <VoiceState>.channelID, javascript is not pascal case except in classes

How can i check if a person has went online, offline, etc. in discord.js?

const channel = client.channels.cache.get('<channelid>');
const person1 = client.users.cache.get('<userid>');
const person = client.users.cache.get('<userid>');
client.on('message', message =>{
client.on('presenceUpdate', () =>{
if(person1.user.presence.status === 'dnd' || person1.user.presence.status === 'online'){
channelforstatus.send('person1 is now online');
}
else if(peron1.user.presence.status === 'offline' || person1.user.presence.status === 'idle'){
channel.send('person1 is offline');
}
client.on('message', message => {
client.on('presenceUpdate', () =>{
if(person.user.presence.status === 'dnd' || person.user.presence.status === 'online'){
channel.send('person is now on');
}
else if(person.user.presence.status === 'offline' || person.user.presence.status === 'idle'){
channel.send('person is now off');
}
});
});
});
});
This is what I've tried and the .send() the function is not working. I've looked everywhere and found nothing that could help me with this problem. I just need it so it checks every time if a specific person has went online, offline, etc. And sends a message to a specific channel.
First of all, one rule to abide with is that event listeners should always be in top level of your code and never nested. (Else you are subject to memory leaks and other issues like duplicated and unintended code execution).
client.on("message", (message) => {
...
});
client.on('presenceUpdate', (oldPresence, newPresence) => {
...
});
Now when looking at presenceUpdate event and Presence object documentation you can manage to see if a status evolved like that :
client.on('presenceUpdate', (oldPresence, newPresence) => {
let member = newPresence.member;
// User id of the user you're tracking status.
if (member.id === '<userId>') {
if (oldPresence.status !== newPresence.status) {
// Your specific channel to send a message in.
let channel = member.guild.channels.cache.get('<channelId>');
// You can also use member.guild.channels.resolve('<channelId>');
let text = "";
if (newPresence.status === "online") {
text = "Our special member is online!";
} else if (newPresence.status === "offline") {
text = "Oh no! Our special member is offline.";
}
// etc...
channel.send(text);
}
}
});
Be aware that presenceUpdate event is fire by EACH guild the user and bot share, meaning that if user status change and share two guilds with your bot, this code will be executed twice.
In case you use presence but get offline instead of the user being online I spent like.. 2 whole days looking for the answer so ill share it anywayz
Common mistakes on presence.status is forgetting to check these stuff at the the developer applications. which i have no idea what means
A screenshot
now on your message (command handler) function.. if you have one
message.guild.members.cache.get('userId').presence.status
or
${message.author.username} is now ${message.author.presence.status};
Ill update this if I found out how to presence all the users instead of just one
my first post... I SHALL REMEMBER THIS xD
To get the presence, you can use user.presence, which will get all kinds of info about the user, but you only need user.presence.clientStatus.desktop
so your code would, for example, be
bot.on('presenceUpdate', () =>{
let person1 = bot.users.cache.get('USERID')
console.log(person1.presence.clientStatus.desktop)
if(person1.presence.clientStatus.desktop === 'dnd' || person1.presence.clientStatus.desktop === 'online'){
channel.send('person1 is now online');
}
else if(person1.presence.clientStatus.desktop === 'offline' || person1.presence.clientStatus.desktop === 'idle'){
channel.send('person1 is offline');
}
})

How to limit command to the server where the command was called?

I created a Discord bot which has some commands that generates riddels and riddels answers.
I discovered a bug that was triggered: if I invite the bot in two different servers and try to run one command in one of this two servers, it will run it in the second one and that's actually bad because I wanted each server to be independent. If the command is run on one server, it shouldn't be run on another.
I tried to save server id and tried to write some conditions with it but didn't work.
on the first server:
on the second server:
I want to make the command works per server not get shared in all of them
let CommandRunned = CommandRunnedWithSpace.trim().toLowerCase()
let argsWithOutSpace = receivedMess.content.toLowerCase().slice(mentionNumber).trim().split(' ');
const cmd = argsWithOutSpace.shift().toLowerCase();
const args = argsWithOutSpace.join(' ');
if (CommandRunned === 'startriddle') {
if (RiddleMap.get('check') === true) {
receivedMess.reply("Riddle Already Started (can't start two riddels at the sametime)");
} else {
currentCluesArray = [];
clueI = 0;
getRndNum = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
let randomNum = getRndNum(0, RiddlesApi.Riddles.length - 1)
RiddlesApi.Riddles.filter((Riddel) => {
if (Riddel.id === randomNum) {
RiddleMessage = Riddel.Riddle
answer = Riddel.Answer
clues = Riddel.clues
}
})
StartRiddleModuel.startRiddle(receivedMess, RiddleMessage);
RiddleMap.set('check', true);
}
}
if (cmd === 'answer') {
if (answerCooldown.has(receivedMess.author.id)) {
receivedMess.delete();
receivedMess.reply('You have to wait ' + answercdseconds + ' seconds befor answering again')
} else {
if (RiddleMap.get('check') === true) {
if (args === answer) {
RiddleMap.set('check', false);
receivedMess.reply("Correct :hushed: ")
receivedMess.react('✅');
} else if (args === '') {
receivedMess.reply("Well you didnt enter anything.How you want me to know your answer then.")
receivedMess.react('💢');
} else {
receivedMess.reply("That wasnt the right answer try again :smirk: ")
receivedMess.react('❌');
}
answerCooldown.add(receivedMess.author.id);
} else {
receivedMess.reply("No Riddles did started");
}
}
}
Without having complete code it's pretty hard to point out which lines of code should be changed. However, the general idea is to compare guild ID each time you run the command. Under Message object, you can find guild ID like this:
msg.guild.id
When user requests a riddle, you should save the guild ID and then compare it with the ID from the answer command.
However, there's another solution which could better fit your needs: awaitMessages method from TextChannel class.
The most important benefit is that it's used per channel, so you don't need to add any logic like the one I described above.
Example from documentation should help you to properly incorporate it in your script (comments and minor changes mine):
// Here you need to create a filter to 'catch' only desired messages
// E.g. filter I use to check if my bot was pinged is as below
// message.mentions.users.some(mention => mention.id === client.user.id)
const filter = m => m.content.includes('answer');
// Here you specify max: 1 as you want to catch and respond to each message
channel.awaitMessages(filter, { max: 1, time: 60000, errors: ['time'] })
.then(collected => console.log('If correct command was sent, program enters here'))
.catch(collected => console.log('In case errors or timeout, put commands here'));
The only thing missing is to loop awaitMessages (so that it doesn't end after one message is found) and set separate timer so you know when the time for answering ends.

Resources