I have a command in my bot, called weather, it works fine, but i want to send an error message if the user writes it without any arguments.
It works if the arguments are not a place, but if you write it without any args, it doesnt reply anything
Here's the code (Updated with entire code)
const Discord = require('discord.js');
const weather = require('weather-js');
exports.run = async (client, message, args) => {
weather.find({search: args[0], degreeType: "C"}, function(err, result){
if (err) message.channel.send(err);
const noargs = new Discord.RichEmbed()
.setDescription(`Input a valid location, please`)
.setColor(0xfd5454)
if(!result.length) {
message.channel.send(noargs);
return;
}
var current = result[0].current;
var location = result[0].location;
It works if you write ",weather nonexistingcity" but if you write ",weather" without any args, it doesnt work.
PD: noargs is a discord embed, is declared but not included in this post.
const weather = require('weather-js');
const Discord = require('discord.js');
module.exports = {
name: "weather",
description: "Checks a weather forecast",
async execute(client, message, cmd, args, Discord){
weather.find({search: args.join(" "), degreeType: 'F'}, function (error, result){
// 'C' can be changed to 'F' for farneheit results
if(error) return message.channel.send(error);
if(!args[0]) return message.channel.send('Please specify a location')
if(result === undefined || result.length === 0) return message.channel.send('**Invalid** location');
var current = result[0].current;
var location = result[0].location;
const weatherinfo = new Discord.MessageEmbed()
.setDescription(`**${current.skytext}**`)
.setAuthor(`Weather forecast for ${current.observationpoint}`)
.setThumbnail(current.imageUrl)
.setColor(0x111111)
.addField('Timezone', `UTC${location.timezone}`, true)
.addField('Degree Type', 'Celsius', true)
.addField('Temperature', `${current.temperature}°`, true)
.addField('Wind', current.winddisplay, true)
.addField('Feels like', `${current.feelslike}°`, true)
.addField('Humidity', `${current.humidity}%`, true)
message.channel.send(weatherinfo)
})
}
}
If you want to check if no args where provoided you can do :
if(args.length == 0) return message.channel.send('You need to provide a city');
...weather-js is programmed to answer the user if he didn't provide args with a default message. I want to know how to change that message.
If you really want to change this message instead of checking your arguments yourself like #PLASMA chicken has suggested, the message is located on line 31 of weather-js/index.js.
Related
I’m building a Discord bot using the Discord.JS module, and using NodeJS. I’m trying to add a simple crypto-price feature to my bot.
For now, I’m using the following code:
const unirest = require("unirest");
const req = unirest("GET", "https://coinranking1.p.rapidapi.com/coin/Qwsogvtv82FCd/price");
req.query({
"referenceCurrencyUuid": "yhjMzLPhuIDl"
});
req.headers({
"X-RapidAPI-Host": "coinranking1.p.rapidapi.com",
"X-RapidAPI-Key": "X",
"useQueryString": true
});
req.end(function (res) {
if (res.error) throw new Error(res.error);
console.log(res.body);
});
So basically, you have to provide the UUID of the desired crypto coin to request information, but I want my users to be able to do (for example) !price bitcoin or !price btc, but this requires the command to be like !price Qwsogvtv82FCd.
How do I resolve this issue?
If you check the API documentation, you can see that instead of using the coin price endpoint, you could use the search suggestion (https://coinranking1.p.rapidapi.com/search-suggestions), where you can search for a coin by its name or symbol. It returns an object like the one below. If you check the objects in data.coins, they have keys like uuid, name, symbol, and price:
{
"status":"success",
"data":{
"coins":[
{
"uuid":"Qwsogvtv82FCd",
"iconUrl":"https://cdn.coinranking.com/gNsKAuE-W/bitcoin_btc.svg",
"name":"Bitcoin",
"symbol":"BTC",
"price":"65955.43592725793773050345"
},
{...}
],
"exchanges":[
{...},
{...}
],
"markets":[...]
}
}
Your current code doesn't really do anything and it doesn't even have discord.js code. Here is a sample code with some explanation:
const { Client, Intents } = require('discord.js');
// I'm using node-fetch instead of unirest
// make sure you install it using npm i node-fetch
const fetch = require('node-fetch');
const RAPID_API_KEY = 'YOUR RAPID API KEY';
const TOKEN = 'YOUR DISCORD API TOKEN';
const client = new Client({
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES],
});
const prefix = '!';
client.on('messageCreate', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command !== 'price') return;
if (!args[0]) return message.reply('Please provide a coin!');
try {
// get the search query
let query = args[0].toLowerCase();
// call the API
let coins = await searchCoin(query);
// if there is no search result, or something went wrong, exit w/ a message
if (!coins || coins.length === 0)
return message.reply(`No result for \`"${query}"\``);
// check the first result only
let coin = coins[0];
// if there is an exact match, send the price returned from the API
if (
coin.name.toLowerCase() === query ||
coin.symbol.toLowerCase() === query
)
return message.reply(
`The current price of **${coin.name} (${coin.symbol})** is **${coin.price} USD**`,
);
// if there is no exact match, just send the coin name and symbol in a message
message.reply(
`No exact result found. Did you mean **${coin.name} (${coin.symbol})**?`,
);
} catch (err) {
console.error(err);
message.reply('Oops, there was an error. Please try again later.');
}
});
client.once('ready', () => {
console.log('Bot is connected...');
});
client.login(TOKEN);
async function searchCoin(query) {
const url = `https://coinranking1.p.rapidapi.com/search-suggestions?query=${query}`;
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Host': 'coinranking1.p.rapidapi.com',
'X-RapidAPI-Key': RAPID_API_KEY,
},
};
try {
const response = await fetch(url, options);
const json = await response.json();
return json.status === 'success' ? json.data?.coins : null;
} catch (err) {
console.error(err);
return null;
}
}
And here is the result:
I currently need to ping the person first then it will cache into the bot. After that, I would then be able to use their ID.
How do I make it so I can use their ID straight away?
This is my avatar command. How would I go to improve and add that command?
module.exports = {
config,
run: async (client, message, args) => {
let embed = new Discord.MessageEmbed();
let mention = message.mentions.members.first()
if(!mention && !isNaN(args[0]) && args[0]) try {mention = await client.users.fetch(args[0])} catch (err) {}
if(!mention && args[0] && isNaN(args[0])) try {mention = await message.guild.members.fetch({query: args[0], limit: 1})} catch (err) {}
if(!mention) mention = message.author
if(mention.roles) mention = mention.user
let user = message.mentions.users.first()
|| message.guild.members.cache.get(args[0])?.user
|| message.author;
embed.setTitle('Avatar!');
embed.setAuthor(message.author.tag, message.author.displayAvatarURL());
embed.setColor(client.config.colors.info);
embed.setImage(user.displayAvatarURL({dynamic: true}));
return message.reply({embeds: [embed] });
}
}
You don't have to.
All members will be cached when your bot starts up (remember to put const client = new Client({ intents: [Intents.FLAGS.GUILDS] }); in your file!)
See the first code block here (under implementation).
The only code I have is this:
module.exports = {
name: "kick",
description: "This command kicks a member!",
execute(message, args) {
const target = message.mentions.users.first();
if (target) {
const memberTarget = message.guild.members.cache.get(target.id);
memberTarget.kick();
message.channel.send("User has been kicked");
} else {
message.channel.send(`You coudn't kick that member!`);
}
},
};
Good Morning. So I'm trying to get it to message the person that got kicked the reason why they got kicked. (!kick user reason) I want it so the bot DMs the person what the reason was but I don't know how to do that.
You would only need to add the following:
const reason = args.splice(1).join(` `) || 'Not specified';
memberTarget.send(`You have been kicked: \nReason: ${reason}`)
module.exports = {
name: "kick",
description: "This command kicks a member!",
execute(message, args) {
const target = message.mentions.users.first();
if (target) {
const memberTarget = message.guild.members.cache.get(target.id);
const reason = args.splice(1).join(` `) || 'Not specified';
memberTarget.kick();
message.channel.send("User has been kicked");
memberTarget.send(`You have been kicked: \nReason: ${reason}`)
} else {
message.channel.send(`You coudn't kick that member!`);
}
},
};
The const reason = args.splice(1).join( ) || 'Not specified'; defines the 'reason' property, if there isn't a reason, it defaults to 'Not specified'.
memberTarget.send(You have been kicked: \nReason: ${reason})
Just sends the message to the targeted member.
Right off the bat, I see that you are getting the target using message.mentions.users and getting the memberTarget from the guild's cache. You should avoid this and use message.mentions.members.
You'll have to use the send method of GuildMember, but since it returns a Promise, you'll have to catch any errors. (e.g: the bot cannot DM the member)
// You should do some sanity checks in case you haven't. You don't want everyone to be able to kick members using the bot.
// Getting the first member in message.mentions.members.
const target = message.mentions.members.first();
// Making sure that target is defined.
if (!target) return message.channel.send('Please mention a member to kick.');
// Making sure a reason is provided. (args[0] is the mention)
if (!args[1]) return message.channel.send('Please provide a reason.');
// Making sure the bot can kick the target.
if (!target.kickable) return message.channel.send('Couldn\'t kick the target.');
// Trying to send a message to the target, notifying them that they got kicked, and catching any errors.
target.send(`You have been kicked from ${message.guild.name} for ${args.slice(1, 2000).join(' ')}`).catch(console.error).finally(() => {
// After the message was sent successfully or failed to be sent, we kick the target and catch any errors.
target.kick(`Kicked by ${message.author.tag} for ${args.slice(1, 2000).join(' ')}}.`).then(() => {
message.channel.send(`${target.user.tag} has been kicked for ${args.slice(1, 2000).join(' ')}.`);
}).catch(error => {
console.error(error)
message.channel.send(`Something went wrong...`);
});
});
This is working kick command with reason made by me (you can try it):-
It has every validation you should have in a kick command
const Discord = require('discord.js')
exports.kick = async(message , prefix , client) => {
if(!message.member.hasPermission("KICK_MEMBERS")) return message.channel.send('Missing Permission! You need to have `KICK_MEMBERS` permissions in order kick this member.')
if(!message.guild.me.hasPermission("KICK_MEMBERS")) return message.channel.send('Missing Permission! I need to have `KICK_MEMBERS` permissions to kick this member.')
const args = message.content.slice(prefix.length).trim().split(' ');
const command = args.shift().toLowerCase();
let member = message.mentions.members.first();
if(!member){
let err = "```css\n[ Agrument Error : You Have not mentioned the user on first args. ]\n```\n\n"
let embed = new Discord.MessageEmbed()
.setAuthor(`${client.user.username} Help Manual` , client.user.displayAvatarURL({format : "png"}))
.setTitle(`${message.guild.name}`)
.setDescription(err)
.addField('Help Command:' , `\`\`\`\n${prefix}kick #user#0001 Reason\n\`\`\``)
.setTimestamp()
.setColor('RED')
return message.channel.send(embed)
}
if(args[0] != `<#!${member.id}>`){
let err = "```css\n[ Agrument Error : You Have not mentioned the user on first args. ]\n```"
let embed = new Discord.MessageEmbed()
.setAuthor(`${client.user.username} Help Manual` , client.user.displayAvatarURL({format : "png"}))
.setTitle(`${message.guild.name}`)
.setDescription(err)
.addField('Help Command:' , `\`\`\`\n${prefix}kick #user#0001 Reason\n\`\`\``)
.setTimestamp()
.setColor('RED')
return message.channel.send(embed)
}
if(member.id === message.author.id) return message.channel.send(`Why? No Just Say Why Do you want to kick yourself?`)
let reason = args.slice(1).join(' ');
if(!reason || reason.length <= 1){
reason = "No Reason Was Provided."
}
if(!member.kickable){
return message.channel.send(`I Don't Have Permissions to Kick ${member.user.username}`)
}
member.kick().then(() => {
return message.channel.send(`Successfully Kicked ${member.user.username} for Reason ==> \`${reason}\``)
}).catch(() => {
return message.channel.send(`I Don't Have Permissions to Kick ${member.user.username}`)
})
}
I just made a weather command for discord.js, it works fine but if I run p!weather 'not a city' it'll give me an error, I can't find any mistakes in my code, does anyone knows how to fix it. I am using slappy/discord.js. This is my code:
const Discord = require("discord.js");
const weather = require("weather-js");
module.exports = class WeatherCommand extends BaseCommand {
constructor() {
super('weather', 'fun', []);
}
async run(client, message, args) {
if (!message.guild) return message.channel.send(`Try again if you are in a server channel!`);
const city = message.content.split(" ").slice(1).join(" ")
if (!city) return message.channel.send("I need a city to check :wink:")
weather.find({search: city, degreeType: 'C'}, function(err, result) {
if (err) {
message.channel.send("**${arg}** Isnt inside my query, please check again")
console.log(err.stack)
return;
}
let url;
if (result[0].current.skytext === "Mostly Sunny") url = "https://openclipart.org/image/2400px/svg_to_png/3367/ivak-Decorative-Sun.png"
else if (result[0].current.skytext === "Mostly Cloudy" || result[0].current.skytext === "Cloudy") url = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/35/Weather-heavy-overcast.svg/200px-Weather-heavy-overcast.svg.png"
else if (result[0].current.skytext === "Partly Cloudy") url = "";
var embed = new Discord.MessageEmbed()
.setTitle(`Forecast for ${result[0].location.name}`, message.author.displayAvatarURL)
.addField("Temperature", `**${result[0].current.temperature}ºC**`, true)
.addField("Humidity", `**${result[0].current.humidity}%**`, true)
.addField("Wind Speed", `**${result[0].current.windspeed.replace("mph", "ms/h")}**`, true)
.addField("Feels Like", `**${result[0].current.feelslike}ºC**`, true)
.addField("Status", `**${result[0].current.skytext}**`, true)
.setTimestamp()
.setThumbnail(result[0].current.imageUrl)
.setColor('YELLOW')
.setFooter(`Requested by: ${message.author.tag}`)
message.channel.send({ embed: embed })
})};
}
thanks
The bot can't read the property of current. You used current after results[0], which means that that's undefined. I suggest logging results to see what's in it to know how to get your desired data.
so I'm trying to make a help command with list of commands showed in embed. My code kinda works but it throws an error "DiscordAPIError: Cannot send an empty message" and I've tried already everything I know and what I've found but I can't fix it.
Here's the code
const Discord = require('discord.js');
const { prefix } = require('../config.json');
module.exports = {
name: 'help',
description: 'List all of my commands or info about a specific command.',
aliases: ['commands', 'cmds'],
usage: '[command name]',
cooldown: 5,
execute(msg, args) {
const data = [];
const { commands } = msg.client;
if (!args.length) {
const helpEmbed = new Discord.MessageEmbed()
.setColor('YELLOW')
.setTitle('Here\'s a list of all my commands:')
.setDescription(commands.map(cmd => cmd.name).join('\n'))
.setTimestamp()
.setFooter(`You can send \`${prefix}help [command name]\` to get info on a specific command!`);
msg.author.send(helpEmbed);
return msg.author.send(data, { split: true })
.then(() => {
if (msg.channel.type === 'dm') return;
msg.reply('I\'ve sent you a DM with all my commands!');
})
.catch(error => {
console.error(`Could not send help DM to ${msg.author.tag}.\n`, error);
msg.reply('it seems like I can\'t DM you! Do you have DMs disabled?');
});
}
const name = args[0].toLowerCase();
const command = commands.get(name) || commands.find(c => c.aliases && c.aliases.includes(name));
if (!command) {
return msg.reply('that\'s not a valid command!');
}
data.push(`**Name:** ${command.name}`);
if (command.aliases) data.push(`**Aliases:** ${command.aliases.join(', ')}`);
if (command.description) data.push(`**Description:** ${command.description}`);
if (command.usage) data.push(`**Usage:** ${prefix}${command.name} ${command.usage}`);
data.push(`**Cooldown:** ${command.cooldown || 3} second(s)`);
msg.channel.send(data, { split: true });
},
};
You should try replace this line :
msg.channel.send(data, { split: true });
with
msg.channel.send(data.join(' '), { split: true }); since your data variable is an array and not a string
The problem is as the error states. You are trying to send an empty message somewhere.
You can try replacing msg.channel.send(data) with msg.channel.send(data.join('\n')), since the data variable is an array.
I don't see why sending an array doesn't work though.