Discord.js Ticket system doesn't send an ephemeral message - discord

I'm trying to make a ticket system with discord.js v13, but the ephemeral method doesn't work and, when my bot turn on, i need to click one time in the button to activate the system.
print
My code:
const { MessageActionRow, MessageButton, MessageEmbed, Permissions } = require('discord.js');
const db = require("quick.db");
exports.run = async (client, interaction) => {
if (!interaction.isButton()) return;
interaction.deferUpdate();
let getContador = await db.get('counter')
if(getContador === null) {
let contador = await db.set("counter", 1)
}
await db.add("counter", 1)
let tcID = "895323735702253569"
let tmID = "895358127950659604"
const filter = i => i.customId === 'OPENTICKET'
const collector = interaction.channel.createMessageComponentCollector({ filter, max: 1 });
collector.on("collect", async i => {
let cTicket = await i.guild.channels.create(`🎫┆Ticket ${getContador}`, {
type: 'GUILD_TEXT',
permissionOverwrites: [
{
id: i.guild.id,
deny: [Permissions.FLAGS.VIEW_CHANNEL],
},
{
id: i.user.id,
allow: [Permissions.FLAGS.VIEW_CHANNEL, Permissions.FLAGS.SEND_MESSAGES],
},
]
})
await interaction.channel.messages.cache.get(tmID).reply({ content: `... ${cTicket.toString()}...`, ephemeral: true })
})
}

You are replying to a normal message. If you would like an ephemeral message, you have to directly reply to the interaction.
interaction.reply({
content: `... ${cTicket.toString()}...`,
ephemeral: true
})

Related

TypeError: command.execute is not a function

I am aware that this problem has been discussed already, but I don't seem to fit the solutions found into my code. I've created some commands to this bot and they seem to work, although they are only basic slash commands (e.g. /ping). This problem came in when I try to run a moderation command or a play command.
This is the code with the error
const { Interaction } = require("discord.js");
module.exports = {
name: 'interactionCreate',
async execute(interaction, client) {
if (!interaction.isCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) return
try{
await command.execute(interaction, client);
} catch (error) {
console.log(error);
await interaction.reply({
content: 'A aparut o eroare cu aceasta comanda!',
ephemeral: true
});
}
},
};
None of the fixes that I found seem to fit, at least to my rather unexperienced eye.
The command I try to run is this:
const { SlashCommandBuilder } = require("#discordjs/builders")
const { MessageEmbed } = require("discord.js")
const { QueryType } = require("discord-player")
module.exports = {
data: new SlashCommandBuilder()
.setName("play")
.setDescription("Asculta muzica")
.addSubcommand((subcommand)=>
subcommand
.setName("song")
.setDescription("Incarca o singura melodie printr-un url")
.addStringOption((option) => option.setName("url").setDescription("url-ul melodiei").setRequired(true)))
.addSubcommand((subcommand) =>
subcommand
.setName("playlist")
.setDescription("Incarca un playlist printr-un url")
.addStringOption((option) => option.setName("url").setDescription("url-ul playlist-ului").setRequired(true)))
.addSubcommand((subcommand) =>
subcommand
.setName("search")
.setDescription("Cauta o melodie pe baza cuvintelor-cheie")
.addStringOption((option) =>
option.setName("searchterms").setDescription("the search keywords").setRequired(true))),
run: async ({ client, interaction }) => {
if (interaction.member.voice.channel)
return interaction.editReply("Trebuie sa fii pe un voice channel pentru a folosi aceasta comanda!")
const queue = await client.player.createQueue(interaction.guild)
if (!queue.connection) await queue.connect(interaction.member.voice.channel)
let embed = new MessageEmbed()
if (interaction.options.getSubcommand() === "song"){
let url = interaction.options.getString("url")
const result = await client.player.search(url, {
requestedBy: interaction.user,
searchEngine: QueryType.YOUTUBE_VIDEO
})
if (result.tracks.length === 0)
return interaction.editReply("Niciun rezultat")
const song = result.tracks[0]
await queue.addTrack(song)
embed
.setDescription(`**[${song.title}](${song.url})**a fost adaugata`)
.setFooter({ text: `Durata: ${song.duration}`})
} else if (interaction.options.getSubcommand() === "playlist"){
let url = interaction.options.getString("url")
const result = await client.player.search(url, {
requestedBy: interaction.user,
searchEngine: QueryType.YOUTUBE_PLAYLIST
})
if (result.tracks.length === 0)
return interaction.editReply("Niciun rezultat")
const playlist = result.tracks
await queue.addTrack(result.tracks)
embed
.setDescription(`**${result.tracks.length} melodii din [${playlist.title}](${playlist.url})**a fost adaugata`)
.setFooter({ text: `Durata: ${playlist.duration}`})
} else if (interaction.options.getSubcommand() === "search"){
let url = interaction.options.getString("seatchterms")
const result = await client.player.search(url, {
requestedBy: interaction.user,
searchEngine: QueryType.AUTO
})
if (result.tracks.length === 0)
return interaction.editReply("Niciun rezultat")
const song = result.tracks[0]
await queue.addTrack(song)
embed
.setDescription(`**[${song.title}](${song.url})**a fost adaugata`)
.setFooter({ text: `Durata: ${song.duration}`})
}
if (!queue.playing) await queue.play()
await interaction.editReply({
embeds: [embed]
})
}
}
and the corresponding error:
TypeError: command.execute is not a function
at Object.execute (C:\Users\shelby\Bot\src\events\interactionCreate.js:15:27)
at Client.<anonymous> (C:\Users\shelby\Bot\src\functions\handelEvents.js:8:58)
at Client.emit (node:events:513:28)
at InteractionCreateAction.handle (C:\Users\shelby\Bot\node_modules\discord.js\src\client\actions\InteractionCreate.js:97:12)
at module.exports [as INTERACTION_CREATE] (C:\Users\shelby\Bot\node_modules\discord.js\src\client\websocket\handlers\INTERACTION_CREATE.js:4:36)
at WebSocketManager.handlePacket (C:\Users\shelby\Bot\node_modules\discord.js\src\client\websocket\WebSocketManager.js:352:31)
at WebSocketShard.onPacket (C:\Users\shelby\Bot\node_modules\discord.js\src\client\websocket\WebSocketShard.js:489:22)
at WebSocketShard.onMessage (C:\Users\shelby\Bot\node_modules\discord.js\src\client\websocket\WebSocketShard.js:328:10)
at callListener (C:\Users\shelby\Bot\node_modules\ws\lib\event-target.js:290:14)
at WebSocket.onMessage (C:\Users\shelby\Bot\node_modules\ws\lib\event-target.js:209:9)
You should be using command.run() instead of command.execute(), as your exported Slash Command uses this property name to store the core function.
const { Interaction } = require("discord.js");
module.exports = {
name: 'interactionCreate',
async execute(interaction, client) {
if (!interaction.isCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) return
try{
await command.run({ interaction, client });
} catch (error) {
console.log(error);
await interaction.reply({
content: 'A aparut o eroare cu aceasta comanda!',
ephemeral: true
});
}
},
};
Additionally, you have to use an object that contains your interaction and client to run the function instead of using two arguments.

Number Type Schema not updating

I'm trying to make a bot that let's you give fame points to users as well as currency, currency works just fine and it updates whenever someone sends a message with a 1 minute cooldown. however I'm having problems with my fame schema. the bot creates a new schema if there's not an already existing one without problem and it also displays the amount correctly, however, when you click the button to give someone a Fame point, it doesn't, it stays at 0. I'm probably missing something simple but I can't seem to find it, here's the code:
const { MessageEmbed,ButtonInteraction} = require('discord.js');
const Fame = require('../../schemas/fame');
module.exports = {
data: {
name: `yes-fame`
},
async execute (interaction, client) {
const user = require('../../commands/entertainment/givefame')
const fameProfile = await client.createFame(user)
try {
await Fame.findOneAndUpdate({ _id: fameProfile._id}, { $inc: { amount: 1 } });
} catch (error) {
console.log(error);
}
const userEmbed = new MessageEmbed()
.setTitle(`<:fame:952026535756435536> Fame Point Given`)
.setDescription(`${interaction.user} has given 1 fame point to ${user} `)
.setTimestamp()
.setColor("#00FF00")
.setFooter(client.user.tag, client.user.displayAvatarURL());
await interaction.reply({ embeds: [userEmbed]});
}
};
(the cooldown is low because I'm not entirely sure how long to make it yet)
Here is the code for the Fame Schema.
const mongoose = require('mongoose');
const fameSchema = new mongoose.Schema ({
_id: mongoose.Schema.Types.ObjectId,
guildId: String,
memberId: String,
amount: { type: Number, default: 0}
});
module.exports = mongoose.model('Fame', fameSchema, 'fame-points');
and here's the code for the const "user", it's either the user mentioned or if none, the one using the slash command.
const user = interaction.options.getUser("user") || interaction.user;
And here's the createFame function
const Fame = require('../schemas/fame');
const mongoose = require('mongoose');
module.exports = (client) => {
client.createFame = async (member) => {
let fameProfile = await Fame.findOne({ memberId: member.id, guildId: member.guild.id });
if (fameProfile) {
return fameProfile;
} else {
fameProfile = await new Fame({
_id: mongoose.Types.ObjectId(),
guildId: member.guild.id,
memberId: member.id,
});
await fameProfile.save().catch(err => console.log(err));
return fameProfile;
}
};
};
I thought that maybe there was an error in the user const itself or when importing it but I made the bot send a test message using that const and it is getting the user no problem so idk what's wrong.
it shows the error:
TypeError: Cannot read properties of undefined (reading 'id')
at Client.client.createFame (C:\Users\xxx\OneDrive\desktop\bot\src\functions\createFame.js:6:89)
at Object.execute (C:\Users\xxx\OneDrive\desktop\bot\src\buttons\info\yes-fame.js:10:46)
at Object.execute (C:\Users\xxx\OneDrive\desktop\bot\src\events\interactionCreate.js:25:26)
at Client. (C:\Users\xxx\OneDrive\desktop\bot\src\functions\handleEvents.js:8:58)
There is a $inc property/method/wtv in mongoose model. Try this-
await Fame.findOneAndUpdate({ _id: fameProfile._id}, { $inc: { amount: 1 } });

Why can't I use an interaction collector in a slash command?

const { SlashCommandBuilder } = require("#discordjs/builders");
const {
MessageEmbed,
MessageActionRow,
MessageSelectMenu,
} = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("setup")
.setDescription("Setup the bot to your server!"),
async execute(interaction) {
let array = [];
await interaction.guild.members.cache.forEach(async (user) => {
if (user.user.bot === false || user.user.id === "925077132865052702")
return;
array.push({
label: user.user.username,
description: user.id,
value: user.id,
emoji: "<a:right:926857658500251668>",
});
});
let row;
if (array < 5) {
row = new MessageActionRow().addComponents(
new MessageSelectMenu()
.setCustomId("select")
.setMinValues(1)
.setMaxValues(parseInt(array.length))
.setPlaceholder("Nothing selected.")
.addOptions(array)
);
} else {
row = new MessageActionRow().addComponents(
new MessageSelectMenu()
.setCustomId("select")
.setMinValues(1)
.setMaxValues(5)
.setPlaceholder("Nothing selected.")
.addOptions(array)
);
}
let welcome = new MessageEmbed()
.setTitle("UChecker | Setup")
.setDescription(
"Please select from the dropdown below all the bots you would like to be notified for."
)
.setColor("FUCHSIA");
let message = await interaction.reply({
embeds: [welcome],
components: [row],
ephemeral: true,
});
const filter = i => {
return i.user.id === interaction.user.id;
};
await message.awaitMessageComponent({ filter, componentType: 'SELECT_MENU', time: 60000 })
.then(async interaction => await interaction.editReply(`You selected ${interaction.values.join(', ')}!`))
.catch(err => console.log(`No interactions were collected.`));
},
};
Here is my code. As you can see at the bottom I am using awaitMessageComponent and it says an error:
TypeError: Cannot read properties of undefined (reading 'createMessageComponentCollector')
at Object.execute (C:\Users\Owner\Desktop\UChecker\src\setup.js:55:31)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Client.<anonymous> (C:\Users\Owner\Desktop\UChecker\index.js:38:3)
C:\Users\Owner\Desktop\UChecker\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:90
if (this.deferred || this.replied) throw new Error('INTERACTION_ALREADY_REPLIED');
^
Error [INTERACTION_ALREADY_REPLIED]: The reply to this interaction has already been sent or deferred.
at CommandInteraction.reply (C:\Users\Owner\Desktop\UChecker\node_modules\discord.js\src\structures\interfaces\InteractionResponses.js:90:46)
at Client.<anonymous> (C:\Users\Owner\Desktop\UChecker\index.js:41:21)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
[Symbol(code)]: 'INTERACTION_ALREADY_REPLIED'
}
I am confused as I thought you could edit a reply? Could someone please help me out because I am really confused. I have created a reply so then it can be edited by the interaction collector and it says it has already replied.
You have to use CommandInteraction#fetchReply() to retrieve the reply message.
await interaction.reply({
embeds: [welcome],
components: [row],
ephemeral: true,
});
const message = await interaction.fetchReply();
Interaction replies are not returned unless you specify fetchReply: true in the options
let message = await interaction.reply({
embeds: [welcome],
components: [row],
ephemeral: true,
fetchReply: true
})

Discord.js v13, #discordjs/voice Play Music Command

This is my code,
The command executes perfectly, The bot joins the voice channel and also sends the name of the song its about to play, but it doesnt play the song in the voice channel.
This is my first time ever asking a question on stackoverflow so dont mind the format and stuff. But I really need help here.
Discord v13 and latest node module.
const ytsearch = require('yt-search');
const Discord = require('discord.js')
const {
joinVoiceChannel,
createAudioPlayer,
createAudioResource,
NoSubscriberBehavior
} = require('#discordjs/voice');
module.exports = {
name: "play",
description: "test command",
async run(client, message, args) {
const voiceChannel = message.member.voice.channel;
if (!voiceChannel) return message.channel.send('Please connect to a voice channel!');
if (!args.length) return message.channel.send('Please Provide Something To Play!')
const connection = await joinVoiceChannel({
channelId: message.member.voice.channel.id,
guildId: message.guild.id,
adapterCreator: message.guild.voiceAdapterCreator
});
const videoFinder = async (query) => {
const videoResult = await ytsearch(query);
return (videoResult.videos.length > 1) ? videoResult.videos[0] : null;
}
const video = await videoFinder(args.join(' '));
if (video) {
const stream = ytdl(video.url, { filter: 'audioonly' });
const player = createAudioPlayer();
const resource = createAudioResource(stream)
await player.play(resource);
connection.subscribe(player);
await message.reply(`:thumbsup: Now Playing ***${video.title}***`)
} else {
message.channel.send('No video results found');
}
}
}```
I would suggest you look at the music bot example at #discordjs/voice.
They do a good job of how to extract the stream from ytdl.
I'm currently still learning how this all works but the part that you will want to look at is in the createAudioResource function.
public createAudioResource(): Promise<AudioResource<Track>> {
return new Promise((resolve, reject) => {
const process = ytdl(
this.url,
{
o: '-',
q: '',
f: 'bestaudio[ext=webm+acodec=opus+asr=48000]/bestaudio',
r: '100K',
},
{ stdio: ['ignore', 'pipe', 'ignore'] },
);
if (!process.stdout) {
reject(new Error('No stdout'));
return;
}
const stream = process.stdout;
const onError = (error: Error) => {
if (!process.killed) process.kill();
stream.resume();
reject(error);
};
process
.once('spawn', () => {
demuxProbe(stream)
.then((probe) => resolve(createAudioResource(probe.stream, { metadata: this, inputType: probe.type })))
.catch(onError);
})
.catch(onError);
});
}

discord.js image search with pages

is there a way to add pages for this command.
e.g | https://gyazo.com/e6782fc9386f9d15c7cc52dabeb8844e (it can be with reactions or buttons)
const { MessageEmbed } = require("discord.js");
module.exports = {
name: "img",
description: "Search for an image!",
category: "utility",
cooldown: {type: "map", time: 10},
aliases: ["is", "imgsearch"],
run: async (client, message, args) => {
if (!args) client.err(message);
gis(args.join(" "), logResults);
async function logResults(error, results){
if (error)return client.err(message);
let random = Math.floor(Math.random() * results.length);
let image = results[random].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
return message.reply(embed);
}
}
}
The easiest solution would be to add two reactions '⬅️, ➡️', and await till user reacts with one of them. (working with reactions is nicely described here)
Your code would look like this:
const { MessageEmbed } = require("discord.js");
module.exports = {
name: "img",
description: "Search for an image!",
category: "utility",
cooldown: {type: "map", time: 10},
aliases: ["is", "imgsearch"],
run: async (client, message, args) => {
if (!args) client.err(message);
gis(args.join(" "), logResults);
async function logResults(error, results){
if (error)return client.err(message);
let random = Math.floor(Math.random() * results.length);
let image = results[random].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
// Awaiting till the message gets sent so we can add reactions & await users to react
const msg = await message.reply(embed);
// Adding reactions
await msg.react('⬅️');
await msg.react('➡️');
// Create a filter so only when original author reacts with ⬅️ or ➡️ the message is edited.
const filter = (reaction, user) => {
return ['⬅️', '➡️'].includes(reaction.emoji.name) && user.id === message.author.id;
};
// Await until user reacts
message.awaitReactions(filter, { max: 1, time: 60000, errors: ['time'] })
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '⬅️') {
await msg.reactions.removeAll();
let image = results[random-1].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
msg.edit(embed);
} else {
await msg.reactions.removeAll();
let image = results[random+1].url
const embed = new MessageEmbed()
.setImage(image)
.setColor("#2f3136");
msg.edit(embed);
}
})
.catch(collected => {
message.reply('Your time to open next or previous image expired!');
});
}
}
}

Resources