I'm trying to make my bot to send a message when someone is disconnected. That contains the one who got disconnected and the one who disconnected them.
But when I run the bot and disconnect someone nothing is happening.
Here is my code:
client.on("voiceStateUpdate", function (oldMember, newMember) {
let newUserChannel = newMember.voiceChannel
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();
const { executor } = disconnectLog;
client.channels.cache.get("828731501016252417").send(`<#${executor.id}> Disconnected <#${oldMember.id}>`)
}
});
The reason nothing is happening is because the client.voiceStateUpdate event now emits oldState and newState representing the VoiceStates of the member instead of the member itself. It's changed in discord.js v12. As the VoiceState doesn't have a voiceChannel property, your newUserChannel will be undefined.
Your if statement (if (newUserChannel === null)) will always be false, as undefined is not strictly equal to null, so nothing inside it will get executed.
You could check if newVoiceState.channel is null instead. You should also check if the bot has the required VIEW_AUDIT_LOG permission before you try to fetch the logs. You also missed the async keyword in front of your callback function, you can only use await inside async functions.
Check the code below, it should work as expected.
client.on('voiceStateUpdate', async (oldVoiceState, newVoiceState) => {
// User leaves a voice channel
if (newVoiceState.channel === null) {
// check if the bot can view audit logs
if (!oldVoiceState.guild.me.hasPermission('VIEW_AUDIT_LOG'))
return console.log('Missing permission: "VIEW_AUDIT_LOG"');
const fetchedLogs = await oldVoiceState.guild.fetchAuditLogs({
limit: 1,
type: 'MEMBER_DISCONNECT',
});
const { executor } = fetchedLogs.entries.first();
client.channels.cache
.get('828731501016252417')
.send(`${executor} disconnected ${oldVoiceState.member}.`);
}
});
PS: The current function sends the last entry every time someone leaves a voice channel, even if they left on their own will. I think, MEMBER_DISCONNECT will only be logged when someone else kicked the member from the channel. You need to verify somehow if the last log entry is the same as the current voiceStateUpdate.
voiceStateUpdate event has VoiceState type parameters, not members.
client.on("voiceStateUpdate", function (oldVoiceState, newVoiceState) {
let newUserChannel = newVoiceState.channel
if (newUserChannel === null) {
// User leaves a voice channel
const fetchedLogs = await (oldVoiceState, newVoiceState).guild.fetchAuditLogs({
limit: 1,
type: 'MEMBER_DISCONNECT',
});
const disconnectLog = fetchedLogs.entries.first();
const { executor } = disconnectLog.executor;
client.channels.cache.get("828731501016252417").send(`<#${executor.id}> Disconnected <#${oldVoiceState.id}>`)
}
});
Related
I've been working on this code for a discord bot that tracks a the voice channels of a server until a specific person joins which then the bot joins and then plays an audio. However whenever I start up my file, it keeps on saying
[nodemon] starting `node index.js`
[nodemon] clean exit - waiting for changes before restart
I have no clue why, I've looked online and I haven't seen any other people having the same issue as me, and if they did the answer didn't help.
Here is my code.
const { Client, GatewayIntentBits } = require('discord.js');
const { Lavalink } = require('discord.js-lavalink');
class MyBot {
// The Discord.js client object that represents our bot
client;
// The ID of the specific person we want to track
userIdToTrack;
// The audio file to play when the specific person joins
audioFile;
constructor(client, userIdToTrack, audioFile) {
// Save the client object and user ID and audio file for later use
this.client = "[bot token]";
this.userIdToTrack = '[discord id]';
this.audioFile = '[file name]';
}
onGuildVoiceJoin(event) {
// Get the member who just joined the voice channel
const member = event.member;
// If the member is the specific person we want to track...
if (member.id === this.userIdToTrack) {
// Get the voice channel that the member joined
const voiceChannel = event.channel;
// Join the voice channel with the bot
voiceChannel.guild.voice.channel.join();
// Play the audio file using Lavalink
lavalink.play(voiceChannel, {
track: '[file name]',
});
const client = new Client({
token: 'bot token]',
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildVoiceStates,
GatewayIntentBits.GuildPresences,
],
});
// Create a new instance of the Lavalink class and connect to the Lavalink nodes
const lavalink = new Lavalink({
client: client,
nodes: [
{ host: 'ratio-w', port: 2334, password: 'youshallnotpass' },
],
});
lavalink.connect();
client.on('ready', () => {
console.log('The bot is ready');
// Create a new instance of the bot, passing in the client object, user ID, and audio file
const bot = new MyBot("bot token", "user id", "file name");
// Listen for voice state update events, which are triggered when a user joins or leaves a voice channel
client.on('voiceStateUpdate', (oldState, newState) => {
// Check if the user we want to track has just joined a voice channel
if (newState.member.id === userIdToTrack && newState.channel) {
// Get the voice channel the user joined
const voiceChannel = newState.channel;
// Join the voice channel with the bot
voiceChannel.join().then(connection => {
// Play the audio file using Lavalink
lavalink.play(voiceChannel, {
track: audioFile,
});
});
}
});
client.on('messageCreate', message => {
if (message.content === 'ping') {
message.reply('hey <#user id>, you STINK!!!!111!');
}
});
client.on('messageCreate', message => {
if (message.content === 'shut up [redacted]') {
message.reply('yeah <#user id> shut up smelly');
}
});
client.on('messageCreate', message => {
if (message.content === 'stop being a nerd [redacted]') {
message.reply('<#user id> be like :nerd:');
}
});
});
process.on('unhandledRejection', (reason, promise) => {
console.log('Unhandled Rejection at:', reason.stack || reason)
// Recommended: send the information to sentry.io
// or whatever crash reporting service you use
})
client.login('[bot id]');}}}
I tried fixing any possible syntax errors, I've tried looking online but no help was found, I've properly started lavalink (I think), I've edited some of the code so that all possible parts are fixed. I've downloaded all possible directories like updating discord.js, node.js, lavalink.js, and more I think.
I am currently developing a Discord bot and I am trying to add a kind of menu as the bot is supposed to be a guide for a game.
To make that work I am trying to add bot messages after reacting to the prior message.
I am testing it on a test message and the bot is supposed to send Test1 if a user reacts with 👍
After reacting, the bot simply does nothing. It doesn't crash nor does it send the intended message.
My code:
case 'Testembed': //Testembed mit Reactions
message.channel.send({embeds: [Testembed.de.data]}).then((question) => {
question.react('🙃')
question.react('👍')
const filter = (reaction, user) => {
return ['👍','🙃'].includes(reaction.emoji.name) && !user.bot;
};
const collector = question.createReactionCollector(filter, { //<-- Here it stops working
max: 1,
time: 15000
});
collector.on('end', (collected, reason) => {
if (reason === 'time') {
message.channel.send('Ran out of time...');
} else {
let userReaction = collected.array()[0];
let emoji = userReaction._emoji.name;
if (emoji === '👍'){
message.channel.send('Test1');
} else if (emoji === '🙃') {
message.channel.send('Test2');
} else {
message.channel.send("I don't understand ${emoji}...");
}
}
});
});
break;
Edit: Bot now throws new error:
throw er; // Unhandled 'error' event
^
TypeError: collected.array is not a function
In discord.js#14.x.x, the method to create a reaction collector changed. Now, the collector would only take one argument and the filter variable would have to be passed in the object. An example would look like this:
const filter = (reaction, user) => {
return ['👍','🙃'].includes(reaction.emoji.name) && !user.bot;
};
const collector = question.createReactionCollector({
max: 1,
time: 15000,
filter
});
const { Client, Intents } = require("discord.js");
const client = new Client({
intents: ["DIRECT_MESSAGES", "GUILDS", "GUILD_MEMBERS"],
presence: {
status: "online",
activities: [{
name: "markets",
type: "WATCHING"
}]
},
});
client.on('ready', () => {
console.log(`Launched as a bot: ${client.user.tag}!`);
});
client.on('guildMemberAdd', member => {
function roleAdd() {
member.roles.add(member.guild.roles.cache.get(process.env.SERVER_ROLE_ID));
}
roleAdd();
});
client.login(process.env.DJS_TOKEN);
Guys I wrote this code but it is not working. I am not getting any errors. I want it to add a role whenever a user joins to my server. the status of the bot is working. I think the issue is on the guildMemberAdd part.
Im not quite sure why you're using the approach of nested functions for this. If you want the event to call the function move the function outside of the event and then create the GuildMember in a parameter.
Or discard the event entirely and leave the plain #<GuildMemberRoleManager>.add method by itself.
I suggest the latter as I assume the nested function declaration wont work.
If you wanted to use auto role add for your server, try the easiest method to do the role add, same way as giving role to a member
When you giving a role to specific member should look like this:
const role = message.guild.roles.cache.find(role => role.id === process.env.SERVER_ROLE_ID)
const target = message.mentions.members.first() || await message.guild.members.cache.get(args[0])
If a bot giving a role higher than the bot or equal to bot. You will get an error such as Missing Permissions To prevent this you need to put a code to return it
if(!target.moderatable) return message.reply("I can't mute this person!")
This command is a same way for auto give role, just a few code lines added/edited/removed.
client.on('guildMemberAdd', member => {
function roleAdd() {
member.roles.add(member.guild.roles.cache.get(process.env.SERVER_ROLE_ID));
}
roleAdd();
});
- function roleAdd() {}
+ let role = member.guild.roles.cache.find(role => role.id == process.env.SERVER_ROLE_ID)
+ member.roles.add(role).catch()
The .catch() line is to prevent on giving error and shutdown your bot.
client.on('guildMemberAdd', member => {
let role = member.guild.roles.cache.find(role => role.id == process.env.SERVER_ROLE_ID)
member.roles.add(role).catch()
});
I would like to convert this so that people just need to react and the application gets sent to them, I have no clue on how to do message on react stuff so if anyone could help me out it will be greatly appreciated.
Two very helpful people have helped me
#Skulaurun Mrusal
and
#PerplexingParadox
Thank you! 🙂
client.on("message", async (message) => {
// Don't reply to bots
if (message.author.bot) return;
if (message.content == "#req") {
if(!message.member.hasPermission("MANAGE_MESSAGES"))
{
message.reply("You do not have permission to do that!");
return;
}
// Perform raw API request and send a message with a button,
// since it isn't supported natively in discord.js v12
client.api.channels(message.channel.id).messages.post({
data: {
embeds: [reqEmbed],
components: [
{
type: 1,
components: [
{
type: 2,
style: 4,
label: "Apply",
// Our button id, we can use that later to identify,
// that the user has clicked this specific button
custom_id: "send_application"
}
]
}
]
}
});
}
});
// Channel id where the application will be sent
const applicationChannelId = "652099170835890177";
// Our questions the bot will ask the user
const questions = [
"What is your In-Game Username?",
"How long have you been drifting on FiveM?",
"Do you use Controller or Keyboard?",
"How much do you play weekly?",
"Have you been in any other teams? If so, why did you leave?",
"Short description about yourself and why you would like to be apart of Blind Spot? (Age, Country)"
];
// Function that will ask a GuildMember a question and returns a reply
async function askQuestion(member, question) {
const message = await member.send(question);
const reply = await message.channel.awaitMessages((m) => {
return m.author.id === member.id;
}, { time: 5 * 60000, max: 1 });
return reply.first();
}
client.ws.on("INTERACTION_CREATE", async (interaction) => {
// If component type is a button
if (interaction.data.component_type === 2) {
const guildId = interaction.guild_id;
const userId = interaction.member.user.id;
const buttonId = interaction.data.custom_id;
const member = client.guilds.resolve(guildId).member(userId);
if (buttonId == "send_application") {
// Reply to an interaction, so we don't get "This interaction failed" error
client.api.interactions(interaction.id, interaction.token).callback.post({
data: {
type: 4,
data: {
content: "I have started the application process in your DM's.",
flags: 64 // make the message ephemeral
}
}
});
try {
// Create our application, we will fill it later
const application = new MessageEmbed()
.setTitle("New Application")
.setDescription(`This application was submitted by ${member.user.tag}`)
.setColor("#ED4245");
const cancel = () => member.send("Your application has been canceled.\n**If you would like to start your application again Click on the Apply button in** <#657393981851697153>");
// Ask the user if he wants to continue
const reply = await askQuestion(member,
"Please fill in this form so we can proceed with your tryout.\n" +
"**Type `yes` to continue or type `cancel` to cancel.**"
);
// If not cancel the process
if (reply.content.toLowerCase() != "yes") {
cancel(); return;
}
// Ask the user questions one by one and add them to application
for (const question of questions) {
const reply = await askQuestion(member, question);
// The user can cancel the process anytime he wants
if (reply.content.toLowerCase() == "cancel") {
cancel(); return;
}
application.addField(question, reply);
}
await askQuestion(member,
"Do you want your application to be submitted?\n" +
"**Type `yes` to get your Application submitted and reviewed by Staff Members**"
);
// If not cancel the process
if (reply.content.toLowerCase() != "yes") {
cancel(); return;
}
// Send the filled application to the application channel
client.channels.cache.get(applicationChannelId).send(application);
} catch {
// If the user took too long to respond an error will be thrown,
// we can handle that case here.
member.send(
"You took too long to respond or Something went wrong, Please contact a Staff member\n" +
"The process was canceled."
);
}
}
}
});
You could use Client's messageReactionAdd event.
client.on("messageReactionAdd", (reaction, user) => {
if (!reaction.emoji.name === "👌") return;
// Check if the message is the right message we want users to react to
// Obviously you need to enable partials for this to work
if (reaction.message.id != "...") return;
const member = reaction.message.guild.member(user);
member.send("Here's your form!");
// ... Rest of your code ...
});
Note that this won't work for reactions cast on messages sent before the bot was started. The solution is to enable Partial Structures. (If you are dealing with partial data, don't forget to fetch.)
Or create a ReactionCollector using Message.createReactionCollector().
// ... The variable message defined somewhere ...
const collector = message.createReactionCollector((reaction, user) => {
return reaction.emoji.name === "👌";
});
collector.on("collect", (reaction, user) => {
const member = message.guild.member(user);
member.send("Here's your form!");
// ... Rest of your code ...
});
Maybe it would be better to use buttons in this case instead of reactions. To create a message with a button you could perform a raw API request or use third party library like discord-buttons. The solution below is for discord.js v12.
client.on("message", async (message) => {
// Don't reply to bots
if (message.author.bot) return;
if (message.content == "#createButton") {
// Perform raw API request and send a message with a button,
// since it isn't supported natively in discord.js v12
client.api.channels(message.channel.id).messages.post({
data: {
content: "If you want to apply, click the button below.",
components: [
{
type: 1,
components: [
{
type: 2,
style: 1,
label: "Apply",
// Our button id, we can use that later to identify,
// that the user has clicked this specific button
custom_id: "send_application"
}
]
}
]
}
});
}
});
And then we need to listen for an event INTERACTION_CREATE indicating that the user has clicked our button. (Or some other interaction triggered the event, for example a slash command.)
// Channel id where the application will be sent
const applicationChannelId = "871527842180132895";
// Our questions the bot will ask the user
const questions = [
"What is your In-Game Username?",
"How long have you been drifting on FiveM?",
"Do you use Controller or Keyboard?",
"How much do you play weekly?",
"Have you been in any other teams? If so, why did you leave?",
"Short description about yourself and why you would like to be apart of Blind Spot? (Age, Country)"
];
// Function that will ask a GuildMember a question and returns a reply
async function askQuestion(member, question) {
const message = await member.send(question);
const reply = await message.channel.awaitMessages((m) => {
return m.author.id === member.id;
}, { time: 5 * 60000, max: 1 });
return reply.first();
}
client.ws.on("INTERACTION_CREATE", async (interaction) => {
// If component type is a button
if (interaction.data.component_type === 2) {
const guildId = interaction.guild_id;
const userId = interaction.member.user.id;
const buttonId = interaction.data.custom_id;
const member = client.guilds.resolve(guildId).member(userId);
if (buttonId == "send_application") {
// Reply to an interaction, so we don't get "This interaction failed" error
client.api.interactions(interaction.id, interaction.token).callback.post({
data: {
type: 4,
data: {
content: "I have started the application process in your DM's.",
flags: 64 // make the message ephemeral
}
}
});
try {
// Create our application, we will fill it later
const application = new Discord.MessageEmbed()
.setTitle("New Application")
.setDescription(`This application was submitted by ${member.user.tag}`)
.setColor("#ED4245");
const cancel = () => member.send("Ok, I have cancelled this process.");
// Ask the user if he wants to continue
const reply = await askQuestion(member,
"Please fill in this form so we can proceed with your tryout.\n" +
"**Type `yes` to continue or type `cancel` to cancel.**"
);
// If not cancel the process
if (reply.content.toLowerCase() != "yes") {
cancel(); return;
}
// Ask the user questions one by one and add them to application
for (const question of questions) {
const reply = await askQuestion(member, question);
// The user can cancel the process anytime he wants
if (reply.content.toLowerCase() == "cancel") {
cancel(); return;
}
application.addField(question, reply);
}
// Send the filled application to the application channel
client.channels.cache.get(applicationChannelId).send(application);
} catch {
// If the user took too long to respond an error will be thrown,
// we can handle that case here.
member.send(
"Something went wrong or you took too long to respond.\n" +
"The process was cancelled."
);
}
}
}
});
I am making a discord bot that is being activated by voice recognition, im at the very beginning right now im making him join a voice channel (which is working), and im trying to make a command to make him leave.
const commando = require('discord.js-commando');
class LeaveChannelCommand extends commando.Command
{
constructor(client){!
super(client,{
name: 'leave',
group: 'music',
memberName: 'leave',
description: 'leaves a voice channel'
});
}
async run(message, args)
{
if(message.guild.voiceConnection)
{
message.guild.voiceConnection.disconnect();
}
else
{
message.channel.sendMessage("seccessfully left")
}
}
}
module.exports = LeaveChannelCommand;
right now you can type !leave from anywhere in the server and the bot leaves,
i want to make it possible to control him only from the same voice channel,
what should i do
It's fairly easy to do. All you need to do is grab the bot's voiceChannel and the user's voiceChannel (if he is in one) and check if they are the same.
Below you can find some example code. Give it a try and let me know how it goes.
async run(message, args)
{
// If the client isn't in a voiceChannel, don't execute any other code
if(!message.guild.voiceConnection)
{
return;
}
// Get the user's voiceChannel (if he is in one)
let userVoiceChannel = message.member.voiceChannel;
// Return from the code if the user isn't in a voiceChannel
if (!userVoiceChannel) {
return;
}
// Get the client's voiceConnection
let clientVoiceConnection = message.guild.voiceConnection;
// Compare the voiceChannels
if (userVoiceChannel === clientVoiceConnection.channel) {
// The client and user are in the same voiceChannel, the client can disconnect
clientVoiceConnection.disconnect();
message.channel.send('Client has disconnected!');
} else {
// The client and user are NOT in the same voiceChannel
message.channel.send('You can only execute this command if you share the same voiceChannel as the client!');
}
}