Related
I've been working to create a Purge Command in JavaScript based off this Purge Command written in TypeScript for reconlx's DJS v13 command handler (I modified a few bits to make all the handlers and whatnot function in DJS v14), however, there are some bugs and a few things I'm losing my mind over.
Firstly, everytime the command is enacted, this little nuisance of a message appears with the success confirmation embeds, and I don't really know how to deal with it.
Secondly, when I purge specifically by user and term, the wrong embed is sent and my bot will purge as normal. According to the source code, it (referring to my bot) should be sending the cleanPurge embed, but it instead sends the userPurge embed. Purging specifically by user works as intended, just with the annoying "thinking" message as an unwanted bonus.
Thirdly, when purging by term, I can only purge if I enact the command right after a message with the specified term. Here's an example (if you don't understand my wording).
// It is okay to purge during these situations
// cat in a hat
// cat in a hat
// cat in a hat
// /purge [amount: 3] {term: cat}
// The command will purge only if it is enacted right after the message with the specific term, however...
// The command won't purge during these situations
// cat in a hat
// cat in a hat
// cat in a hat
// SHITPOST
// /purge [amount: 3] {term: cat}
// The message "SHITPOST" is in-between the last message with the term "cat" and when I enact my command,
// therefore, for some reason, I can't purge any messages with my specified keyword before the message "SHITPOST".
// I can purge messages with the term "cat" AFTER the message "SHITPOST" until another message gets in the way.
// If you have no idea what I mean, a link to my bot's demo is below.
Purging without specifics DOESN'T bring up the "{Bot} is thinking..." message and works as intended.
If you're confused, here's a link to a demo of my bot's bugs
Any questions, please feel free to ask me, and sorry if my wording is shit.
Source code for purge.js
const { EmbedBuilder, ApplicationCommandOptionType, PermissionsBitField } = require("discord.js");
const { Command } = require("reconlx");
const ms = require("ms");
module.exports = new Command({
name: "purge",
description: "Deletes a specified number of messages",
userPermissions: PermissionsBitField.Flags.ManageMessages,
options: [
{
name: "amount",
description: "Number of messages to purge",
type: ApplicationCommandOptionType.Integer,
min_value: 1,
max_value: 100,
required: true,
},
{
name: "user",
description: "Purge this member's messages",
type: ApplicationCommandOptionType.User,
required: false,
},
{
name: "term",
description: "Purge messages with this specific term",
type: ApplicationCommandOptionType.String,
required: false,
},
{
name: "reason",
description: "Reason for purging",
type: ApplicationCommandOptionType.String,
required: false,
},
],
run: async ({ interaction }) => {
const amount = interaction.options.getInteger("amount");
const user = interaction.options.getUser("user");
const term = interaction.options.getString("term");
const reason = interaction.options.getString("reason") || "Unspecified";
const channel = interaction.channel
const messages = await interaction.channel.messages.fetch({
limit: amount + 1,
});
if (user) {
const userMessages = messages.filter((m) => m.author.id === user.id);
const purged = await interaction.channel.bulkDelete(userMessages, true);
const userPurge = new EmbedBuilder()
.setColor("#2F3136")
.setTitle(`🧹 PURGED!`)
.addFields(
{
name: `Cleared ${purged.size} message${
purged.size > 1 ? "s" : ""
}!`,
value: `Any messages from \`${user.tag}\` have been deleted from ${channel}!`
},
{
name: `User`,
value: `\`${user.tag}\``,
inline: true
},
{
name: `Term`,
value: `\`Unspecified\``,
inline: true
},
{
name: `Reason(s)`,
value: `\`${reason}\``,
inline: true
},
)
interaction.channel.send({ embeds: [userPurge] });
} else if (term) {
const filteredTerm = messages.filter((m) =>
m.content.toLowerCase().includes(term)
);
const purged = await interaction.channel.bulkDelete(filteredTerm, true);
const termPurge = new EmbedBuilder()
.setColor("#2F3136")
.setTitle(`🧹 PURGED!`)
.addFields(
{
name: `Cleared ${purged.size} message${
purged.size > 1 ? "s" : ""
}!`,
value: `Any messages with the term ||\`${term}\`|| have been deleted from ${channel}!`
},
{
name: `User`,
value: `\`Unspecified\``,
inline: true
},
{
name: `Term`,
value: `||\`${term}\`||`,
inline: true
},
{
name: `Reason(s)`,
value: `\`${reason}\``,
inline: true
},
)
interaction.channel.send({ embeds: [termPurge] });
} else if (term && user) {
const memberMessages = messages.filter((m) => m.author.id === member.id && m.content.toLowerCase().includes(term));
const purged = await interaction.channel.bulkDelete(memberMessages, true);
const cleanPurge = new EmbedBuilder()
.setColor("#2F3136")
.setTitle(`🧹 PURGED!`)
.addFields(
{
name: `Cleared ${purged.size} message${
purged.size > 1 ? "s" : ""
}!`,
value: `Any messages from \`${user.tag}\` with the term ||\`${term}\`|| have been deleted from ${channel}!`
},
{
name: `User`,
value: `\`${user.tag}\``,
inline: true
},
{
name: `Term`,
value: `||\`${term}\`||`,
inline: true
},
{
name: `Reason(s)`,
value: `\`${reason}\``,
inline: true
},
)
interaction.channel.send({ embeds: [cleanPurge] });
} else {
const purged = await interaction.channel.bulkDelete(messages, true);
const purge = new EmbedBuilder()
.setColor("#2F3136")
.setTitle(`🧹 PURGED!`)
.addFields(
{
name: `Cleared ${purged.size - 1} message${
purged.size > 1 ? "s" : ""
}!`,
value: `The specified number of messages have been deleted from ${channel}!`
},
{
name: `User`,
value: `\`Unspecified\``,
inline: true
},
{
name: `Term`,
value: `\`Unspecified\``,
inline: true
},
{
name: `Reason(s)`,
value: `\`Unspecified\``,
inline: true
},
)
interaction.channel.send({ embeds: [purge] });
}
},
});
Your video is still processing, so I couldn't watch it, but:
In the "cat"/"cat"/"cat"/"shitpost" situation, you'd need amount=4, because you're only fetching N + 1 messages. If you need want your bot to purge N last matching messages even if there are more in between (e.g. in a "a"/"b"/"a"/"b"/"a"/"b" situation where you want to purge all "b"s), you'd need to fetch more messages until you've purged enough. Another "good enough" option might be to fetch e.g. amount * 2 messages and hope it's enough.
In any case, you could start by de-quadriplicating your message filtering and embed building:
{
run: async ({ interaction }) => {
const { options, channel } = interaction;
const amount = options.getInteger("amount");
const user = options.getUser("user");
const term = options.getString("term");
const reason = options.getString("reason") || "Unspecified";
const lastNMessages = await channel.messages.fetch({
limit: amount + 1,
});
const filteredMessages = lastNMessages.filter((message) => {
if (user && message.author.id !== user.id) {
return false;
}
if (term && !message.content.toLowerCase().includes(term)) {
return false;
}
return true;
});
const purged = await channel.bulkDelete(filteredMessages, true);
const title = `Cleared ${purged.size} message${purged.size > 1 ? "s" : ""}!`;
const message = [
`${purged.size} messages`,
user ? ` from \`${user.tag}\`` : "",
term ? ` containing \`${term}\`` : "",
` have been deleted from ${channel}!`,
].join("");
const userPurge = new EmbedBuilder()
.setColor("#2F3136")
.setTitle(`🧹 PURGED!`)
.addFields(
{
name: title,
value: message,
},
{
name: `User`,
value: user ? `\`${user.tag}\`` : "Unspecified",
inline: true,
},
{
name: `Term`,
value: term ? `||\`${term}\`||` : `\`Unspecified\``,
inline: true,
},
{
name: `Reason(s)`,
value: `\`${reason}\``,
inline: true,
},
);
await channel.send({ embeds: [userPurge] });
},
}
I was coding a userInfo command but when I use the command, the joinedAtTimeStamp is showing <t:NaN:R> in the embed. It's the only problem in this code.
My code:
const { MessageEmbed, ContextMenuInteraction } = require("discord.js");
module.exports = {
name: "userInfo",
aliases: ["user"],
permissions: ["SEND_MESSAGES", "ATTACH_FILES"],
description: "user",
async execute(message, args, cmd, client, Discord, profileData) {
const target = message.mentions.users.first();
if(!args[0]) {
const response2 = new MessageEmbed()
.setColor("RANDOM")
.setAuthor({name: message.author.tag, iconURL: message.author.displayAvatarURL({dynamic: true})})
.setThumbnail(message.author.displayAvatarURL({dynamic: true}))
.addFields(
{name: "ID", value: message.author.id},
{name: "Joined Server", value: `<t:${parseInt(message.author.joinedTimestamp / 1000)}:R>`, inline: true},
{name: "Account Created", value: `<t:${parseInt(message.author.createdTimestamp / 1000)}:R>`, inline: true},
);
message.reply({embeds:[response2]});
}
const response = new MessageEmbed()
.setColor("RANDOM")
.setAuthor({name: target.tag, iconURL: target.displayAvatarURL({dynamic: true})})
.setThumbnail(target.displayAvatarURL({dynamic: true}))
.addFields(
{name: "ID", value: target.id},
{name: "Joined Server", value: `<t:${parseInt(target.joinedTimestamp / 1000)}:R>`, inline: true},
{name: "Account Created", value: `<t:${parseInt(target.createdTimestamp / 1000)}:R>`, inline: true},
);
message.reply({embeds: [response], ephemeral: true})
}
}
I am using discord.js v13 and node 16.
message.author is a User and it doesn't have a joinedTimestamp property, only GuildMembers have. message.member represents the author of the message as a guild member, so you can use that as it will have a joinedTimestamp property.
The reason you see NaN instead of the correct value is because parseInt will return NaN if you try to parse undefined:
console.log('undefined:', parseInt(undefined / 1000, 10));
console.log('3459192421512:', parseInt(3459192421512 / 1000, 10));
The following code should work as expected
.addFields(
{ name: 'ID', value: message.author.id },
{
name: 'Joined Server',
value: `<t:${parseInt(message.member.joinedTimestamp / 1000, 10)}:R>`,
inline: true,
},
{
name: 'Account Created',
value: `<t:${parseInt(message.author.createdTimestamp / 1000, 10)}:R>`,
inline: true,
},
);
As for target, it's the same issue; message.mentions.users.first() is a User. You could create a new variable, e.g. targetMember and assign message.mentions.members.first(), so it will be a GuildMember:
const target = message.mentions.users.first();
const targetMember = message.mentions.members.first();
And then, just replace target:
.addFields(
{ name: 'ID', value: target.id },
{
name: 'Joined Server',
value: `<t:${parseInt(targetMember.joinedTimestamp / 1000, 10)}:R>`,
inline: true,
},
{
name: 'Account Created',
value: `<t:${parseInt(target.createdTimestamp / 1000, 10)}:R>`,
inline: true,
},
);
PS: It's a good idea to use the radix in parseInt. That's why I added 10 as the second parameter in parseInt.
Could you verify the type of target.joinedTimestamp?
It could be that the double conversion you are doing here:
parseInt(target.joinedTimestamp / 1000)
destroyed your number.
(You are converting whatever target.createdTimestamp is to number, dividing it by 100 (making it a floating point number) and then discarding the floating point by converting back to int.)
I was making a status command for my discord bot, that returns title, description, and some fields.
I ran into an error. I am using discord.js v13 and Node.js v16.14.2.
My code:
const { MessageEmbed, CommandInteraction, Client, version } = require("discord.js");
const { connection } = require("mongoose");
const os = require("os");
const quick = require('quick.db');
module.exports = {
name: "status",
asliases: [],
permissions: [],
description: "Displays the status of the client",
async execute(message, args, cmd, client, Discord, profileData) {
const messagePing = Date.now();
const endMessagePing = Date.now() - messagePing;
const status = [
"Disconnected",
"Connected",
"Connecting",
"Disconnecting"
];
const embed = new MessageEmbed()
.setColor("RANDOM")
.setTitle(`🌟 PDM Bot Status`)
.setThumbnail('https://imgur.com/IDhLmjc')
.setDescription("in the Skys with PDM Bot")
.addFields(
{ name: "🧠 Client", value: client.tag, inline: true },
{ name: "📆 Created", value: `<t:${parseInt(client.createdTimestamp / 1000, 10)}:R>`, inline: true },
{ name: "✅ Verified", value: "No, Please help us to get Verified :)", inline: true },
{ name: "👩🏻💻 Owner", value: 'Pooyan#9627', inline: true },
{ name: "📚 Database", value: 'Connected', inline: true },
{ name: "⏰ Up Since", value: `<t:${parseInt(client.readyTimestamp / 1000, 10)}:R>`, inline: true },
{ name: "🏓 Ping", value: `${endMessagePing}ms , for more information, use -ping command`, inline: true },
{ name: "📃 Commands", value: `45`, inline: true },
{ name: "🏨 Servers", value: `${client.guilds.cache.size}`, inline: true },
{ name: "👦 Users", value: `${client.guilds.cache.memberCont}`, inline: true },
);
message.channel.send({ embeds: [embed], ephemeral: true });
}
}
The error that I ran into because of the embed:
RangeError [EMBED_FIELD_VALUE]: MessageEmbed field values must be non-empty strings.
at Function.verifyString (C:\Users\Pooyan\Desktop\PDM Bot Main\node_modules\discord.js\src\util\Util.js:416:41)
at Function.normalizeField (C:\Users\Pooyan\Desktop\PDM Bot Main\node_modules\discord.js\src\structures\MessageEmbed.js:544:19)
at C:\Users\Pooyan\Desktop\PDM Bot Main\node_modules\discord.js\src\structures\MessageEmbed.js:565:14
at Array.map (<anonymous>)
at Function.normalizeFields (C:\Users\Pooyan\Desktop\PDM Bot Main\node_modules\discord.js\src\structures\MessageEmbed.js:564:8)
at MessageEmbed.addFields (C:\Users\Pooyan\Desktop\PDM Bot Main\node_modules\discord.js\src\structures\MessageEmbed.js:328:42)
at Object.execute (C:\Users\Pooyan\Desktop\PDM Bot Main\commands\status.js:26:14)
at module.exports (C:\Users\Pooyan\Desktop\PDM Bot Main\events\guild\message.js:104:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
[Symbol(code)]: 'EMBED_FIELD_VALUE'
}
I read one or two similar questions/posts but it did not help.
Multiple properties here don't exist, including:
client.tag
client.createdTimestamp
client.guilds.cache.memberCount
Here are the things you should replace them with:
// client.tag
client.user.tag
// client.createdTimestamp
client.user.createdTimestamp
// client.guilds.cache.memberCount
client.guilds.cache.reduce((acc, g) => acc + g.memberCount, 0)
I was trying to make an embed info command with "info user" and "info server" subcommand. When I try to show the owner's user tag in the embeds it shows undefined so I was told to change get(ownerId) to fetch, but was then told to resolve the promise. Same goes with the member, where I was trying to see how many bots there are in the server, it always show 1 whereas there were 5. Now the terminal doesn't show error when I do the info server command, but in the discord channel it shows interaction failed. The info user command works perfectly. How should I fix this?
const { SlashCommandBuilder } = require('#discordjs/builders');
const { MessageEmbed } = require("discord.js");
const moment = require("moment");
module.exports = {
data: new SlashCommandBuilder()
.setName('info')
.setDescription('returns info based on input')
.addSubcommand(subcommand =>
subcommand
.setName("user")
.setDescription("get the information of a member mentioned")
.addUserOption(option => option.setName("member").setDescription("Tag a member")))
.addSubcommand(subcommand =>
subcommand
.setName("server")
.setDescription("info about this server")),
async execute(interaction, client, user, members) {
if (interaction.options.getSubcommand() === "user") {
const user = interaction.options.getUser("member");
if (user) {
const member = interaction.guild.members.cache.get(user.id)
const userEmbed = new MessageEmbed()
.setTitle(`${user.username}'s Information:`)
.setDescription(`This is a member in ${interaction.guild.name} :raised_hands:`)
.setAuthor(user.username, user.displayAvatarURL())
.setThumbnail(client.user.displayAvatarURL())
.addFields(
{ name: `Username`, value: `This member's username is ${user.username}`, inline: true },
{ name: `Tag`, value: `This member's tag is #${user.discriminator}`, inline: true },
{ name: `Joined Discord`, value: new Date(user.createdTimestamp).toDateString(), inline: true },
{ name: `Joined server`, value: new Date(member.joinedTimestamp).toDateString(), inline: true },
{ name: `Is this member a bot?`, value: `${user.bot}`, inline: true },
{ name: `Nickname`, value: member.nickname || "None", inline: true },
{ name: `Role count`, value: `${member.roles.cache.size - 1}`, inline: true },
)
.setImage(user.displayAvatarURL())
.setTimestamp()
.setColor("#F2A4D3")
.setFooter(client.user.tag, client.user.displayAvatarURL());
if (interaction.guild.members.cache.get(user.id).roles.cache.has("869759848747786262")) {
userEmbed.addFields({ name: `Boost status`, value: `This member has been boosting our server since ${new Date(member.premiumSinceTimestamp).toDateString()} :grin:`, inline: true }, { name: `\u200B`, value: `\u200B`, inline: true })
} else {
userEmbed.addFields({ name: `Boost status`, value: `This noob isn't boosting our server :neutral_face:`, inline: true }, { name: `\u200B`, value: `\u200B`, inline: true })
}
await interaction.reply({ embeds: [userEmbed] });
} else {
const user = interaction.user
const member = interaction.guild.members.cache.get(user.id)
const selfEmbed = new MessageEmbed()
.setTitle(`Your User Information (narcissistic much??):`)
.setDescription(`You're in ${interaction.guild.name} :raised_hands:`)
.setAuthor(user.username, user.displayAvatarURL())
.setThumbnail(client.user.displayAvatarURL())
.addFields(
{ name: `Username`, value: `Your username is ${user.username}`, inline: true },
{ name: `Tag`, value: `Your tag is #${user.discriminator}`, inline: true },
{ name: `Joined Discord`, value: `You joined discord on ${new Date(user.createdTimestamp).toDateString()}`, inline: true },
{ name: `Joined server`, value: `You joined this server on ${new Date(member.joinedTimestamp).toDateString()}`, inline: true },
{ name: `Are you a bot?`, value: `${user.bot}`, inline: true },
{ name: `Nickname`, value: member.nickname || "None", inline: true },
{ name: `Role count`, value: `${member.roles.cache.size - 1}`, inline: true },
)
.setImage(user.displayAvatarURL())
.setTimestamp()
.setColor("#F2A4D3")
.setFooter(client.user.tag, client.user.displayAvatarURL());
if (interaction.guild.members.cache.get(user.id).roles.cache.has("869759848747786262")) {
selfEmbed.addFields({ name: `Boost status`, value: `OOO you've been boosting our server since ${new Date(member.premiumSinceTimestamp).toDateString()}, so swag :grin:`, inline: true }, { name: `\u200B`, value: `\u200B`, inline: true })
} else {
selfEmbed.addFields({ name: `Boost status`, value: `You're not boosting our server, get nitro and boost it right now you idiot :neutral_face:`, inline: true }, { name: `\u200B`, value: `\u200B`, inline: true })
}
await interaction.reply({ embeds: [selfEmbed] });
//await interaction.reply(`Username: ${user.username}\nYour ID: ${user.id}`);
}
} else if (interaction.options.getSubcommand() === "server") {
const server = interaction.guild;
const user = await client.users.fetch(interaction.guild.ownerId);
const members = await interaction.guild.members.fetch();
const channels = interaction.guild.channels.cache;
const emojis = interaction.guild.emojis.cache;
const date = new Date(interaction.guild.createdTimestamp).toDateString();
const serverEmbed = new MessageEmbed()
.setTitle(`${server.name}'s Information`)
.setAuthor(server.name, server.iconURL())
.setThumbnail(client.user.displayAvatarURL())
.addFields(
{ name: `Owner`, value: `<#${interaction.guild.ownerId}>, ${user.tag}` },
{ name: `Server ID`, value: `${server.id}`, inline: true },
{ name: `Total Members`, value: `${server.memberCount}`, inline: true },
//{ name: `Online`, value: `${server.members.cache.filter(member => member.user.presence.status = "online").size}`, inline: true},
{ name: `Time created`, value: `${moment(interaction.guild.createdTimestamp).format("LT")}, ${moment(interaction.guild.createdTimestamp).format("LL")}, ${moment(interaction.guild.createdTimestamp).fromNow()}`},
//{ name: `Time created`, value: `${moment(interaction.guild.createdTimestamp.toLocale()).format("LT)")}, ${moment(date).format("LL")}`},
{ name: `Emojis`, value: `${emojis.size}`},
{name: `Regular emojis`, value: `${emojis.filter(emoji => !emoji.animated).size}`},
{name: `Animated emojis`, value: `${emojis.filter(emoji => emoji.animated).size}`},
{name: `Human`, value: `${members.filter(member => !member.user.bot).size}`},
{name: `Bots`, value: `${members.filter(member => member.user.bot).size}`},
{name: `Text channels`, value: `${channels.filter(channel => channel.type === "text").size}`},
{name: `Voice channels`, value: `${channels.filter(channel => channel.type === "voice").size}`},
{name: `Boost`, value: `${interaction.guild.premiumSubscriptionCount || "0"}`},
{name: `Online`, value: `${members.filter(member => member.presence.status === "online")}`},
)
.setImage(server.iconURL())
.setTimestamp()
.setColor("#F2A4D3")
.setFooter(client.user.tag, client.user.displayAvatarURL());
await interaction.reply({ embeds: [serverEmbed] });
} else {
await interaction.reply("No sub command was used.");
}
},
};
I am working on a discord bot and I was trying to test an embed and an error popped up saying
ReferenceError: channel is not defined
This is the code for the embed
client.on('message', (message) => {
console.log(`[${message.author.tag}]: ${message.content}`);
if (message.content === 'brh!testembed') {
const exampleEmbed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('Some title')
.setURL('https://discord.js.org/')
.setAuthor('Some name', 'https://i.imgur.com/wSTFkRM.png', 'https://discord.js.org')
.setDescription('Some description here')
.setThumbnail('https://i.imgur.com/wSTFkRM.png')
.addFields(
{ name: 'Regular field title', value: 'Some value here' },
{ name: '\u200B', value: '\u200B' },
{ name: 'Inline field title', value: 'Some value here', inline: true },
{ name: 'Inline field title', value: 'Some value here', inline: true },
)
.addField('Inline field title', 'Some value here', true)
.setImage('https://i.imgur.com/wSTFkRM.png')
.setTimestamp()
.setFooter('Some footer text here', 'https://i.imgur.com/wSTFkRM.png');
channel.send(exampleEmbed);
}
});
Like the error says you have not defined channel if you want to send the embed to the same channel as your command was used in just do:
message.channel.send(exampleEmbed);
If you are using v13 use:
message.channel.send({embeds: [exampleEmbed]});