I am trying to make a discord bot for a database or something similar. The point of the bot should be to store information. I want to store the number of podcasts I have listened to, how many hours they add up to, and what are they, all this sort of information. I thought a discord bot should do; I know of quite a few that store such information. I am really a beginner to this, and any information would help me out. one of the functions that this bot should have is a dropdown menu; I came across this problem where when I call the menu function, the bot crashes, and I get this type of error:
throw new Error(
^
Error: TOO_MANY_CHARACTERS_OF_MENU_DESCRIPTION: The maximum length of MessageMenuOption.description is 100 characters, received 54 instead.
This is my code of the dropdown menu:
client.on('message', async message =>{
if(!message.guild || message.author.bot) return;
if(message.content == prefix + 'menu'){
//first option
let = option1 = new MessageMenuOption()
.setLabel('Podcast')
.setValue('Podcast')
.setDescription('If you have listened to a podcast today, post it here!')
.setDefault()
//second option
let = option2 = new MessageMenuOption()
.setLabel('Tutorial')
.setValue('Tutorial')
.setDescription('If you have watched a tutorial today, post it here!')
.setDefault()
//third option
let = option3 = new MessageMenuOption()
.setLabel('Documentary/General_knowledge')
.setValue('Documentary/General_knowledge')
.setDescription('If you have watched a documentary today, post it here!')
.setDefault()
let selection = new MessageMenu()
.setID('Selection')
.setMaxValues(1)
.setMinValues(1)
.setPlaceholder('Select something!')
.addOption(option1)
.addOption(option2)
.addOption(option3)
let embed = new Discord.MessageEmbed()
.setColor('BLURPLE').setTitle('What have you learned today?')
let menuMsg = await message.channel.send(embed, selection)
function menu_selection(menu) {
switch(values[0]) {
case 'Podcast':
menu.reply.send("Nice!, hope this podcast was useful!")
break;
case 'Tutorial':
menu.reply.send("Nice!, hope this tutorial was useful!")
break;
case 'Documentary/General_knowledge':
menu.reply.send("Nice!, hope this video was useful!")
break;
}
}
client.on('clickMenu', (menu) => {
if(menu.message.id == menuMsg.id) {
if(menu.clicker.user.id == message.author.id) menu_selection(menu)
else menu.reply.send("Type ```.menu``` to get access to this menu!")
}
})
}
})
Related
So basically I have a question now. And I made a logs for showing people who join/leave/move between the voice channel and now I want to expand the function of it. So I've decided to show if somebody disconnect a user from a channel. But I have a problem while fetching audit logs into this. If I disconnected somebody once and someone leave on its own after, it still shows up that I disconnected the users. So I am thinking is it possible to fix this issue by fetching a specific time of audit log but I don't know how to do this. Here is a part of code which shows the disconnect and leave part.
else if (newUserChannel === null) {
// User leaves a voice channel
const fetchedLogs = await (oldMember, newMember).guild.fetchAuditLogs({
limit: 1,
type: 'MEMBER_DISCONNECT',
});
const disconnectLog = fetchedLogs.entries.first();
// console.log(disconnectLog)
const { executor } = disconnectLog;
const Disconnected = new Discord.MessageEmbed()
.setColor('#555555')
.setAuthor(`${executor.username}#${executor.discriminator}`, executor.displayAvatarURL())
.setDescription(`<#${executor.id}> **has disconnected user** <#${oldMember.id}>`)
.setTimestamp()
.setFooter(F1, F2)
const VCLeave = new Discord.MessageEmbed()
.setColor('#55FFFF')
.setAuthor(`${oldMember.member.user.tag}`, oldMember.member.user.displayAvatarURL({ dynamic: true }))
.setDescription(`<#${oldMember.id}> **has left voice channel \`${oldUserChannel.name}\`**`)
.setTimestamp()
.setFooter(F1, F2)
LogsChannel.send(Disconnected);
LogsChannel.send(VCLeave);
}
Comparing the entry's time is a good idea to fix this issue, in my opinion.
disconnectLog has a property called createdAt (Date) and createdTimestamp (Number).
This is how you get the entry's time and compare it later to the current date.
const Diff = Math.abs((new Date().getTime() - disconnectLog.createdAt.getTime()) / 1000);
if (Diff <= 5) {console.log("The entry was created less than 5 seconds ago, so the user was disconnected by an admin.")};
I planned to create a discord server with bots. There are quite a lot (6 in total) and are just supposed to be fictional characters with some background story. I'm quite new and all of that is way too complicated for me to code myself, therefor I ask for your help! I just want to have a nice server for my friends and I with enjoyable bots and all of these desperate hours of trying to get some useful code is driving me nuts..
I only managed to get one bot to do stuff, using the prefix "-".
It can change it's status (watching, listening, playing) and the name of the thing he's doing.
I'm not quite sure why streaming doesn't work or if that's possible in general but it would be really cool if it would.
My status code: (1st Problem)
client.once('ready', () => {
console.log('Bot is ready!');
if (config.activity.streaming == true) {
client.user.setActivity(config.activity.game, {type: 'WATCHING'}); //STREAMING, PLAYING, LISTENING
} else {
client.user.setActivity(config.activity.game, {url: 'https://twitch.tv/usrname'});
client.user.setStatus('idle'); //dnd, idle, online, invisible
}
});
config.json
"activity": {
"streaming": true,
"game": "Whatevergame"
}
}
As I said, streaming is not working for some reason and the status (idle, dnd..) is also not working.
2nd Problem
If I try to add other bots with the login, it will log both bots on, but only one of them will work, what's actually pretty logical since the commands are all made for only one bot. So I'm trying to figure out how to get them all packed into the main file.
3rd Problem
I used the try - catch function to execute commands, which I pre- set up, and if theres none, it sends an error message. See for yourself:
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();
try {
client.commands.get(command).execute(message, args);
}
catch {
message.channel.send("I don't know that, sorry.");
}
});
So everytime I type another command, from which I do not want the bot to respond to, it will respond with "I don't know[...]" It would be sufficient to just set up another prefix for the "other command" to fix that problem so the bot knows that for every prefix starting with a.e "-", it has to send an error message if that command is not existing. But for other prefixes, a.e "?", it's supposed to execute the other command/s.
4th Problem
My (current) last problems are the welcome messages. My code:
index.js
const welcome = require("./welcome");
welcome (client)
welcome.js
module.exports = (client) => {
const channelId = '766761508427530250' // welcome channel
const targetChannelId = '766731745960919052' //rules and info
client.on('guildMemberAdd', (member) => {
console.log(member)
const message = `New user <#${member.id}> joined the server. Please read through ${member.guild.channels.cache.get(targetChannelId).toString()} to gain full access to the server!`
const channel = member.guild.channels.cache.get(channelId)
channel.send(message)
})
}
The code is working perfectly fine, however it would be way more exciting with a little more variety. I'm trying to get multiple welcome messages that get randomly chosen by the bot.. I thought about a Mathfloor as an approach but I'm not quite sure how that would work..
Thank you for reading through my text and I hope that I will soon be able to enjoy the server with my guys!
Cheers!
First problem
I'm not sure why ClientUser.setActivity() and ClientUser.setStatus is not working. In the STREAMING example, it might be because you didn't specify the type of activity. Either way, there's an easier way to what you're doing, which is ClientUser.setPresence(). This method is kind of like a combination of the other two.
client.once('ready', () => {
console.log('Bot is ready!');
config.activity.streaming
? client.user.setPresence({
activity: { name: config.activity.game, type: 'WATCHING' },
})
: client.user.setPresence({
activity: {
name: config.activity.game,
type: 'STREAMING',
url: 'https://twitch.tv/usrname',
},
status: 'idle', // note: the idle icon is overwritten by the STREAMING icon, so this won't do much
});
});
Second Problem
It's pretty hard to make multiple bots, both duplicates of each other, in one file. I would recommend just using a lot of Array.prototype.forEach() loops to apply all events and such to both clients.
[1, 2, 3].forEach((num) =>
console.log(`The element I'm currently iterating a function through is ${num}`)
);
// example main file
const { Client, Collection } = require('discord.js');
const [roseClient, sunflowerClient] = [new Client(), new Client()];
// adding properties:
[roseClient, sunflowerClient].forEach((client) => client.commands = new Collection())
// events
[roseClient, sunflowerClient].forEach((client) =>
client.on('message', (message) => {
// ...
});
);
// login
roseClient.login('token1');
sunflowerClient.login('token2');
Third problem
Again, forEach() loops save the day (❁´◡`❁). This time, however, you should actually use Array.prototype.every(), which will return true if every element of an array passes the given test.
Basically, if we were to use a normal forEach() loop, then even if one of the prefixes found the match, the other wouldn't and the error message would always be sent out. So instead we'll use every() to only send out an error message if both prefixes find no match.
// what if we ony wanted the error message if *every* number was 3
[1, 2, 3].forEach((num) => {
if (num === 3) console.error('Error message');
});
console.log('--------------------');
// now it will only send if all numbers were three (they're not)
if ([1, 2, 3].every((num) => num === 3))
console.error('Error message');
client.on('message', (message) => {
if (['-', '?'].every((prefix) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
try {
// it did not pass the test (the test being finding no match), and the error message should not be displayed
return false;
client.commands.get(command).execute(message, args);
} catch {
// it did pass the test (by finding no match). if the next test is failed too, the error message should be displayed
return true;
message.channel.send("I don't know that, sorry.");
}
});
});
Fourth Problem
You're on the right track! Math.floor() is definitely the right way to get a random element from an array.
function chooseFood() {
// make an array
const foods = ['eggs', 'waffles', 'cereal', "nothing (●'◡'●)", 'yogurt'];
// produce a random integer from 0 to the length of the array
const index = Math.floor(Math.random() * foods.length);
// find the food at that index
console.log(`Today I will eat ${foods[index]}`);
};
<button onClick="chooseFood()">Choose What to Eat</button>
module.exports = (client) => {
client.on('guildMemberAdd', (member) => {
console.log(member);
const welcomes = [
`Welcome ${member}!`,
`Woah! Didn't see you there ${member}; welcome to the server!`,
`${member} enjoy your stay at ${member.guild}!`,
];
const message = `${
welcomes[Math.floor(Math.random() * welcomes.length)]
} Please read through ${member.guild.channels.cache.get(
'766731745960919052'
)} to gain full access to the server!`;
member.guild.channels.cache.get('766761508427530250').send(message);
});
};
That was a mouthful (╯°□°)╯︵ ┻━┻
I'm building a simple poll bot for Discord in JavaScript, right now I'm trying to implement max number of reactions per user to a message.
For example, suppose we have the following options for a poll question:
The Question?
Option A
Option B
Option C
Option D
Option E
Each "option" is a reaction to the message given from the bot, I want to make sure that a user cannot react to more than 3 of those options.
My train of thought was to make a messageReactionAdd listener and
then when the user reacted for the 4th time, remove the last
reaction, sending him a message like "You've already voted 3 times,
please remove a reaction to vote again".
Still, I'm stuck trying to navigate through the objects to find the
total reaction count per user I can find the total reaction count
per emoji but that's not what I need.
Could someone give me some insight on this?
EDIT
Code used to send messages:
Embed = new Discord.MessageEmbed()
.setColor(0x6666ff)
.setTitle(question)
.setDescription(optionsList);
message.channel.send(Embed).then(messageReaction => {
for (var i = 0; i < options.length; i++){
messageReaction.react(emojiAlphabet[i][0]);
}
message.delete().catch(console.error);
});
Try this:
const {Collection} = require('discord.js')
// the messages that users can only react 3 times with
const polls = new Set()
// Collection<Message, Collection<User, number>>: stores how many times a user has reacted on a message
const reactionCount = new Collection()
// when you send a poll add the message the bot sent to the set:
polls.add(message)
client.on('messageReactionAdd', (reaction, user) => {
// edit: so that this does not run when the bot reacts
if (user.id === client.user.id) return
const {message} = reaction
// only do the following if the message is one of the polls
if (polls.has(message)) {
// if message hasn't been added to collection add it
if (!reactionCount.get(message)) reactionCount.set(message, new Collection())
// reaction counts for this message
const userCount = reactionCount.get(message)
// add 1 to the user's reaction count
userCount.set(user, (userCount.get(user) || 0) + 1)
if (userCount.get(user) > 3) {
reaction.users.remove(user)
// <#!id> mentions the user (using their nickname if they have one)
message.channel.send(`<#!${user.id}>, you've already voted 3 times, please remove a reaction to vote again.`)
}
}
})
client.on('messageReactionRemove', (reaction, user) => {
// edit: so that this does not run when the bot reacts
if (user.id === client.user.id) return
const {message} = reaction
const userCount = reactionCount.get(message)
// subtract 1 from user's reaction count
if (polls.has(message)) userCount.set(user, reactionCount.get(message).get(user) - 1)
})
first time poster here. Sorry if this is an obvious fix, but I'm very new to the world of nodejs and programming in general.
I'm currently trying to create a Discord bot that allows any user to initiate a "love it or hate it" vote with the !vote command. Once the vote is initiated, the bot sends out a message announcing the vote, then reacts to its own message with a heart and skull emoji to denote the love and hate options, respectively. This part is working as intended.
After a set amount of time passes (a very short period), the bot should tally the emoji reactions and figure out if there are more hearts, more skulls, or an equal number of both. Depending on the outcome, it will send another message announcing the outcome of the vote. This part is not working as intended.
As it stands, I can get the bot to respond to my !vote command by sending a new message in the chat and reacting to that message with the proper emojis. The bot will also wait for the set amount of time and announce the outcome of the vote. However, it always announces that the vote was neutral, regardless of which emoji I clicked on before the timer expired (making sure I didn't click both, of course).
My code to compare the number of votes clearly is not functioning as intended. However, after spending hours trying out different fixes, I can't figure out the solution for the life of me and it's driving me crazy. Is there a part of this that's incorrect? And if so, how do I fix it?
Many thanks to anyone who can chime in. After lurking for a while and finding countless fixes in other people's questions in the past, I thought I'd finally turn to the lovely people at Stack Overflow for help. You guys rock!
const Discord = require('discord.js');
const bot = new Discord.Client();
bot.on('message', function(message){
if(message.content.toLowerCase().startsWith('!vote'))
{
var heartCount = 0;
var skullCount = 0;
message.channel.send(
"The vote begins! Do we love it or hate it?")
.then(async function (message){
try {
await message.react("❤️")
await message.react("💀")
}
catch (error) {
console.error('One of the emojis failed to react.');
}
})
const filter = (reaction, user) => {
return ["❤️","💀"].includes(reaction.emoji.name) && user.id === message.author.id };
message.awaitReactions(filter, {time: 10000})
.then(collected => {
for (var i = 0; i < collected.length; i++){
if (collected[i].emoji.name === "❤️")
{heartCount++;}
else if (collected[i].emoji.name === "💀")
{skullCount++;}
};
if (heartCount > skullCount){
message.channel.send("We love it!");
}
else if (heartCount < skullCount){
message.channel.send("We hate it.");
}
else {
message.channel.send("We're neutral about it.");
}
})
}
});
bot.login(process.env.BOT_TOKEN);
The fist problem its user.id === message.author.id so only message author can react. message.channel.send return a promise of new message, so you can use then => for message react. Better use action collector on collect for get count and then when collector ends send a message.
const Discord = require('discord.js');
const bot = new Discord.Client();
bot.on('message', function(message){
var heartCount = 0;
var skullCount = 0;
if(message.content.toLowerCase().startsWith('!vote')) {
message.channel.send('The vote begins! Do we love it or hate it?').then(msg => {
msg.react(`❤️`).then(() => msg.react('💀'));
const filter = (reaction, user) => {
return [`❤️`, '💀'].includes(reaction.emoji.name);
};
const collector = msg.createReactionCollector(filter, {time: 10000});
collector.on('collect', (reaction, reactionCollector) => {
if (reaction.emoji.name === `❤️`) {
heartCount+=1
} else if (reaction.emoji.name === `💀`) {
skullCount+=1
}
});
collector.on('end', (reaction, reactionCollector) => {
if (heartCount > skullCount){
message.channel.send("We love it!");
}
else if (heartCount < skullCount){
message.channel.send("We hate it.");
}
else {
message.channel.send("We're neutral about it.");
}
});
})
}
})
I'm trying to find out if its possible to get the time/information of users last activity retrospectively using discord.js
Say I have something like
client.guilds.find('id', 'SERVER ID').fetchMembers().then(members => {
const role = members.roles.find('name', 'Newbies')
role.members.forEach(member => {
console.log(member.user.lastMessage) // null
})
})
Unless the member has posted, since the client is listening, the lastMessage is always null.
Is there a way to find the last activity? or a workaround, like a query to return all the users messages, which I can then take the most recent one from?
Effectively I want to know what date/time the user last posted so we can monitor non-contributing accounts.
Thanks
After looking thought the documentation I didn't find something neither so I came up with a manual search function.
Basically, it will scan every channels until finding a message from X user, or the end of the messages in the channel. It then compare the last messages of the users from every channels and print the last one.
It can be very long if the user hasn't write since a long time. Of course, you have to check lastMessage before trying this.
I would add a time limit maybe. Because if you have thousand of messages, the function will run eternally.
You can stop the function if the last message found is in the accepted time to not be kick/do whatever.
I made the search stop if the first message found in the pack of fetched messaged is older than the ban limit, however, if the first message is not older, remember that it means for the other, so we still need to check them (it can be avoided by checking the last message of the pack as well).
async function fetchMessageUser(chan, id, res) {
let option = {};
if (typeof res !== 'undefined'){
option = {before: res.id};
}
return await chan.fetchMessages(option)
.then(async msgs => {
if (msgs.size === 0){
return {continue: false, found: false};
};
if ((Date.now() - (msgs.first().createdTimestamp)) > 86400000 ) { // 1 day
return {continue: false, found: false};
}
let msgByAuthor = msgs.find(msg => {
return msg.author.id === id;
});
if (msgByAuthor === null){
return {continue: true, id: msgs.last().id};
} else {
return {continue: false, found: true, timestamp: msgByAuthor.createdTimestamp};
}
})
.catch(err => console.log('ERR>>', err));
}
client.on('message', async (msg) => {
let timestamp = [];
for (let [id, chan] of msg.guild.channels){
if (chan.type !== 'text'){ continue; }
let id = '587692527826763788'; // id of the user, here a non verified account
let res;
do {
res = await fetchMessageUser(chan, id, res);
} while(res.continue);
if (res.found) {
timestamp.push(res.timestamp);
}
}
console.log(timestamp);
let first = timestamp.sort((a,b) => (b-a))[0];
console.log(new Date(first));
});
A better variant would be to run it for an array of users, checking all 50 last messages from every channel, and associating each users with his most recent messages if he wrote one, and doing this until all the messages in all the channels are too old to avoid a kick/whatever. And then do something for all the users who don't have an associated messages.
I think what you need is one of Discord's built in features, namely: pruning. This feature will grab inactive members and lets you kick them. Luckily, discord.js has an API call for it and even lets you get the number of members first without actually kicking them by setting the dry parameter to true. The feature will also allow you to specify the amount of days a user has to be inactive.
Have a look at the docs: https://discord.js.org/#/docs/main/stable/class/Guild?scrollTo=pruneMembers
Hope that helps out!