How to async run a command file in the the commands folder - discord

I wanted to add a kick command to my discord bot, which uses the await function.The only way i know to async run is
client.on("message", async (message) => {
however, I cannot do this in a command file inside the commands folder
My kick command
const { MessageEmbed } = require("discord.js");
module.exports = {
name: "kick",
description: "kicks a member",
execute(client, args) {
if (!message.member.hasPermission("KICK_MEMBERS")) return message.channel.send("Invalid Permissions")
let member = message.mentions.members.first()
if(!member)
return message.reply("Please mention a valid member of this server");
if(!member.kickable)
return message.reply("I cannot kick this user! Do they have a higher role? Do I have kick permissions?");
let reason = args.slice(1).join(' ');
if(!reason) reason = "No reason provided";
await member.kick(reason)
.catch(error => message.reply(`Sorry ${message.author} I couldn't kick because of : ${error}`));
message.reply(`${member.user.tag} has been kicked by ${message.author.tag} because: ${reason}`)
}}
Sorry if this seems like a stupid question, Im pretty new to coding

Try changing your code to:
module.exports = {
name: "kick",
description: "kicks a member",
// vvv THIS LINE CHANGED vvv
// vvv THIS LINE CHANGED vvv
// vvv THIS LINE CHANGED vvv
execute: async (client, args) => {
if (!message.member.hasPermission("KICK_MEMBERS")) return message.channel.send("Invalid Permissions")
let member = message.mentions.members.first()
if(!member)
return message.reply("Please mention a valid member of this server");
if(!member.kickable)
return message.reply("I cannot kick this user! Do they have a higher role? Do I have kick permissions?");
let reason = args.slice(1).join(' ');
if(!reason) reason = "No reason provided";
await member.kick(reason)
.catch(error => message.reply(`Sorry ${message.author} I couldn't kick because of : ${error}`));
message.reply(`${member.user.tag} has been kicked by ${message.author.tag} because: ${reason}`)
}}
Specific Change:
execute(client, args) {
becomes
execute: async (client, args) => {
Essentially what that does is it says the function is async, vs your code is just declaring execute as a normal (sync) function. Also since I'm not sure if you can declare an async function with normal function syntax, I changed it to ES6 arrow function syntax:
eg. execute() {} to execute: () => {}
You can read more about arrow functions here

Related

Discord music bot saying I need to send a second argument even when i do

Whats wrong with my code, I cant seem to figure it out. Followed a few tutorials before and made a few simple bots on my own, but cant seem to figure this out. Its not playing music nor connecting to the vc
Heres My Code:
const ytdl = require('ytdl-core');
const ytSearch = require('yt-search');
module.exports = {
name: 'play',
description: 'Joins and plays a video from youtube',
async execute(message, args) {
const voiceChannel = message.member.voice.channel;
if (!voiceChannel) return message.channel.send('You need to be in a channel to execute this command!');
const permissions = voiceChannel.permissionsFor(message.client.user);
if (!permissions.has('CONNECT')) return message.channel.send('You dont have the correct permissins');
if (!permissions.has('SPEAK')) return message.channel.send('You dont have the correct permissins');
if (!args.length) return message.channel.send('You need to send the second argument!');
const validURL = (str) =>{
var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
if(!regex.test(str)){
return false;
} else {
return true;
}
}
if(validURL(args[0])){
const connection = await voiceChannel.join();
const stream = ytdl(args[0], {filter: 'audioonly'});
connection.play(stream, {seek: 0, volume: 1})
.on('finish', () =>{
voiceChannel.leave();
message.channel.send('leaving channel');
});
await message.reply(`:thumbsup: Now Playing ***Your Link!***`)
return
}
const connection = await voiceChannel.join();
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'});
connection.play(stream, {seek: 0, volume: 1})
.on('finish', () =>{
voiceChannel.leave();
});
await message.reply(`:thumbsup: Now Playing ***${video.title}***`)
} else {
message.channel.send('No video results found');
}
}
}
The main principle we want to focus on here is Guard Statements which you make good use of in your code.
If you aren't already familiar, a guard statement is one that resides at the top of a block of code and prevents the execution of code below it if a specific condition is met. This is really useful for making discord bots because it will allow us to stop command execution if the permission to use it is missing for example (which you use in your code provided)
The caveat here is that in your specific guard statement where you check for the number of args used, you provide this line:
if (!args.length) return message.channel.send('You need to send the second argument!');
Now, there's nothing wrong with this line, except that we're only checking if the property length doesn't exist on args which isn't what we're really trying to check.
If we want to make sure that there are exactly two arguments provided, we would want to rewrite the condition like this:
if (args.length == 2) return message.channel.send('You need to send the second argument!');
From here, you can change the condition to meet your desired requirements and it should work great!

Run client.setActivity out of client.once('ready' etc. discord.js

I am trying to set the status of the bot based on a user message (not in the code below), but I keep getting the error
TypeError: Cannot read property 'setActivity' of null
code is below, thanks in advance
client.once('ready', () => {
console.log('Ready!');
client.user.setActivity("your every move", { type: "WATCHING" }) //works
});
function setStatus(game, type){
client.user.setActivity(game, type)
}
setStatus("your every move", { type: "WATCHING" }) //returns "TypeError: Cannot read property 'setActivity' of null"
client.login(config.token);
this code should set the activity. Usage would be +activity watching/playing/listening game
BTW the setStatus function also works if you have it in a function (if you call that function in client. or that function that calls the function is called by client.)
const Discord = require("discord.js");
const client = new Discord.Client();
const cfg = require("./config.json");
const prefix = "+";
client.once('ready', () => {
console.log('Ready!');
setStatus("your every move", { type: "WATCHING" })
});
client.on("message", message =>{
if(message.content.startsWith(prefix)){
args = message.content.substr(prefix.length).split(/ +/);
cmd = args[0].toLowerCase();
if(cmd == "activity"){
let type = args[1].toUpperCase();
console.log(type);
let game = args
game.splice(0,2);
setStatus(game.join(" "), { type: type });
}
}
});
function setStatus(game, type){
client.user.setActivity(game, type)
}
client.login(cfg.token);

user.ban is Not a function?

I was trying to make a ban command where you can ban a user with a reason.
Turns out user.ban is not a function in Discord.js V12 even though it should be.
Here is my code.
const { MessageEmbed } = require('discord.js');
module.exports = {
name: 'ban',
description: 'Bans a user.',
category: 'Moderation',
usage: '^ban <user> <reason>',
run: async (bot, message, args) => {
if (!message.member.hasPermission('BAN_MEMBERS')) {
return message.channel.send('You do not have permission to do this! ❌');
}
if (!message.guild.me.hasPermission('BAN_MEMBERS')) {
return message.channel.send('I do not have permission to do this! ❌');
}
const user = message.mentions.users.first();
if (!user) {
return message.channel.send('User was not specified. ❌');
}
if (user.id === message.author.id) {
return message.channel.send('You cannot ban yourself! ❌');
}
let reason = message.content
.split(' ')
.slice(2)
.join(' ');
if (!reason) {
reason = 'No reason provided.';
}
let Embed = new MessageEmbed()
.setTitle(`Justice! | Ban Action`)
.setDescription(`Banned \`${user}\` - Tag: \`${user.discriminator}\``)
.setColor('ORANGE')
.setThumbnail(user.avatarURL)
.addField('Banned by', `\`${message.author.username}\``)
.addField(`Reason?`, `\`${reason}\``)
.setTimestamp();
message.channel.send(Embed);
user.ban(reason);
},
};
Is there a way to fix this?
You're getting a User instead of a GuildMember. A User represents a person on discord, while a GuildMember represents a member of a server. You can get a GuildMember instead of a User by using mentions.members instead of mentions.users ex:
const user = message.mentions.members.first()

Discord bot role command stopped working for unknown reasons

I have a command which worked, but at some point stopped, returning to the chat message that the role does not exist. An error "(node:12228) DeprecationWarning: Collection#find: pass a function instead" is sent to the console every time I use a command, but I always had it
const Discord = require("discord.js");
module.exports.run = async (bot, message, args) => {
if(!message.member.hasPermission("MANAGE_MEMBERS")) return message.reply();
let rMember = message.guild.member(message.mentions.users.first()) || message.guild.members.get(args[0]);
if(!rMember) return message.reply("nope.");
let role = args.join(" ").slice(22);
if(!role) return message.reply("nope!");
let gRole = message.guild.roles.find(`name`, role);
if(!gRole) return message.reply("role does not exist.");
const allowed = ['some id'];
if (!allowed.includes(gRole.id)) return;
if(rMember.roles.has(gRole.id)) return message.reply("nope.");
await(rMember.removeRoles(['some id']));
await(rMember.addRole(gRole.id));
if(gRole.id == 'id') rMember.addRole('id') && rMember.removeRoles(['some id']);;
try{
await rMember.send(`you got ${gRole.name}!`)
}catch(e){
}
}
module.exports.help = {
name: "role"
}
So I need the command to work.
In order of appearance, I see these mistakes in your code...
You're not catching any rejected promises.
MANAGE_MEMBERS is not a valid permission flag.
You should pass a function into Collection.find().
No idea what you're trying to do with the declaration of role.
Your use of the && logical operator in your if statement is incorrect. Use a block statement instead.
Your catch block in the try...catch statement has been left empty.
Combining the answers provided to your other questions about this code, this is a correct, much cleaner rewrite...
const getMention = require('discord-mentions'); // Don't forget to install.
module.exports.run = async (bot, message, args) => {
if (!message.guild) return;
try {
if (!message.member.hasPermission('MANAGE_ROLES')) return;
if (!args[1]) return await message.reply('Please provide a user.');
if (!args[2]) return await message.reply('Please provide a role.');
if (args[3]) return await message.reply('Too many arguments provided.');
let member;
if (getMention(args[1])) member = getMention(args[1], message.guild).member;
else member = message.guild.members.find(m => m.user.tag === args[1] || m.id === args[1]);
if (!member) return await message.reply('Invalid user provided.');
let role;
if (getMention(args[2])) role = getMention(args[2], message.guild).role;
else role = message.guild.roles.find(r => r.name === args[2] || r.id === args[2]);
if (!role) return await message.reply('Invalid role provided.');
const allowed = ['role1ID', 'role2ID', 'role3ID'];
if (!allowed.includes(role.id)) return await message.reply('That role is not allowed.');
if (member.roles.has(role.id)) return await message.reply('That user already has that role.');
await member.removeRoles(['someID', 'someOtherID']);
await member.addRole(role.id);
if (role.id === 'anAlternateRoleID') {
await member.removeRoles(['someID', 'someOtherID']);
await member.addRole('otherRoleID');
}
await member.send(`You got the ${role.name} role.`)
.catch(() => console.log(`Couldn't send message to ${member.user.tag}.`));
} catch(err) {
console.error(err);
}
};
module.exports.help = {
name: 'role'
};
Keep in mind, if you're removing just one role from a member, you should use the singular version of the method, GuildMember.removeRole().

Delaying a delete event

I have a ticket system on my discord.js bot, and when you close it, it instantly closes. I was curious if there was a way to delay it from deleting for 1 hour. Here's my code:
const Discord = require('discord.js');
module.exports.run = async (bot, message, args) => {
if (!message.channel.name.startsWith('ticket')) return message.channel.send('You are not in a ticket channel!');
let reason = args[0] | 'Ticket Closed!'
message.channel.delete(args[0])
}
module.exports.help = {
name: "close"
}
One easy way to do it is with a simple setTimeout function. E.g.:
module.exports.run = async (bot, message, args) => {
if (!message.channel.name.startsWith('ticket')) return message.channel.send('You are not in a ticket channel!');
let reason = args[0] | 'Ticket Closed!'
setTimeout(() => {
message.channel.delete(args[0]);
}, 60 * 60 * 1000); // Sets timeout for 1 hour
}
You could use
.then(m => m.delete(time in ms));
after the message.
Or, if you want to edit it before you delete it:
const msg = await message.channel.send("Edit message!")
msg.edit("It's edited now!")
msg.edit("You can do it multiple times!")
// You can use a setTimeout() here if you want a delay. Also, make sure that this is in an async function
msg.delete()

Resources