Bot plays same audio for joining and leaving the channel - javascript

my Bot is playing the same audio File for joining and leaving the Voice Channel and i dont know how to solve it:
client.on('voiceStateUpdate', (oldMember, newMember) => {
let newUserChannel = newMember.voiceChannel
let oldUserChannel = oldMember.voiceChannel
const voiceChannel = client.channels.cache.get('807305239941480543')
if(oldUserChannel === undefined && newUserChannel !== undefined && oldMember.member.user.bot === false && newMember.member.user.bot === false) {
voiceChannel.join().then(connection => { connection.play("./a.mp3").on("finish", () => connection.disconnect())
});
} else if(newUserChannel === undefined && oldMember.member.user.bot === false && newMember.member.user.bot === false){
voiceChannel.join().then(connection => { connection.play("./b.mp3").on("finish", () => connection.disconnect())
});
}
})
I dont get any error and the Bot works but the Bot is playing the audio file ./b.mp3 everytime and not the audio ./a.mp3.
Thanks!

You are already on the right track but you're overthinking the if statement.
First off, when the voiceStateUpdate event is triggered, the parameters available are voiceStates so we'll use oldState and newState in this code.
You have the right idea when you check if the user is a bot but you can do that in a separate check.
if (oldState.member.user.bot) return;
Now that we know a user is joining/leaving we can differentiate, however we need to check three cases:
a user joins a new channel, here case A
a user leaves a channel, here case B
a user switches channels, here case C
A joining is indicated if oldState.channelID is either null or undefined.
oldState.channelID === null || typeof oldState.channelID == 'undefined'
A leaving is indicated if newState.channelID is either null or undefined.
newState.channelID === null || typeof newState.channelID == 'undefined'
A switching is indicated if neither of the above fit which we simply cover with else.
Since I don't have your MP3 files I simply console.log() a "PLAYING (A/B/C)" which you need to switch out for your audiofiles.
The entire voiceStateUpdate looks like this:
client.on('voiceStateUpdate', (oldState, newState) => {
if (oldState.member.user.bot) return;
const voiceChannel = client.channels.cache.get('807305239941480543');
if (oldState.channelID === null || typeof oldState.channelID == 'undefined') {
voiceChannel.join().then(connection => {
console.log("PLAYING (A)");
connection.disconnect();
});
} else if (newState.channelID === null || typeof newState.channelID == 'undefined') {
voiceChannel.join().then(connection => {
console.log("PLAYING (B)");
connection.disconnect();
});
} else {
voiceChannel.join().then(connection => {
console.log("PLAYING (C)");
connection.disconnect();
});
}
})
;

Related

Discord JS category and returning ID

I'm trying to check (and create, if it does not exist) the checking process works fine.
Here is a copy of my code:
var bb_admin='0';
//Check if admin_logs exists if not create it
if(message.guild.channels.cache.find(channel => channel.name === "admin_logs") === undefined && typeof message.guild.channels.cache.find(channel => channel.name === "admin_logs") == 'undefined')
{
console.log("creating");
bb_admin = message.guild.channels.create('admin_logs', {parent: bb_cat});
} else {
console.log("already exists");
bb_admin = message.guild.channels.cache.find(channel => channel.name === "admin_logs");}
console.log('bb_admin after',bb_admin);
The problem which I'm having is I need to be able to assign the channel ID to a variable once it is created before moving on.
I cannot use a .then statement as the next steps has to happen outside of this. (I'm cycling a log file and populating the row into a channel based on contents).
What appears to be happening is I'm getting a promise back, however when I change this line:
bb_admin = message.guild.channels.create('admin_logs', {parent: bb_cat})
to:
bb_admin = await message.guild.channels.create('admin_logs', {parent: bb_cat})
to wait for the response I'm given the following error message: SyntaxError: await is only valid in async functions and the top level bodies of modules
I've seen this question which seems pretty much the same as what I'm trying to achieve. but even running attempt 2 presented with the error: TypeError: Cannot read property 'create' of undefined
Any pointers where I am going wrong here, I've been going around in circles for a few days now.
Edit: Very Basic Example:
/**
* #file app.js
* #description BeerBot
* #author Beer
* #version 0.0.1
*/
// Require all needed packages and files
const { Client, MessageEmbed } = require('discord.js');
const config = require('./config.json');
const client = new Client();
// Ready event
client.on('ready', () => {
// Log when bot is ready
console.log(`${client.user.tag} is online!`);
});
// Message event
client.on('message', message => {
if (message.author.bot || !message.guild) return;
if (!message.content.startsWith("!")) return;
//Try a simple category created command
var bb_cat = message.guild.channels.cache.find(channel => channel.name === "BeerBot");
var bb_admin = 0;
//Check if admin_logs exists if not create it
if(message.guild.channels.cache.find(channel => channel.name === "admin_logs") === undefined && typeof message.guild.channels.cache.find(channel => channel.name === "admin_logs") == 'undefined')
{
//Try and create channel
console.log("creating");
bb_admin = message.guild.channels.create('admin_logs', {parent: bb_cat});
//End try and create channel
} else {
console.log("already exists");
bb_admin = await message.guild.channels.cache.find(channel => channel.name === "admin_logs");
}
//This always returns a promise
console.log('bb_admin after',bb_admin);
});
// Login into your bot with the bot token
client.login(config.client.token);
Instead of creating an async IIFE as #Viriato suggested, you should turn your current callback to an async function like in my example below.
Also, you should use a variable if you're calling message.guild.channels.cache.find() three times :) And you don't need to check if the find() method returned undefined or checking its typeof. You can simply check if the returned value is truthy.
// make the callback function async
client.on('message', async (message) => {
if (message.author.bot || !message.guild) return;
if (!message.content.startsWith('!')) return;
let adminLogsChannel = message.guild.channels.cache.find(
(channel) => channel.name === 'admin_logs',
);
// if admin_logs does not exist, create it
if (!adminLogsChannel) {
let parent = message.guild.channels.cache.find(
(channel) => channel.name === 'BeerBot',
);
adminLogsChannel = await message.guild.channels.create('admin_logs', { parent });
}
// this returns a GuildChannel now
console.log('adminLogsChannel after', adminLogsChannel);
});

reaction a only first message in "if"

client.on('message', message => {
if (message.channel.type === 'text' && message.channel.name.toLowerCase() == "channel-2" && message.content === "test")
{
message.react("✅")
}
})
this is the code, is there any way for it to react to just the first message? for example: if 5 people send "test" on the same channel, I wanted her to react only to the first, ignoring the other 4
Just call .off with the handler when you react:
client.on('message', function handler(message) {
if (message.channel.type === 'text' && message.channel.name.toLowerCase() == "channel-2" && message.content === "test") {
message.react("✅");
client.off('message', handler);
}
});

Discord.js counting system

so I was trying to make my own version of a counting system for my server like how other bots such as countr do it, so I made the following:
if (message.channel.id === "794733520458612736") {
const numdb = db.get("numdb");
if (message.content === numdb) {
db.add("numdb", 1);
message.react("✅");
} else if (typeof message.content === "number") {
db.set("numdb", 1);
message.channel.send(`${message.author} ruined it at **${numdb}**! The next number is **1**.`);
message.react("❌");
};
};
Yet, when I try it, it doesn't seem to work. Does anyone know what I am doing wrong?
Alright, I solved it as shown below:
if (message.channel.id === "794733520458612736") {
const numdb = db.get("numdb");
if (message.content == `${numdb}`) {
db.add("numdb", 1);
message.react("✅");
} else if (!isNaN(message.content) && message.content != `${numdb}`) {
db.set("numdb", 1);
message.channel.send(`${message.author} ruined it at **${numdb-1}**! The next number is **1**.`);
message.react("❌");
};
};
I figured out that the reason was because === checks both value and type (credit to Zsolt) and the old method I used to check if it was a number didn't work, so I switched it to isNaN.

javascript how to fill a return from values of array

I don't know how to formule the question(title), so I'll just say it here, and maybe someone may help or provide a new point of view about it.
I'm working with discord.js and I want to check if user has a role/roles from a message
client.on('message', message => {
if (message.member.roles.find(r => r.name === 'ADMIN')) {
console.log('I am admin');
}
});
Now my idea is to make this a polymorphism functions, because if I want to check two roles I have to do this:
client.on('message', message => {
if (message.member.roles.find(r => r.name === 'ADMIN') || message.member.roles.find(r => r.name === 'Other')) {
console.log('I am admin');
}
});
And I would like to move this if condition to a function and it will check it even if I want to check one or more `permissions.
For now I have tried to deal with it, but nothing, and stopped here... Maybe someone can give me some advice or other point of view. The idea is to prevent duplicate code and an if as long as the width of my monitor.
function hasRole(msg, permissions, condition = 'or') {
if (Array.isArray(permission)) {
if (condition === 'or') {
permissions.forEach(function (element) {
});
// permission.join('||');
return msg.member.roles.find(r => r.name === permissions) ||
msg.member.roles.find(r => r.name === permissions);
} else if (condition === 'and') {
}
}
return msg.member.roles.find(r => r.name === permissions);
}
If you want to check DiscordJS DOCS.
Response:
function checkPermissions(msg, permissions, condition = 'or') {
if (condition === 'or') {
return msg.member.roles.some(r => permissions.includes(r.name));
} else if (condition === 'and') {
return msg.member.roles.every(r => permissions.includes(r.name));
}
}
Something like this?
function hasRole(msg, permissions, condition = 'or') {
//harmonise #permissions to array, if isn't already one
permissions = Array.isArray(permissions) ? permissions : [permissions];
//if or, at least 1 member role must be present in #permissions
if (condition === 'or')
return msg.member.roles.some(role => permissions.includes(role));
//if and, all member roles must be found in #permissions
else
return permissions.every(perm => msg.member.roles.includes(perm));
}
function checkPermissions(msg, permissions, condition = 'or') {
if (Array.isArray(permissions)) {
if (condition === 'or') {
return msg.member.roles.some(r => permissions.includes(r.name));
} else if (condition === 'and') {
let value = false;
permissions.forEach(permission => {
value = !!msg.member.roles.find(r => r.name === permission);
});
return value;
}
}
return !!msg.member.roles.find(r => r.name === permissions);
}

I am trying to show roles in my !!userinfo command but I get errors

I have a !!userinfo command and I am trying to get it to where I can #anyone and it shows there info how I have everything else working but then I came up to this problem here is the error.
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'map' of undefined
I have looked it up no answer, but I did come up with something it said that it usually means that is unpopulated but I don't know how to get it in there.
const Discord = module.require("discord.js");
const fs = require("fs");
const userdata = JSON.parse(fs.readFileSync('commands/storage/userdata.json', 'utf8'));
module.exports.run = async (bot, message, args) => {
let member;
if (message.mentions.users > 0) {
member = message.mentions.user.size()
} else {
member = message.author
}
let user;
if (message.mentions.users > 0) {
user = message.mentions.user.size()
} else {
user = message.author
}
embed = new Discord.RichEmbed()
.setAuthor(message.member.username)
.setDescription("Users Info", true)
.setColor("#64FF00", true)
.addField("Full Username:", `${message.member.username}${message.member.discriminator}`, true)
.addField("ID:", message.member.id, true)
.addField("Created at:", message.member.createdAt, true)
.addField("Status:", `${user.presence.status}`, true)
.addField("Game:", `${user.presence.game}`, true)
.addField("Roles", member.roles.map(r => `${r}`).join('|'), true);
message.channel.send(embed);
}
module.exports.help = {
name: "userinfo"
}
I Would like it so I can #anyone and there info comes up
You can easily make the first part:
let member;
if (message.mentions.users > 0) {
member = message.mentions.user.size()
} else {
member = message.author
}
let user;
if (message.mentions.users > 0) {
user = message.mentions.user.size()
} else {
user = message.author
}
into:
const user = message.mentions.users.first() || message.author;
const member = message.mentions.members.first() || message.member;
if(!member) return message.channel.send('This command can only be run in a guild!')
Also you want to change the embed bit to:
let embed = new Discord.RichEmbed()
.setAuthor(user.tag)
.setDescription("Users Info", true)
.setColor("#64FF00", true)
.addField("Full Username:", user.tag , true)
.addField("ID:", user.id, true)
.addField("Created at:", user.createdAt, true)
.addField("Status:", user.presence.status , true)
.addField("Game:", user.presence.game ? user.presence.game : 'none' , true)
.addField("Roles", member.roles.map(r => `${r}`).join(' | '), true);
message.channel.send(embed);
I believe the problem lies with how you assign a value to the variable member. Adding to that, I think you have some redundant code since you have a variable member and a variable user which you give a value with the same code.
Below you can find your code which I've rewritten. Give it a go and let me know what the result is.
module.exports.run = async (bot, message, args) => {
let guildMember;
if (message.mentions.members.first()) {
guildMember = message.mentions.members.first();
} else {
guildMember = message.member;
}
// We need the User object aswell for different properties
const user = guildMember.user;
let embed = new Discord.RichEmbed()
.setAuthor(user.username)
.setDescription("Users Info", true)
.setColor("#64FF00", true)
.addField("Full Username:", `${user.username}${user.discriminator}`, true)
.addField("ID:", user.id, true)
.addField("Created at:", user.createdAt, true)
.addField("Status:", `${user.presence.status}`, true)
.addField("Game:", `${user.presence.game}`, true)
.addField("Roles", guildMember.roles.map(r => `${r}`).join('|'), true);
message.channel.send(embed);
}
This sets member to a number
member = message.mentions.user.size()
Since member is now a number, trying to access member.roles results in undefined. And since undefined does not have a .map method, you see that exception.

Categories