(Discord Bot) Get message that follows command prefix - javascript

I'm trying to reference the previous message sent by a client using discord.js
How would I go about getting the last message sent?
client.on("messageCreate", (message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'set-reminder'){
channelName = client.channels.cache.find(channel => channel.name === "spam");
message.channel.send("Command Works");
channelName.messages.fetch({ limit: 1 }).then(messages => {
// find "command works" message (previous message from client)
let lastMessage = messages.first();
console.log(lastMessage.content);
})
}
})```

The message.channel.send function is async
You can await the send function or use .then
The send function also returns the message, you don't need a query to get it
await
let message = await message.channel.send("Command Works");
console.log(message.content);
then
message.channel.send("Command Works").then((message) => {
console.log(message.content);
});
(async means not-synchronous : you have to wait to get its result)

Related

"mute" command gives random output

if(command === "mute"){
const target = message.mentions.users.first();
if (target) {
if (!message.member.hasPermission("ADMINISTRATOR")) {
return message.reply("Unauthorized");
}
let muted = client.settings.get(message.guild.id, 'mute')
let muteRole = message.guild.roles.cache.find(role => role.name === muted);
let memberTarget = message.guild.members.cache.get(target.id);
let rolelist = memberTarget.roles.cache
.map(r => r)
if (!args[1]) {
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> has been muted`);
return
}
memberTarget.roles.remove(rolelist);
memberTarget.roles.add(muteRole);
message.channel.send(`<#${memberTarget.user.id}> will be muted for ${ms(ms(args[1]))}`);
setTimeout(function () {
memberTarget.roles.add(rolelist);
memberTarget.roles.remove(muteRole);
}, ms(args[1]));
} else {
message.channel.send('User not found!');
}
So I have this mute command which removes all your roles, gives you the muteRole, when time is up, it gives back your previous roles and removes the muteRole. The problem I'm having is that it sometimes removes all your roles and doesn't give you the muteRole, other times it doesn't remove the muteRole when the time is up. Sometimes it removes all your roles and doesn't give you the
muteRole and when the times up it doesn't give your roles back...
Basically the outcome is always random. So my question is how do I make it consistent?
The methods .add() and .remove() return a Promise so you should try using await / .then().
If you do it with this, the next function or .then() will not be executed until the promise is completely processed.
Example:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'));
Now you're nearly finished. The last thing you need is the .catch() block, because if the code above fails / throws an error you should catch that:
.catch(err => console.log(`An error occured: ${err}`))
Final result:
memberTarget.roles.remove(rolelist)
.then(() => memberTarget.roles.add(muteRole))
.then(() => message.channel.send('some message'))
.catch(err => console.log(`An error occured: ${err}`));
References
GuildMemberRoleManager (Discord.js)
Promises
Handle promises
Await

How do I use an API in Discord.js?

I was looking for a cool way I could automate some interesting news articles on my discord server. I wanted to use webhooks at first but then decided to go with APIs. I looked all around and saw that I should go with New York Times API but when I went to code it, it came up with a few errors.
const Discord = require("discord.js");
const client = new Discord.Client();
const token = require("./token.js");
const fetch = require('node-fetch');
const prefix = '!';
const trim = (str, max) => str.length > max ? `${str.slice(0, max - 3)}...` : str;
client.once('ready', () => {
console.log('Ready!');
});
client.on('message', async message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'news') {
const { file } = await fetch('https://api.nytimes.com/svc/topstories/v2/technology.json?api-key=').then(response => response.json());
message.channel.sendMessage(file);
}
}).then((state) => {
assert(state.action === 'DONE', 'should change state');
})
.catch((error) => {
assert.isNotOk(error, 'Promise error');
});
throw
client.login(token);
This is my code, I know this is probably riddled with mistakes but I am just starting out with node.js
I looked at the example from the discord.js website and took some stuff from there. I don't know what I should do and if you could explain it out a little to help me learn that would be great. I keep getting the Unhandled Rejection Promise Warning and the Cannot send an empty message errors. I am using Visual Studio Code.
You can use the async/await to get the results array from the API response, then send the details in embeds. You can either send the first article, a random article or more than one articles.
The following should work, it sends the first three articles:
const { Client, MessageEmbed } = require('discord.js');
const fetch = require('node-fetch');
const token = require("./token.js");
const client = new Client();
const API_KEY = 'QerEdX953-NOT-REAL-hdvgx7UPs';
const prefix = '!';
client.on('message', async (message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'news') {
try {
const response = await fetch(
`https://api.nytimes.com/svc/topstories/v2/technology.json?api-key=${API_KEY}`,
);
const data = await response.json();
if (data.results.length === 0) {
return message.channel.send('There are no top stories for you today 🙊');
}
const embed = new MessageEmbed();
// you could also get the number of stories from args[0]
const MAX_STORIES = 3;
data.results.slice(0, MAX_STORIES).forEach((result) => {
embed.setTitle(result.title);
embed.setDescription(result.abstract);
embed.setURL(result.url);
embed.setTimestamp(result.published_date);
if (result.multimedia.length && result.multimedia[2]) {
embed.setThumbnail(result.multimedia[2].url);
}
message.channel.send(embed);
});
} catch (error) {
message.channel.send('Oops, there was an error fetching the API');
console.log(error);
}
}
});
The response from the Top Stories API does not have a file key and so is undefined. You want to destructure results to access the articles array.
The error message says that you cannot call sendMessage with an empty message (undefined in this case).
I'm not sure of the message you want to send but you can send the link to the first article with the following code, for example.
const res = await fetch(`https://api.nytimes.com/svc/topstories/v2/technology.json?api-key=${NYTIMES_API_KEY}`)
const { results } = await res.json()
if (results.length) {
message.channel.sendMessage(results[0].url)
} else {
message.channel.sendMessage('No articles found')
}

Adding a global timer for tmi.js integrated discord.js

I'm trying to do a discord bot that listens to multiple twitch chat for commands, then run them on discord, using both tmi.js and discord.js. Currently it is working, but I can't seem to add a global cooldown on the commands itself to prevent spamming. At first I've tried adding a cd timer to each command, but I'm unable to get it working, hence the decision to try to make a global cd but still to no avail. Am I doing something wrongly?
twitch.on('message', (channel, tags, message, self) => {
if(!message.startsWith(prefix) || self) return;
const args = (message.slice(prefix.length).trim().split(/ +/));
const commandName = args.shift().toLowerCase();
if (!twitch.commands.has(commandName)) return;
const command = twitch.commands.get(commandName);
}
try {
command.execute(bot, botChannel, vcChannel, isReady);
} catch (error){
console.error(error);
}
});
just to update, I basically took a leaflet from async await functions here: https://stackoverflow.com/a/54772517/14637034
Then, I modified the code as such:
const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => {
setTimeout(() => {
cb();
resolve();
}, timeout);
});
const doStuffAsync = async () => {
await setAsyncTimeout(() => {
isReady = true;
console.log(isReady);
}, 10000);};
twitch.on('message', (channel, tags, message, self) => {
if(!message.startsWith(prefix) || self) return;
const args = (message.slice(prefix.length).trim().split(/ +/));
const commandName = args.shift().toLowerCase();
if (!twitch.commands.has(commandName)) return;
if (isReady){
const command = twitch.commands.get(commandName);
isReady = false;
try {
command.execute(bot, botChannel, vcChannel);
} catch (error){
console.error(error);
}
doStuffAsync();
}
});
Seemed to work for now, as 10s is a long enough time for bot to leave discord properly without causing timeout. I'm still open to better suggestions for optimization though!

discord.js node.js code object promise problem

client.on('message', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
let member = message.guild.members;
if (command === 'ping') {
message.channel.send(`${srv.getServerName().then()}`)
}
});
I have a coding like this, when I write ping from the channel, it should write servername but it writes object promise. How can I solve it?
Sorry my english not good, i using google translate.
It seems srv.getServerName() is a Promise, and you're sending it instead of the resolved value to your channel. That's why you see [object Promise].
You can get the server name first and send the message from its .then() method:
if (command === 'ping') {
srv
.getServerName()
.then(name => message.channel.send(name))
}
Or you can make the callback an async function and await the response before you send it:
client.on('message', async (message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
const member = message.guild.members;
if (command === 'ping') {
const serverName = await srv.getServerName();
const embed = new MessageEmbed()
.setTitle('Embed title')
.setDescription(`This is the "${serverName}" server`);
message.channel.send(embed);
}
});

await is only valid in async function error inside a bot command

I wrote this code and I can't run my bot, I don't know why.
if (command === 'await') {
let msg = await message.channel.send("Vote!");
await msg.react(agree);
await msg.react(disagree);
const reactions = await msg.awaitReactions(reaction => reaction.emoji.name === agree || reaction.emoji.name === disagree, {
time: 15000
});
message.channel.send(`Voting complete! \n\n${agree}: ${reactions.get(agree).count-1}\n${disagree}: ${reactions.get(disagree).count-1}`);
}
SyntaxError: await is only valid in async function
As it says, await can only be used inside an async function. So if this code is inside a function, make that function async. For example, if the surrounding function looks like this:
function doStuff() {
if(command === 'await'){
let msg = await message.channel.send("Vote!");
await msg.react(agree);
await msg.react(disagree);
const reactions = await msg.awaitReactions(reaction => reaction.emoji.name === agree || reaction.emoji.name === disagree, {time:15000});
message.channel.send(`Voting complete! \n\n${agree}: ${reactions.get(agree).count-1}\n${disagree}: ${reactions.get(disagree).count-1}`);
}
}
Change it to this:
async function doStuff() { // <--- added async
if(command === 'await'){
let msg = await message.channel.send("Vote!");
await msg.react(agree);
await msg.react(disagree);
const reactions = await msg.awaitReactions(reaction => reaction.emoji.name === agree || reaction.emoji.name === disagree, {time:15000});
message.channel.send(`Voting complete! \n\n${agree}: ${reactions.get(agree).count-1}\n${disagree}: ${reactions.get(disagree).count-1}`);
}
}
If this code is not in a function (ie, it's at the topmost scope a script), then you'll need to put it in one. It could be an immediately invoked function if desired
(async function () {
if (command === 'await') {
const msg = await message.channel.send('Vote!');
await msg.react(agree);
await msg.react(disagree);
const reactions = await msg.awaitReactions(reaction => reaction.emoji.name === agree || reaction.emoji.name === disagree, { time: 15000 });
message.channel.send(`Voting complete! \n\n${agree}: ${reactions.get(agree).count - 1}\n${disagree}: ${reactions.get(disagree).count - 1}`);
}
})();

Categories