Discord.js - Updating a MessageEmbed in the following code - node.js

So, I have (this is only part of it) the following code, but I can't figure out this whole updating a sent embed thing...
The coding is all working if I send a new embed every time, but I don't want to clutter the channel; thus attempting to update the first embed.
Code:
const filter = m => m.author.id === message.author.id;
let hangembedStart = new Discord.MessageEmbed()
.setDescription("Let's get started!")
.setColor('#0099ff')
.setThumbnail(sicon)
.addField('Word:', asterisc)
message.channel.send(hangembedStart);
const collector = message.channel.createMessageCollector(filter, {
maxMatches: 9,
time: 30000
});
collector.on('collect', m => {
if (m.content === 'cancel') {
inProgress = false;
delete guessed;
collector.stop();
return;
}
if (lowChar === text) {
message.channel.send(`Congratulations, you guessed the word!`);
inProgress = false;
delete guessed;
collector.stop();
return;
}
let hits = checkChar(lowChar, text);
if (hits === 0) {
let hangembedGuess = new Discord.MessageEmbed()
.setDescription("Hangman - The Game - In progress")
.setColor('#0099ff')
.setThumbnail(sicon)
.addField('Word:', reveal)
.addField('Guessed:', guessed.join(" "))
message.channel.send(hangembedGuess);
} else if (hits > 0) {
let hangembedGuess = new Discord.MessageEmbed()
.setDescription("Hangman - The Game - In progress")
.setColor('#0099ff')
.setThumbnail(sicon)
.addField('Word:', reveal)
.addField('Guessed:', guessed.join(" "))
message.channel.send(hangembedGuess);
}
});
collector.on('end', collected => {
message.channel.send(`Game ended, word was: ${text}!`);
inProgress = false;
delete guessed;
//collector.stop();
});
How the ... can I update the first embed in this code, instead of sending a new one each time?
I tried using message.edit() but that triggers:
UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot edit a message authored by another user
I've googled, read, searched, tried, tested just about everything I've come across, but can't wrap my head around this one...

Got it sorted!!
Added the following line:
const hangmanMessage = await message.channel.send(hangembedStart);
//above
const filter = m => m.author.id === message.author.id;
Then changed the following line(s):
message.channel.send(hangembedGuess);
//to this
hangmanMessage.edit(hangembedGuess);
Now it updates the first embed, instead of sending a new one each time :D

Related

How to make a button work infinitely and not only once when pressed discord.js

I just learnt how to make a button in discord.js, and I even learnt how to make a cookie counter, but the only problem is that I can only click it once. If I do it again, it doesn't work. My code is:
let button = new ButtonBuilder()
.setCustomId('cookie')
.setLabel('0')
.setStyle(ButtonStyle.Primary)
let clicker = new ActionRowBuilder()
.addComponents(
button,
);
console.log(button);
console.log(button.data.label);
for the components and
const filter = i => i.customId === 'cookie' && i.user.id === `${interaction.user.id}`;
const collector = interaction.channel.createMessageComponentCollector({ filter, time: 15000 });
collector.on('collect', async i => {
if (i.customId === 'cookie'){
// cookieCount(guildid, messageid);
const newCookie = Number(button.data.label + 1);
clicker = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('cookie')
.setLabel(`${newCookie}`)
.setStyle(ButtonStyle.Primary),
);
await i.update({ embeds: [embed], components: [clicker]})
}
});
for the update.
Btw I'm relatively new to discord.js.
The time option is how long the collector will run in milliseconds. If you remove that option, it should go forever.
const collector = interaction.channel.createMessageComponentCollector({ filter });
If you are wanting to have a button that works indefinitely and through restarts of the bot you can create an event called interactionCreate and then you can filter that to run only when it's a button interaction.
From that you can check the name of the clicked button then run the correct code for that button. Using the event allows all buttons that the bot has sent to be used.
import { Client, Interaction, InteractionType } from 'discord.js';
client.on('interactionCreate', interaction => {
if(interaction.type == InteractionType.MessageComponent) {
if(interaction.customId == 'button_1') {
// Your code....
}
}
});

Why does my Discord bot keep repeating when it runs this command?

This is the code used, there is nothing (I think) that's causing it to repeat, matter of fact I added something so it stops repeating but it didn't do anything at all.
client.on('message', e =>{
if(e.member.roles.cache.has('12345678901')){
if(!e.content.startsWith(p) || e.author.bot) return;
console.log('successfully unmuted')
var ar = e.content.slice(p.length).split(/ +/)
var cmd = ar.shift().toLowerCase();
if(cmd === 'b'){
console.log('succesfully banned')
var member = e.mentions.users.first();
if(member){
var membertarget = e.guild.members.cache.get(member.id)
membertarget.ban();
var sbbed = new discord.MessageEmbed()
.setColor('GREEN')
.setTitle('success!')
.setDescription(`<#${membertarget.user.id}> has been successfully banned!`)
}else {
var bbed = new discord.MessageEmbed()
.setColor('RED')
.setTitle('invalid user!')
.setDescription('ban failed because there was not a valid member mentioned :(')
e.channel.send({ embeds: [bbed] })
}
}
} else {
var rolefb = new discord.MessageEmbed()
.setColor('RED')
.setTitle('failed!')
.setDescription('sorry! you dont have a high enough role to use this command, but this can change!')
if (e.author.bot) return;
e.channel.send({embeds: [rolefb]})
}
})
This code is supposed to just ban somebody but it keeps repeating itself whenever it fails:
Code:
client.on('message', e =>{
if (e.author.bot) return
if(e.member.roles.cache.has('960191891473829929')){
I have edited the code, but it still doesn't work.
Your code in the message event listener runs whenever a message is posted in your server so the bot sending the message will also be counted. So all you have to do is add an if statement in the start to check whether the author of the message was a bot:
if (message.author.bot) return
Try to add this statement to your code before if(e.member.roles.cache.has('12345678901')){
if (e.author == client.user) return;
Also, change the if(e.member.roles.cache.has('12345678901')){ to else if (e.member.roles.cache.has('12345678901')){.
I would recommend restructuring the entire code and make it into a command handler, though.

TypeError: Cannot read property ' ' error with discord.js

So I have figured out how to set up a simple database with discord.js in a users.json file and my !start cmnd works to create the users database, but when me and my cousin tried the !daily cmnds, the cmnd seems to be fine but I get this error: TypeError: Cannot read property 'a number' of undefined. I believe the number refers to my user number or database number (a number means an actual long number, not "a number").
Also here is the code that goes along with this that is in my index.js file:
var UserJSON = JSON.parse(Fs.readFileSync('./DB/users.json'));
UserJSON[message.author.id] = {
bal: 0,
lastclaim: 0,
}
Fs.writeFileSync('./DB/users.json', JSON.stringify(UserJSON));
let SuccessEmbed = new Discord.MessageEmbed();
SuccessEmbed.setTitle("**SUCCESS**");
SuccessEmbed.setDescription("You have joined the economy! type !help to get started");
message.channel.send(SuccessEmbed);
return;
}
if (args[0] == "daily") {
let userJSON = JSON.parse(Fs.readFileSync('./DB/users.json'));
if (Math.floor(new Date().getTime() - UserJSON[message.author.id].lastclaim) / (1000 * 60 * 60 * 24) < 1) {
let WarningEmbed = new Discord.MessageEmbed()
WarningEmbed.setTitle("**ERROR**");
WarningEmbed.setDescription("You have claimed today already");
message.channel.send(WarningEmbed);
return;
}
UserJSON[message.author.id].bal += 500;
UserJSON[message.author.id].lastclaim = new Date().getTime();
Fs.writeFileSync('./DB/users.json', JSON.stringify(UserJSON));
let SuccessEmbed = new Discord.MessageEmbed();
SuccessEmbed.setTitle("**SUCCESS**");
SuccessEmbed.setDescription("You have claimed a daily reward of 500 coins!");
message.channel.send(SuccessEmbed);
}
}
})
Also to specify, the ./DB/users.json refers to the folder DB for database and users.json is the file that stores the databases.
Here is what the user.json file looks like:
{"*my database number*":{"bal":0,"lastclaim":0},"*my cousin's database number*":{"bal":0,"lastclaim":0}}
Is there any code I need to add into my index.js file to stop this from happening. If possible, answer as soon as possible so I can get this error worked out. Thank You!
Edit: I somehow figured this out by re-doing it and this is the finished product if anyone wants to start an economy bot:
const Discord = require("discord.js");
const client = new Discord.Client();
const Fs = require("fs");
const prefix = "!";
client.on("ready", () => {
console.log("Ready!");
});
client.on("message", async (message) => {
if(message.content.startsWith(prefix)) {
var args = message.content.substr(prefix.length)
.toLowerCase()
.split(" ");
if (args[0] == "start") {
let UserJSON = JSON.parse(Fs.readFileSync("./DB/users.json"));
UserJSON[message.author.id] = {
bal: 0,
lastclaim: 0,
}
Fs.writeFileSync("./DB/users.json", JSON.stringify(UserJSON));
let SuccessEmbed = new Discord.MessageEmbed();
SuccessEmbed.setTitle("**SUCCESS**");
SuccessEmbed.setDescription("You have joined the economy! type !help to get started");
message.channel.send(SuccessEmbed);
return;
}
if (args[0] == "daily") {
let UserJSON = JSON.parse(Fs.readFileSync("./DB/users.json"));
if (Math.floor(new Date().getTime() - UserJSON[message.author.id].lastclaim) / (1000 * 60 * 60 * 24) < 1) {
let WarningEmbed = new Discord.MessageEmbed()
WarningEmbed.setTitle("**ERROR**");
WarningEmbed.setDescription("You have claimed today already");
message.channel.send(WarningEmbed);
return;
}
UserJSON[message.author.id].bal += 500;
UserJSON[message.author.id].lastclaim = new Date().getTime();
Fs.writeFileSync("./DB/users.json", JSON.stringify(UserJSON));
let SuccessEmbed = new Discord.MessageEmbed();
SuccessEmbed.setTitle("**SUCCESS**");
SuccessEmbed.setDescription("You have claimed a daily reward of 500 discord coins!");
message.channel.send(SuccessEmbed);
}
}
})
client.login('your token');
also remember to make a DB folder with an users.json file
I realized that the problem with the code is that instead of vars, it needed to be let before the UserJSON, so the line of code should read:
let UserJSON = JSON.parse(Fs.readFileSync("./DB/users.json"));
UserJSON[message.author.id] = {
bal: 0,
lastclaim: 0,
}

How can I resolve this problem (node.js, discord.js)

if (!args[1]) return message.channel.send('You need to specify a person!')
if (!args[2]) return message.channel.send('Please specify a time for how long the ban council will last.')
var tim = args[2]
const sweden = message.mentions.users.first()
message.react('👍').then(() => message.react('👎'))
const mappo = ['👍', '👎']
if (!args[1]) return message.channel.send('Please specify a person!')
if(message.guild){ //this will check if the command is being called from a server
const embad = new Discord.MessageEmbed()
.setTitle('Ban Council')
.addField('The Convicted:', `${sweden.tag}`)
.addField('Rules:', 'Vote on whether the convicted is guilty or not with the prompted reactions. The ban will end automatically in 5 seconds.')
message.channel.send(embad)
setTimeout(function(){
if(sweden){
const lyft = message.guild.member(sweden)
if(lyft){
if(message.reactions.cache.map(r => `${'👍'} ${r.users.cache.size}`)[0] > message.reactions.cache.map(r => `${'👍'} ${r.users.cache.size}`)[1]){
lyft.ban({ ression: 'Majority has exiled you from server. '}).then(() => {
message.reply(`The user ${december.tag} was banned as a result of a majority vote.`)
})
} else {
message.channel.send('The ban was cancelled.')
}
}else{
message.reply('The user is not in this server.')
}
}else{
message.reply('You need to specify a person!')
}
}, tim)
} else {
message.channel.send('Banning does not work here!')
}
It sends the "Ban cancelled" before it actually has the chance to take input. I've tried collectors, and it doesn't work because of the max: part, how can I resolve this problem? (Also it returns no errors)
This is in a case. (appending onto what feedback I got)
Firstly you should beautify your code before you post on stackoverflow, you could have removed the break keyword and just explain it was inside of a switch case
The reason it does not work is because you are checking the message's reaction, and not the embed that you send, so to fix this you need to assign a variable to message.channel.send(embad), but this is a promise so you need to await it, which requires an async function
lastly awaitReactions and createReactionCollector are probably better options,
So here's the new code:
(async () => {
if (!args[1]) return message.channel.send('You need to specify a person!');
if (!args[2]) return message.channel.send('Please specify a time for how long the ban council will last.')
if (!message.guild) return message.channel.send('Banning does not work here');
var tim = args[2]
const sweden = message.mentions.member.first()
const mappo = ['👍', '👎']
message.react('👍').then(() => message.react('👎'))
const embad = new Discord.MessageEmbed()
.setTitle('Ban Council')
.addField('The Convicted:', `${sweden.tag}`)
.addField('Rules:', 'Vote on whether the convicted is guilty or not with the prompted reactions. The ban will end automatically in 5 seconds.')
const embedMessage = await message.channel.send(embad);
setTimeout(function () {
if (!sweden) return message.reply('You need to mention a person');
const filter = (reaction) => mappo.includes(reaction.emoji.name);
embad.awaitReactions(filter, { time: 5000 })
.then(collection => {
//not the most optimal way to do it
const emoji1 = collection.find(e => e.emoji.name === '👍');
const emoji2 = collection.find(e => e.emoji.name === '👎');
//both default to 0
const upvotes = emoji1 && emoji1.users.size || 0;
const downvotes = emoji2 && emoji2.users.size || 0;
if (upvotes > downvotes) {
lyft.ban({ reason: 'Majority has exiled you from server. ' })
.then(() => message.reply(`The user ${december.tag} was banned as a result of a majority vote.`));
} else {
message.channel.send('The ban was cancelled.');
}
})
.catch(console.error);
}, tim);
})();
It's been around 8 months since I made this post, and I found the answer, and an even more effective way to do it. I won't post the entire code, as it's pretty long and not very neat. However, this is a much more effective way of counting reactions.
My Original Code was:
const upvotes = message.reactions.cache.map(r => ${'👍'} ${r.users.cache.size})[0]
const downvotes = message.reactions.cache.map(r => ${'👎'} ${r.users.cache.size})[1]
It doesn't work very well either.
const [upvoteReaction, downvoteReaction] = message.reactions.cache.first(2);
const upvotes = upvoteReaction.users.cache.size;
const downvotes = downvoteReaction.users.cache.size;
It takes the number of reactions from the first two reactions on the message. Seeing as how the only reactions are thumbs up and thumbs down, it will get the numbers from both of them. From there, you can just compare the two.

How to use db.subtract after time using glitch.com, discord.js

Basically im trying to run this code
const Discord = require('discord.js');
const fs = require('fs');
const db = require("quick.db");
module.exports.run = async (bot, message, args) => {
let user = message.member;
let vic = db.get(`vic_${user.id}`);
console.log("Activating auto start command!");
let intro = new Discord.RichEmbed()
.setTitle("You have dosed on vicodin and you are now immune to all shots")
.setColor('#00cc00');
let nopill = new Discord.RichEmbed()
.setTitle("You do not own this drug")
.addField("Error", "<:bluepill:713790607901982780> --- **You do not own any `Vicodin Pills`, please purchase off of the black market** --- <:bluepill:713790607901982780>")
.setFooter("Must own first")
let pill = new Discord.RichEmbed()
.setTitle("You have already dosed")
.addField("Error", "<:bluepill:713790607901982780> --- **You have already dosed on `Vicodin Pills`, please wait until the effect wear off to dose again** --- <:bluepill:713790607901982780>")
.setFooter("Already dosed")
if (args[0].startsWith("testing")) {
if (vic === null) return message.channel.send(nopill)
} else if (args[0].startsWith("vicodin")) {
if (vic === 0) return message.channel.send(nopill)
if (vic === 2) return message.channel.send(pill)
message.channel.send(intro)
db.set(`vic_${user.id}`, 2)
console.log(`${user} just dosed vicodine`);
setTimeout(() => {
console.log(`this is a test by zuc`)
db.set(`vic_${user.id}`, 0)
}, 1800000);
}
}
What it dose is when a user run the Dose command it makes them dose on the pill, im trying to make the pill/dose remove after a certain amount of time using db.subtract, since im using glitch.com to do this, the setTimeout isnt doing what i want it to after that time.
Change the timeout code to:
setTimeout(() => {
console.log(`this is a test by zuc`)
db.delete(`vic_${user.id}`);
db.add(`vic_${user.id}`, 0);
}, 1800000);

Resources