This is my current code:
const superagent = require("snekfetch");
const Discord = require('discord.js')
const random = require('random')
const os = require('os')
module.exports.run = async (client, message, args) => {
if (!message.channel.nsfw) {
message.react('💢');
return message.channel.send({embed: {
color: 16734039,
description: "CO TY ROBISZ! TE ZDJENCIA SA TYLKO DLA DOROSLYCH! (idz na kanal NSFW)"
}})
}
superagent.get('https://nekos.life/api/v2/img/ero')
.end((err, response) => {
const embed = new Discord.RichEmbed()
.setTitle(":smirk: Eevee")
.setImage(random.choice(os.listdir("./app/eevee")))
.setColor(`RANDOM`)
.setFooter(`Tags: eevee`)
.setURL(response.body.url);
message.channel.send(embed);
}).catch((err) => message.channel.send({embed: {
color: 16734039,
description: "Something is wrong... :cry:"
}}));
}
module.exports.help = {
name: "eevee",
description: "Fajno zdjencia",
usage: "eevee",
type: "NSFW"
}
When I try to run it, I get this error message:
TypeError: os.listdir is not a function
Is there anything I can do to fix this problem?
I don't really know the os package but after a bit of researching I've found no readdir function. If you want to get all files of a directory you also can do it like this:
const fs = require('fs')
const allMyFiles = fs.readdirSync();
Also you are creating your embed with RichEmbed() which is outdated. Since v12 you have to use MessageEmbed():
const exampleEmbed = new Discord.MessageEmbed()
.setTitle('Test')
[...]
Related
it might be a stupid question but since I'm a beginner I sadly don't understand most of how javascript works yet.
I'm trying to create a small Discord bot for a project that I'm working on and I would like to make it so you can select an option from a dropdown menu and whatever you select it sends a different embedded message in the channel. But whatever I do it doesn't send the embedded message. I've looked up multiple tutorials, but it seems like I'm missing something. Maybe someone can direct me in the right direction.
It is sending the dropdown menu, but sending error "InteractionAlreadyReplied". And whenever I try to select an option it won't send the embedded messages.
Here is my code so you can see the approach I'm using. I've tried using "MessageActionRow" and "MessageSelectMenu", but it seems like they don't work anymore. After inserting "ActionRowBuilder" and "StringSelectMenuBuilder" I got the menu working, but as said I don't get the embedded messages as an option. (didn't include the .env file since its only the token in there) I'm just not sure how I can make it so it connects the values from the dropdown menu to the right embeds.
CommandFile:
const { Discord, MessageActionRow, MessageSelectMenu,
SlashCommandBuilder, EmbedBuilder, roleMention, ButtonBuilder,
StringSelectMenuBuilder, StringSelectMenuOptionBuilder, ActionRowBuilder } = require('discord.js');
const { MessageEmbed } = require("discord.js")
module.exports = {
data: new SlashCommandBuilder()
.setName('dropdown')
.setDescription('Returns a select dropdown!'),
async execute(interaction, client, message, args) {
const row = new ActionRowBuilder()
.addComponents(
new StringSelectMenuBuilder()
.setCustomId("select")
.setPlaceholder("Wähle etwas aus:")
.addOptions([
{
label: "Auswahl 1",
description: "Beschreibung Auswahl 1",
value: "first"
},
{
label: "Auswahl 2",
description: "Beschreibung Auswahl 2",
value: "second"
},
{
label: "Auswahl 3",
description: "Beschreibung Auswahl 3",
value: "third"
},
])
)
let embed = new EmbedBuilder()
.setTitle("Embed Startseite")
.setDescription("Ab hier kann man selecten, was man möchte")
.setColor(0x18e1ee)
let sendmsg = await interaction.reply({ content:
"ã…¤", ephemeral:true, embeds: [embed], components: [row] })
let embed1 = new EmbedBuilder()
.setTitle("Embed 1")
.setDescription("Embed 1 Beschreibung")
.setColor(0x18e1ee)
let embed2 = new EmbedBuilder()
.setTitle("Embed 2")
.setDescription("Embed 2 Beschreibung")
.setColor(0x18e1ee)
let embed3 = new EmbedBuilder()
.setTitle("Embed 3")
.setDescription("Embed 3 Beschreibung")
.setColor(0x18e1ee)
const collector = message.createMessageComponentCollector({
componentType: "StringSelectMenuBuilder"
})
collector.on("collect", async (collected) => {
const value = collected.values[0]
if(value === "first") {
collected.reply({ embeds: [embed1], ephemeral:true })
}
if(value === "second") {
collected.reply({ embeds: [embed2], ephemeral:true })
}
if(value === "third") {
collected.reply({ embeds: [embed3], ephemeral:true })
}
})
}
}
bot.js:
require("dotenv").config();
const { token } = process.env;
const { Client, Collection, GatewayIntentBits, ChannelSelectMenuInteraction } = require("discord.js");
const fs = require("fs");
const client = new Client({ intents: GatewayIntentBits.Guilds });
client.commands = new Collection();
client.buttons = new Collection();
client.selectMenus = new Collection();
client.commandArray = [];
const functionFolders = fs.readdirSync(`./src/functions`);
for (const folder of functionFolders) {
const functionFiles = fs
.readdirSync(`./src/functions/${folder}`)
.filter((file) => file.endsWith(".js"));
for (const file of functionFiles)
require(`./functions/${folder}/${file}`)(client);
}
client.handleEvents();
client.handleCommands();
client.handleComponents();
client.login(token);
HandleComponents.js :
const { readdirSync } = require('fs');
module.exports = (client) => {
client.handleComponents = async () => {
const componentFolders = readdirSync(`./src/components`);
for (const folder of componentFolders) {
const componentFiles = readdirSync(`./src/components/${folder}`).filter(
(file) => file.endsWith('.js')
);
const { buttons, selectMenus } = client;
switch (folder) {
case "buttons":
for (const file of componentFiles) {
const button = require(`../../components/${folder}/${file}`);
buttons.set(button.data.name, button);
}
break;
case "selectMenus":
for (const file of componentFiles) {
const menu = require(`../../components/${folder}/${file}`);
selectMenus.set(menu.data.name, menu);
}
break;
default:
break;
}
}
};
};
HandleCommands.js :
const { REST } = require('#discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const fs = require("fs");
module.exports = (client) => {
client.handleCommands = async () => {
const commandFolders = fs.readdirSync("./src/commands");
for (const folder of commandFolders) {
const commandFiles = fs
.readdirSync(`./src/commands/${folder}`)
.filter(file => file.endsWith(".js"));
const { commands, commandArray } = client;
for (const file of commandFiles) {
const command = require(`../../commands/${folder}/${file}`);
commands.set(command.data.name, command);
commandArray.push(command.data.toJSON());
}
}
const clientId = "IDbutCensored";
const guildId = "IDbutCensored";
const rest = new REST({ version: '9' }).setToken(process.env.token);
try {
console.log("Started refreshing application (/) commands.");
await rest.put(Routes.applicationGuildCommands(clientId, guildId), {
body: client.commandArray,
});
console.log("Successfully reloaded application (/) commands.");
} catch (error) {
console.error(error);
}
};
};
handleEvents.js :
const fs = require("fs");
module.exports = (client) => {
client.handleEvents = async () => {
const eventFolders = fs.readdirSync(`./src/events`);
for (const folder of eventFolders) {
const eventFiles = fs
.readdirSync(`./src/events/${folder}`)
.filter((file) => file.endsWith(".js"));
switch (folder) {
case "client":
for (const file of eventFiles) {
const event = require(`../../events/${folder}/${file}`);
if (event.once) client.once(event.name, (...args) => event.execute(...args, client));
else client.on(event.name, (...args) => event.execute(...args, client));
}
break;
default:
break;
}
}
}
}
The error is pretty self explanatory. The error InteractionAlreadyReplied means you already replied and you're trying to reply again.
You can solve this by doing the following;
• Use .followUp() to send a new message
• If you deferred reply it's better to use .editReply()
• Information about responding to slash commands / buttons / select menus
From the Discord docs
Code:
const config = require('../../config.json');
const Discord = require('discord.js');
module.exports = async(guild, bannerURL, client) => {
const logChannel = await client.channels.cache.get(config.log_channel_id);
if (!logChannel) return;
const embed = new Discord.MessageEmbed()
.setAuthor({ name: guild.name, iconURL: guild.iconURL() })
.setDescription(`**${guild.name} has banner now!**`)
.setImage(bannerURL)
.setColor(config.colour)
.setTimestamp()
return logChannel.send({ embeds: [embed] })
}
When adding a banner to the server it gives the error Unhandled Rejection: TypeError: Cannot read properties of undefined (reading 'channels')
The other logging files have the exact same line of code const logChannel = await client.channels.cache.get(config.log_channel_id); and it works fine
Adding console.log(client) before const logChannel returns undefined
This code below works after we troubleshot the issue.
banner.js
module.exports = {
name: 'banner',
description: 'emit update',
devs: true,
run: async (guild, message) => {
guild.emit('guildBannerAdd', message.member);
message.channel.send('Done ...');
},
};
guildBannerAdd.js
const config = require('../../config.json')
const Discord = require('discord.js')
module.exports = async (client, member) => {
const guild = client.guilds.cache.get(config.serverID)
const logChannel = client.channels.cache.get(config.log_channel_id);
if (!logChannel) return;
const embed = new Discord.MessageEmbed()
.setAuthor({
name: guild.name,
iconURL: guild.iconURL()
})
.setDescription(`**${guild.name} has banner now!**`)
.setImage(guild.bannerURL())
.setColor(config.colour)
.setTimestamp();
return logChannel.send({
embeds: [embed]
});
}
What I did was use code from another command which does work. The command grabs images from a link then pastes them in the chat. I have made 3 other commands which post things such as hug | kiss | bye, etc... I thought I can simply add a similar thing for NSFW commands but that doesn't seem to be the case. The command partially works the text goes through but doesn't respond with an image like other commands.
Here are a few examples of the output for the command
Image of the output for discord command
[![enter image description here][1]][1]
Here is the code for the command that does not work
const fetch = require('node-fetch');
const config = require('../../config.js');
module.exports = {
config: {
name: "lewd",
aliases: [""],
category: "nsfw",
description: "Sends an NSFW image ;)",
usage: `${config.PREFIX}cat`,
},
run: async (bot, message, args) => {
const res = await fetch('https://gallery.fluxpoint.dev/api/nsfw/lewd');
const img = (await res.json()).link;
const embed = new Discord.MessageEmbed()
.setTitle(`OwO`)
.setImage(img)
.setFooter(`Requested ${message.member.displayName}`, message.author.displayAvatarURL({ dynamic: true }))
.setTimestamp()
.setColor(message.guild.me.displayHexColor);
message.channel.send(embed);
}
}
If you need the code that does work and output an image here it is
const fetch = require('node-fetch');
const config = require('../../config.js');
module.exports = {
config: {
name: "hug",
aliases: [""],
category: "images",
description: "hug",
usage: `${config.PREFIX}cat`,
},
run: async (bot, message, args) => {
const res = await fetch('https://some-random-api.ml/animu/hug');
const img = (await res.json()).link;
const embed = new Discord.MessageEmbed()
.setTitle(`;)`)
.setImage(img)
.setFooter(`Requested ${message.member.displayName}`, message.author.displayAvatarURL({ dynamic: true }))
.setTimestamp()
.setColor(message.guild.me.displayHexColor);
message.channel.send(embed);
}
} ```
[1]: https://i.stack.imgur.com/UjIwV.png
This is my code:
const superagent = require("snekfetch");
const Discord = require('discord.js')
const random = require('random')
const fs = require('fs')
module.exports.run = async (client, message, args) => {
if (!message.channel.nsfw) {
message.react('💢');
return message.channel.send({embed: {
color: 16734039,
description: "CO TY ROBISZ! TE ZDJENCIA SA TYLKO DLA DOROSLYCH! (idz na kanal NSFW)"
}})
}
superagent.get('https://nekos.life/api/v2/img/ero')
.end((err, response) => {
const embed = new Discord.MessageEmbed()
const allMyFiles = fs.readdirSync("/app/eevee")
.setTitle(":smirk: Eevee")
.setImage(random.choice(allMyFiles))
.setColor(`RANDOM`)
.setFooter(`Tags: eevee`)
.setURL(random.choice(allMyFiles));
message.channel.send(embed);
}).catch((err) =>
console.log(err))
message.channel.send({embed: {
color: 16734039,
description: "Something is wrong... :cry:"
}});
}
module.exports.help = {
name: "eevee",
description: "Fajno zdjencia",
usage: "eevee",
type: "NSFW"
}
How do I make the command display a random image from a folder, if that is not possible does anyone know any API similar to nekos.life but with customizable images?
Using Math.random():
const allMyFiles = fs.readdirSync('/path/to/dir/')
let myFile = allMyFiles[Math.floor(Math.random() * allMyFiles.length)]
I have script for warn command and i need help with that, because this
code working, this command saving warns in warnings.json, but when i warn someone that warn be in every guild i want only in one guild warns. Please help :D
const { MessageEmbed } = require("discord.js")
const fs = require('fs')
const warns = JSON.parse(fs.readFileSync("./warnings.json", "utf8"))
const moment = require('moment')
module.exports = {
name: "warn",
description: "Wysyła ankiete",
guildOnly: true,
cooldown: 5,
run(msg, args) {
// Embed na permisjebota
const permisjebota = new MessageEmbed()
.setTitle("⛔ Nie mam uprawnień! :O")
.setColor('ffff00')
.setDescription("Nie mam uprawnień do tej komendy! Daj mi uprawnienia lub skonsultuj się z adminem serwera")
.setTimestamp()
// Embed na permisje dla użytkownika
const permisje = new MessageEmbed()
.setTitle("Nie masz permisji do tej komendy! :O")
.setColor('ffff00')
.setDescription("Nie masz uprawnień do tej komendy! Jeżeli uważasz, że to błąd skonsultuj się z adminem serwera!")
if (!msg.member.guild.me.hasPermission("ADMINISTRATOR"))
return msg.channel.send(permisjebota)
if (!msg.member.hasPermission("MANAGE_MESSAGES")) return msg.channel.send(permisje)
if(!args[0, 1]) {
const bananekbot = new MessageEmbed()
.setTitle("Nie podałeś argumentów!")
.setColor('ffff00')
.setDescription("Poprawne użycie: `m!warn <nick> <powód>`")
return msg.channel.send(bananekbot)
}
var warnUser = msg.guild.member(msg.mentions.users.first() || msg.guild.members.get(args[0]))
var reason = args.slice(1).join(" ")
if (!warnUser) return msg.channel.send("Brak argumentu poprawne użycie: m!warn <nick> <powód>")
if (!warns[warnUser.id]) warns[warnUser.id] = {
warns: 0,
}
warns[warnUser.id].warns++
fs.writeFile("./warnings.json", JSON.stringify(warns), (err) =>{
if(err) console.log(err)
})
const warnembed = new MessageEmbed()
.setTitle("✅ Nadano warna")
.setColor('ffff00')
.setTimestamp()
.setDescription(`Użytkownik: ${warnUser} (${warnUser.id})
NadajÄ…cy warna: ${msg.author}
Powód: ${reason}`)
return msg.channel.send(warnembed)
}
}
A potential solution to this is to have warnings.json as an array, and in side containing an object with guild id, warns and anything else you need to store. So warnings.json ends up something like this.
[
{
"guild_id": "12345678901234",
"an_extra": "Thing",
"warns": [
"your_warns",
"are_here",
"store_in_any_format"
]
},
{
"guild_id": "12345678901234",
"an_extra": "Guild",
"warns": [
"so_on",
"And so forth",
"go the warns and guilds"
]
}
]
This way, you can simply do Array.find(guild => guild.guild_id === msg.guild.id) (Assuming the guild you are trying to access is msg.guild).
Learn more on MDN about Array.prototype.find()