I am trying to build a bot with the discord.js library in node.js that will create a new voice channel in a certain category when a user joins a certain channel. After the creation of the channel, I want the bot to then move the user to the new channel!
I am trying the following code:
var temporary = [];
client.on('voiceStateUpdate', async (oldMember, newMember) => {
const mainCatagory = '815281015207624704';
const mainChannel = '814938402137833484';
if (newMember.voiceChannelID == mainChannel) {
await newMember.guild
.createChannel(`📞 ┋ Support Room`, { type: 'voice', parent: mainCatagory })
.then(async (channel) => {
temporary.push({ newID: channel.id, guild: newMember.guild.id });
await newMember.setVoiceChannel(channel.id);
});
}
if (temporary.length >= 0)
for (let i = 0; i < temporary.length; i++) {
let ch = client.guilds
.find((x) => x.id === temporary[i].guild)
.channels.find((x) => x.id === temporary[i].newID);
if (ch.members.size <= 0) {
await ch.delete();
return temporary.splice(i, 1);
}
}
});
The code comes with no error but doesn't create the voice channel!
The problem is that you are using discord.js v12, but your code is made for v11.
Client#voiceStateUpdate now passes VoiceStates as parameters, not GuildMembers. You should rename newMember and oldMember to newState and oldState respectively.
GuildMember#voiceChannelID is a deprecated property, which is why you don't get any errors. Your code never actually gets past the if statement. It has turned into GuildMember#voice#channelID (newState.channelID).
Guild#createChannel is also deprecated, being replaced with Guild#channels#create. The function still looks and acts the same, so you only need to change the name (newState.guild.channels.create).
GuildMember#setVoiceChannel has turned into GuildMember#voice#setChannel (newState.setChannel)
Client#guilds#find has turned into Client#guilds#cache#find (client.guilds.cache.find)
Guild#channels#find has turned into Guild#channels#cache#find (client.cache.find(...).channels.cache.find)
(As a side note, always use Collection#get instead of Collection#find when searching by IDs. .find((value) => value.id === '...') should always be converted to simply .get('...'). This also applies to switching Collection#some with Collection#has)
Guild#members#size has turned into Guild#members#cache#size (ch.members.cache.size)
Every single one of these deprecations occurred as a result of discord.js switching to a Manager/caching system. For example, Client#guilds now returns a GuildManager instead of a collection.
More information about switching from v11 to v12 (including Managers)
Related
I'm trying to make a joke command with my friends to ban people who are playing Roblox or if he has the Roblox game status. I've searched everything in the internet and in stack overflow if there's a solution but I can't find a single working one. Here's my code:
module.exports = async (client) => {
const guild = client.guilds.cache.get('877016354581004389');
if(guild){
setInterval(async () => {
if(!guild.me.permissions.has('ADMINISTRATOR')) return;
const channel = guild.channels.cache.get('877016354581004392');
if(!channel) return console.log('ANNOUNCEMENT CHANNEL NOT FOUND...')
let bannedAmount = 0;
await guild.members.fetch().then(members => {
members.forEach(member => {
for(const allMember of Object.keys(member)){
if(allMember.user.presence.activities){
const activity = allMember.user.presence.activities[0]
if(activity.name.toLowerCase() == "roblox"){
channel.send(`${allMember} got banned because he's playing ROBLOX!!`)
allMember.ban({ reason: `he played roblox lol`});
bannedAmount = bannedAmount + 1
break;
}
}
}
})
});
let members;
if(bannedAmount > 1) members = 'members';
let kid;
if(bannedAmount > 1) kid = 'kids';
if(bannedAmount <= 0 || null){
console.log(`No member banned for playing Roblox...`);
} else if(bannedAmount > 0) {
channel.send(`${bannedAmount} ${kid || 'kid'} got banned in this server for playing Roblox. Don't do it kids!`)
console.log(`${bannedAmount} ${members || 'member'} got banned for playing Roblox...`)
}
}, 20000);
}
}
I have no hate with the game Roblox guys just fooling around lol
PS: I have already enabled intents in both discord dev website and also in the index.js file and also had used <member>.presence.activities but it looks like only user has presence property.
Well, the problem is that GuildMember#presence returns or a Presence class OR undefined, because it's an optional property. What you do in your code is taking the presence property of a user who probably doesn't has any presence and that's why allMember.user.presence returns undefined and allMember.user.presence.activities[0] too. Also keep in mind that you take the User of a member, but presences go on GuildMembers and not on Users.
Debugging:
Just use allMember instead of allMember.user, so u take the presence of a GuildMember instead of a User, after this a Member who has a presence will return the presence data too.
Add a if statement that controls if a member has a presence or not, so you don't run in the same error again.
I don't know if you tought about this, but if a member has more than one presence and the first presence in the array isn't Roblox, but for example the second presence in the array is Roblox the member won't get banned.
I hope this helps you, if you have questions just contact me on Discord
~ Iliannnn#0001
I'm trying to create a modmail system and whenever I try to make it, it says "channel.send is not a function, here is my code."
const Discord = require("discord.js")
const client = new Discord.Client()
const db = require('quick.db')
// ...
client.on('message', message => {
if(db.fetch(`ticket-${message.author.id}`)){
if(message.channel.type == "dm"){
const channel = client.channels.cache.get(id => id.name == `ticket-${message.author.id}`)
channel.send(message.content)
}
}
})
// ...
client.login("MYTOKEN")
I'm trying this with version 12.0.0
EDIT:
I found my issue, for some reason the saved ID is the bots ID, not my ID
As MrMythical said, you should use the find function instead of get. I believe the issue is that you're grabbing a non-text channel, since channel is defined, you just can't send anything to it.
You could fix this by adding an additional catch to ensure you are getting a text channel, and not a category or voice channel. I would also return (or do an error message of sorts) if channel is undefined.
Discord.js v12:
const channel = client.channels.cache.find(c => c.name === `ticket-${message.author.id}` && c.type === 'text');
Discord.js v13:
const channel = client.channels.cache.find(c => c.name === `ticket-${message.author.id}` && c.type === 'GUILD_TEXT');
Edit:
You can tell channel is defined because if it weren't it would say something along the lines of: Cannot read property 'send' of undefined.
You are trying to find it with a function. Use .find for that instead:
const channel = client.channels.cache.find(id => id.name == `ticket-${message.author.id}`)
so i am creating a bot with a kick command and would like to be able to add a reason for said action, i've heard from somewhere that i may have to do string manipulation. currently i have a standalone reason as shown in the code below:
client.on("message", (message) => {
// Ignore messages that aren't from a guild
if (!message.guild) return;
// If the message starts with ".kick"
if (message.content.startsWith(".kick")) {
// Assuming we mention someone in the message, this will return the user
const user = message.mentions.users.first();
// If we have a user mentioned
if (user) {
// Now we get the member from the user
const member = message.guild.member(user);
// If the member is in the server
if (member) {
member
.kick("Optional reason that will display in the audit logs")
.then(() => {
// lets the message author know we were able to kick the person
message.reply(`Successfully kicked ${user.tag}`);
})
.catch((err) => {
// An error happened
// This is generally due to the bot not being able to kick the member,
// either due to missing permissions or role hierarchy
message.reply(
"I was unable to kick the member (this could be due to missing permissions or role hierarchy"
);
// Log the error
console.error(err);
});
} else {
// The mentioned user isn't in this server
message.reply("That user isn't in this server!");
}
// Otherwise, if no user was mentioned
} else {
message.reply("You didn't mention the user to kick!");
}
}
});
Split message.content and slice the first 2 array elements, this will leave you with the elements that make up the reason. Join the remaining elements back to a string.
const user = message.mentions.users.first();
const reason = message.content.split(' ').slice(2).join(' ');
Here is something that could help:
const args = message.content.slice(1).split(" "); //1 is the prefix length
const command = args.shift();
//that works as a pretty good command structure
if(command === 'kick') {
const user = message.mentions.users.first();
args.shift();
const reason = args.join(" ");
user.kick(reason);
//really close to Elitezen's answer but you might have a very terrible problem
//if you mention a user inside the reason, depending on the users' id, the bot could kick
//the user in the reason instead!
}
Here's how you can take away that problem (with regex)
const userMention = message.content.match(/<#!?[0-9]+>/);
//you may have to do some more "escapes"
//this works since regex stops at the first one, unless you make it global
var userId = userMention.slice(2, userMention.length-1);
if(userId.startsWith("!")) userId = userId.slice(1);
const user = message.guild.members.cache.get(userId);
args.shift();
args.shift();
user.kick(args.join(" "))
.then(user => message.reply(user.username + " was kicked successfully"))
.catch(err => message.reply("An error occured: " + err.message))
I assume you want your full command to look something like
.kick #user Being hostile to other members
If you want to assume that everything in the command that isn't a mention or the ".kick" command is the reason, then to get the reason from that string, you can do some simple string manipulation to extract the command and mentions from the string, and leave everything else.
Never used the Discord API, but from what I've pieced from the documentation, this should work.
let reason = message.content.replaceAll(".kick", "")
message.mentions.forEach((mentionedUser) => reason.replaceAll("#" + mentionedUser.username, "")
// assume everything else left in `reason` is the sentence given by the user as a reason
if (member) {
member
.kick(reason)
.then(() => {
// lets the message author know we were able to kick the person
message.reply(`Successfully kicked ${user.tag}`);
})
}
I want to create a verify Command with discord.js v12 which gives you a verified Role which is defined in a Configfile.
Configfile:
{
"token": "my-token",
"status": "a game",
"statusurl": "",
"statustype": 0,
"botmanager": ["285470267549941761", "743136148293025864"],
"prefix": "m!",
"server": {
"343308714423484416": {
"active": true,
"hasBeta": true,
"adminroles": ["533646738813353984"],
"modroles": ["744589796361502774"],
"premiumtoken": "",
"welcomechannel": "653290718248435732",
"welcomemessage": "Hey Hey %user% at %server%",
"welcomemsgenabled": true,
"leavechannel": "653290718248435732",
"leavemessage": "Bye %user% at %server%",
"leavemsgenabled": true,
"verifiedrole": "533646700712296448",
"ruleschannel": "382197929605201920"
}
}
}
My Code:
const Discord = require('discord.js')
const client = new Discord.Client()
const config = require('./config.json')
client.on('ready', () => {
client.user.setStatus('online')
client.user.setActivity("m!help")
console.log(`Bot started successfully in ${client.guilds.cache.size} Guilds with ${client.users.cache.size} Users and ${client.channels.cache.size} Channels`)
})
client.on("message", async message => {
if(message.author.bot) return;
if(!message.content.startsWith(config.prefix)) return;
const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
if(command === "verify") {
if(args.length == 0) {
let member = message.mentions.members.first();
if(message.member.roles.cache.some(r=>[config.server[(message.guild.id)].modroles].includes(r.id))) {
if(!member) {
return message.channel.send(new Discord.MessageEmbed().setColor(0xd35400).setTitle("Invalid User").setDescription("Please use the following Syntax:\n `m!verify <Nutzer>`"))
} else {
var role = message.guild.roles.find(role => role.id === config.server[(message.guild.id)].verifiedrole);
member.roles.cache.add(config.guild[(message.guild.id)].verifiedrole)
}
} else {
message.channel.send(new Discord.MessageEmbed().setTitle("Missing Perms!").setDescription("You're missing the permission to execute this command!").setColor(0xe74c3c))
}
}
}
console.log("Command used: " + command + " " + args + " | User: " + message.author.id + " | Guild: " + message.guild.id)
}
}
})
client.login(config.token)
I removed the most Code so only this command is left. Important is, that this Bot have to be able to use at multiple Servers at the time.
What is wrong here?
OK, so lets make this a multi part answer. First "What is wrong here?" Well, for the most part your current code does not work because you don't use the brackets correctly. You are trying to close brackets that you don't open anywhere. You also use a few too many "if" statements in places where you don't need them.
Next is your concern about multiple servers. This is really not a problem if you write the code to be dynamic. The execution of the command is quick enough that you don't need to worry about two people trying to use the command and the roles getting mixed up.
What I would really advise you to do is take a look at this https://discordjs.guide/ and this https://discord.js.org/#/docs/main/stable/general/welcome
Now to the topic of this question, this is how you could do such a "verify" command. I also added a few notations into the code to explain what we're doing 🙂
client.on("message", message => { // You don't need the async here
// This is all working correctly
if (message.author.bot) return;
if (!message.content.startsWith(config.prefix)) return;
const args = message.content.slice(config.prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
if (command === "verify") {
// We define the server constant as the part of the JSON that deals with the server the message came from
// This makes accessing those values easier
const server = config.server[message.guild.id];
// Your code here was also working
let member = message.mentions.members.first();
// Here we first define the moderator role
// Technicaly this is not needed but it makes the whole code a little easier to understand
// We need modrole[0] here because the modrole entry in your JSON is an array
let modrole = message.guild.roles.cache.find(r => r.id === server.modroles[0]);
// Here we check if the member who calls this command has the needed role
// We need to use the ID of the role to check
if (!message.member.roles.cache.has(modrole.id)) {
// If the user does not have the required role we return here
// That way you don't need to use the 'else' statement
// Creating the embed object in multiple lines improves readability
return message.channel.send(new Discord.MessageEmbed()
.setTitle("Missing Perms!")
.setDescription("You're missing the permission to execute this command!")
.setColor(0xe74c3c)
);
}
if (!member) {
// Here we check if a member was tagged in the command and if that user exists
// Same reasons as above
return message.channel.send(new Discord.MessageEmbed()
.setColor(0xd35400)
.setTitle("Invalid User")
.setDescription(`Please use the following Syntax:\n '${config.prefix}verify <Nutzer>'`)
);
}
// Now we define the role that we want the bot to give
// Here we also don't need to do this but it improves readability and makes working with the role a little easier
var role = message.guild.roles.cache.find(role => role.id === server.verifiedrole);
// Here we add the role to the specified member
// We don't need to use the .cache here
member.roles.add(role.id);
// We can use something called "template strings" here so we don't need to combine multiple strings
// They allow us to put predefined values into the string
console.log(`Command used: ${command} ${args} | User: ${message.author.id} | Guild: ${message.guild.id}`)
}
})
If you want, that the command can be executed at multiple servers at the time you need to write the code in async/await. If you want to learn more about async you can get very good help especially for discord.js v12 here: Understanding async/await
you can get a command for a specifiq channel and give a role for acces to the server
So I have been utterly frustrated these past few days because I have not been able to find a single resource online which properly documents how to find emojis when writing a discord bot in javascript. I have been referring to this guide whose documentation about emojis seems to be either wrong, or outdated:
https://anidiots.guide/coding-guides/using-emojis
What I need is simple; to just be able to reference an emoji using the .find() function and store it in a variable. Here is my current code:
const Discord = require("discord.js");
const config = require("./config.json");
const fs = require("fs");
const client = new Discord.Client();
const guild = new Discord.Guild();
const bean = client.emojis.find("name", "bean");
client.on("message", (message) => {
if (bean) {
if (!message.content.startsWith("#")){
if (message.channel.name == "bean" || message.channel.id == "478206289961418756") {
if (message.content.startsWith("<:bean:" + bean.id + ">")) {
message.react(bean.id);
}
}
}
}
else {
console.error("Error: Unable to find bean emoji");
}
});
p.s. the whole bean thing is just a test
But every time I run this code it just returns this error and dies:
(node:3084) DeprecationWarning: Collection#find: pass a function instead
Is there anything I missed? I am so stumped...
I never used discord.js so I may be completely wrong
from the warning I'd say you need to do something like
client.emojis.find(emoji => emoji.name === "bean")
Plus after looking at the Discord.js Doc it seems to be the way to go. BUT the docs never say anything about client.emojis.find("name", "bean") being wrong
I've made changes to your code.
I hope it'll help you!
const Discord = require("discord.js");
const client = new Discord.Client();
client.on('ready', () => {
console.log('ready');
});
client.on('message', message => {
var bean = message.guild.emojis.find(emoji => emoji.name == 'bean');
// By guild id
if(message.guild.id == 'your guild id') {
if(bean) {
if(message.content.startsWith("<:bean:" + bean.id + ">")) {
message.react(bean.id);
}
}
}
});
Please check out the switching to v12 discord.js guide
v12 introduces the concept of managers, you will no longer be able to directly use collection methods such as Collection#get on data structures like Client#users. You will now have to directly ask for cache on a manager before trying to use collection methods. Any method that is called directly on a manager will call the API, such as GuildMemberManager#fetch and MessageManager#delete.
In this specific situation, you need to add the cache object to your expression:
var bean = message.guild.emojis.cache?.find(emoji => emoji.name == 'bean');
In case anyone like me finds this while looking for an answer, in v12 you will have to add cache in, making it look like this:
var bean = message.guild.emojis.cache.find(emoji => emoji.name == 'bean');
rather than:
var bean = message.guild.emojis.find(emoji => emoji.name == 'bean');