So i want that my poll command asks for the channel and the question in a conversation, but i haven't figured out how to get the channel when the user only gives the ID, i have figured out that i have to use .content but i still don't know how to implement it.
My code:
run: async(message, client, args) => {
// Channel where the poll should take palce
await message.channel.send(`Please provide a channel where the poll should take place or cancel this command with "cancel"!`)
const response1 = await message.channel.awaitMessages(m => m.author.id === message.author.id, {max: 1});
const channel = response1.first().mentions.channels.first() || response1.content.guild.channels.cache.get()
if (!channel) {
return message.channel.send(`You did not mention or provide the ID of a channel where the poll should take place!`)
}
// Channel where the poll should take palce
await message.channel.send(`Please provide a question for the poll!`)
const response2 = await message.channel.awaitMessages(m => m.author.id === message.author.id, {max: 1});
let question = response2.first();
if (!question) {
return message.channel.send(`You did not specify your question!`)
}
const Embed = new Discord.MessageEmbed()
.setTitle(`New poll!`)
.setDescription(`${question}`)
.setFooter(`${message.author.username} created this poll.`)
.setColor(`0x0099ff`)
let msg = await client.channels.cache.get(channel.id).send(Embed)
await msg.react("👍")
await msg.react("👎")
}
And it is this line: response1.content.guild.channels.cache.get() that is writte wrong by me but idk what i have to change/where to add the .content so that it works.
Would be nice if someone can help me.
My message event for the args:
module.exports = async (client, message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
if (!message.guild) return;
if (!message.member) message.member = await message.guild.fetchMember(message);
const args = message.content.slice(prefix.length).split(/ +/g);
const cmd = args.shift().toLowerCase();
if (cmd.length == 0) return;
let command = client.commands.get(cmd)
if (!command) command = client.commands.get(client.aliases.get(cmd));
if (command) {
try {
command.run(message, client, args)
} catch (error) {
console.error(error);
message.reply('There was an error trying to execute that command!');
}
}
}
You need the content to grab the id, but I assume that's already handled by the code that generates the args parameter.
To get the guild you can use Message.guild, and then just Guild.channels.cache.get()
That means that your code would look like this:
const channel = response1.first().mentions.channels.first()
|| response1.first().guild.channels.cache.get(args[0]) // Assuming args[0] is your id
So i went around it with making another constructor means:
const ID = client.channels.cache.get(response1.first().content)
const channel = response1.first().mentions.channels.first() || ID
It works fine now
Related
I am making a discord bot and i use the following code while having all the correct npm stuff installed and ffmpeg working. This bot was working earlier today and i messed it up so i reverted to the old code and now it isnt working.
const Discord = require('discord.js');
const api = require("imageapi.js");
const client = new Discord.Client();
const YouTube = require('simple-youtube-api')
const ytdl = require('ytdl-core')
const prefix = '!';
client.once('ready', () => {
console.log("Online!");
client.user.setActivity('!help');
});
client.on('message', async message => {
if(message.author.bot) return
if(!message.content.startsWith(prefix)) return
const args = message.content.substring(prefix.length).split("")
if(message.content.startsWith(`${prefix}play`)) {
const voiceChannel = message.member.voice.channel
if(!voiceChannel) return message.channel.send("You need to be in a voice channel to play music")
const permissions = voiceChannel.permissionsFor(message.client.user)
if(!permissions.has('CONNECT')) return message.channel.send(`I don\'t have permission to connect`)
if(!permissions.has('SPEAK')) return message.channel.send(`I don\'t have permission to speak`)
try {
var connection = await voiceChannel.join()
} catch(error){
console.log("error")
return message.channel.send(`There was a error when connection to the voice channel`)
}
const dispatcher = connection.play(ytdl(args[1]))
.on('finish', () => {
voiceChannel.leave()
})
.on('error', error => {
console.log(error)
})
dispatcher.setVolumeLogarithmic(5 / 5)
} else if (message.content.startsWith(`${prefix}stop`)) {
if(!message.member.voice.channel) return message.channel.send("You need to be in a voice channel to stop the music")
message.member.voice.channel.leave()
return undefined
}
})```
This means that args[1] is not a valid youtube URL or ID. When you split the message:
const args = message.content.substring(prefix.length).split("")
You split by '' instead of ' '. This is the difference of splitting by every character vs every space.
const str = 'Hello World';
console.log(str.split(''));
console.log(str.split(' '));
So, you probably called ytdl('w') as in www.youtube.com/.... Even though you fixed this problem, you should add error handling to make sure:
args[1] exists
args[1] is a valid ID
if (!args[1]) return message.channel.send('...');
try {
const audio = ytdl(args[1]);
} catch (err) {
return message.channel.send('...');
}
I am trying to make it so when you get to a certain amount of reactions my bot will send a message and if somebody can help here is my code
.then(function(sentMessage) {
sentMessage.react('👍').catch(() => console.error('emoji failed to react.')).message.reactions.cache.get('👍').count;
const filter = (reaction, user) => {
return reaction.emoji.name === '👍' && user.id === message.author.id;
};
message.awaitReactions(filter, { max: 2, time: 00, errors: ['time'] })
.then(collected => console.log(collected.size))
.catch(collected => {
console.log(`After a minute, only ${collected.size} out of 4 reacted.`);
});
});
})
Instead of awaitReactions, you could also use createReactionCollector which is probably easier to use and its collector.on() listeners are more readable than awaitReactions's then() and catch() methods.
You won't need to use message.reactions.cache.get('👍').count to check the number of reactions, as the end event fires when you reached the maximum and you can send a message inside that.
Also, in your filter, you don't need to check if user.id === message.author.id as you will want to accept reactions from other users. However, you can check if !user.bot to make sure that you won't count the bot's reaction. You can also remove the time option if you don't want to limit the time your bot collects reactions.
Another error was that you called .awaitReactions() on the message itself not the sentMessage.
Check out the working code below:
// v12
client.on('message', async (message) => {
if (message.author.bot || !message.content.startsWith(prefix)) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
const MAX_REACTIONS = 2;
if (command === 'react') {
try {
// send a message and wait for it to be sent
const sentMessage = await message.channel.send('React to this!');
// react to the sent message
await sentMessage.react('👍');
// set up a filter to only collect reactions with the 👍 emoji
// and don't count the bot's reaction
const filter = (reaction, user) => reaction.emoji.name === '👍' && !user.bot;
// set up the collecrtor with the MAX_REACTIONS
const collector = sentMessage.createReactionCollector(filter, {
max: MAX_REACTIONS,
});
collector.on('collect', (reaction) => {
// in case you want to do something when someone reacts with 👍
console.log(`Collected a new ${reaction.emoji.name} reaction`);
});
// fires when the time limit or the max is reached
collector.on('end', (collected, reason) => {
// reactions are no longer collected
// if the 👍 emoji is clicked the MAX_REACTIONS times
if (reason === 'limit')
return message.channel.send(`We've just reached the maximum of ${MAX_REACTIONS} reactions.`);
});
} catch (error) {
// "handle" errors
console.log(error);
}
}
});
If you're using discord.js v13, there are a couple of changes:
you'll need to add the GUILD_MESSAGE_REACTIONS intents
the message event is now messageCreate
the collector's filter is inside the options object
// v13
const { Client, Intents } = require('discord.js');
const client = new Client({
intents: [
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
],
});
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();
const MAX_REACTIONS = 2;
if (command === 'react') {
try {
// send a message and wait for it to be sent
const sentMessage = await message.channel.send('React to this!');
// react to the sent message
await sentMessage.react('👍');
// set up a filter to only collect reactions with the 👍 emoji
// and don't count the bot's reaction
const filter = (reaction, user) => reaction.emoji.name === '👍' && !user.bot;
// set up the collecrtor with the MAX_REACTIONS
const collector = sentMessage.createReactionCollector({
filter,
max: MAX_REACTIONS,
});
collector.on('collect', (reaction) => {
// in case you want to do something when someone reacts with 👍
console.log(`Collected a new ${reaction.emoji.name} reaction`);
});
// fires when the time limit or the max is reached
collector.on('end', (collected, reason) => {
// reactions are no longer collected
// if the 👍 emoji is clicked the MAX_REACTIONS times
if (reason === 'limit')
return message.channel.send(`We've just reached the maximum of ${MAX_REACTIONS} reactions.`);
});
} catch (error) {
// "handle" errors
console.log(error);
}
}
});
And the result:
You want to check the collected.size with an if statement like so:
let amount = 4; // any integer
if (collected.size /* returns an integer */ === amount) {
console.log(`Got ${amount} reactions`)
}
Hope I got the issue right.
If I understand it correctly, then you can just change the parameters for the awaitMessage method. You can remove the time: 00, errors: ['time'] arguments since they're optional and keep the max: 2. That way, the function will only finish once there are 2 reactions (in this case).
I would recommend removing the user.id === message.author.id; from the filter since it seems like you want multiple users to react to the message.
For more information, you can check the discord.js guide or the documentation for awaitReactions.
Code:
message.channel.send("Message reacting to.").then(function (sentMessage) {
sentMessage.react('👍').catch(() => console.error('emoji failed to react.'));
const filter = (reaction, user) => {
return reaction.emoji.name === '👍';
};
message.awaitReactions(filter, { max: 2 })
.then(collected => console.log(collected.size))
});
So the error I'm receiving but cannot find is accepting any arguments as a valid command after a space. I believe this might be a .split() error, as if you match the arguments exactly it will produce a different output. Now if you use an argument that is not listed, it will still produce the original command, !qa = !qa mollusk
It should return an error, when an argument passes but is not present, but does not do so.
Here is my index and everything associated for replication:
const fs = require('fs');
const Discord = require('discord.js');
const { prefix, token } = require('./config.json');
const featureFiles = fs.readdirSync('./commands/features').filter(file => file.endsWith('.js'));
for (const file of featureFiles) {
const command = require(`./commands/features/${file}`);
client.commands.set(command.name, command);
}
client.on('message', message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
//.trim() is removed, see notes below on why
const args = message.content.slice(prefix.length).split(/ +/g);
const commandName = args.shift().toLowerCase();
const command = client.commands.get(commandName)
|| client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
if (!command) return;
if (command.guildOnly && message.channel.type !== 'text') {
return message.reply('That command cannot be used inside a DM');
}
if (command.args && !args.length) {
let reply = `You didn't provide any arguments!`;
if (command.usage) {
reply += `\nThe proper usage would be: \`${prefix}${command.name} ${command.usage}\``;
}
return message.channel.send(reply);
}
try {
command.execute(message, client, args);
} catch (error) {
console.error(error);
message.channel.send('Error trying to execute command');
}});
client.login(token);
I removed .trim() as it was reading whitespaces in between the prefix and command name, which I did not want, so one could use 100 spaces between the prefix and command, and it will execute it.
Here is my module I am building:
const Discord = require('discord.js');
module.exports ={
name: 'qa',
description: 'Find members who have the QA role and search by specialty.',
usage: '[OptionalArg]',
execute(message, client, args) {
if(message.channel.type === 'dm') {
message.channel.send('Command can\'t be used here')
}
try{
let roleID = "738530035526402100";
let membersWithRole = message.guild.roles.cache.get(roleID).members.map(m=>m.user.tag).join('\n');
const embed = new Discord.MessageEmbed()
.setColor('#008798')
.setTitle('Qualified Advice')
.setDescription(`${membersWithRole}`)
.setTimestamp(new Date)
const testing = new Discord.MessageEmbed()
.setColor('#008798')
.setTitle('Test QA')
.setDescription(`test`)
.setTimestamp(new Date)
const data =[embed];
if (args[0] === 'test') {
return message.channel.send(testing)
}
message.channel.send(data, 'To see focus types, type `!qa [arg]`, example `!qa test`', {split: true});
} catch(e) {
console.log(e)
}
},
};
Am I right for thinking it's found in .split()? This has me stumped, maybe I'm overlooking it, it also does the same thing with regular commands that do not have any arguments. This has lead to believe me this is in the index. I want it to simply return if other input is made (like ?qa alksjdkalsjd) that is not specified as an arg.
Discord.js = v12
What you want to do is restructure your if like this:
if(args.length === 0) { // this runs everytime there are no args provided
return message.channel.send(data, 'To see focus types, type `!qa [arg]`, example `!qa test`', { split: true });
}
if (args[0] === 'test') {
return message.channel.send(testing)
}
/* ........... */
return message.channel.send(error); // send a errror here if the args were not handled by the above cases
How do I make it so that when someone reacts with the first emoji in this command, the bot deletes the message and sends it to another channel?
Current Code:
const Discord = require("discord.js");
module.exports.run = async (bot, message, args) => {
if (!message.member.hasPermission("MANAGE_MESSAGES"))
return message.channel.send("You are not allowed to run this command.");
let botmessage = args.join(" ");
let pollchannel = bot.channels.cache.get("716348362219323443");
let avatar = message.author.avatarURL({ size: 2048 });
let helpembed = new Discord.MessageEmbed()
.setAuthor(message.author.tag, avatar)
.setColor("#8c52ff")
.setDescription(botmessage);
pollchannel.send(helpembed).then(async msg => {
await msg.react("715383579059945512");
await msg.react("715383579059683349");
});
};
module.exports.help = {
name: "poll"
};
You can use awaitReactions, createReactionCollector or messageReactionAdd event, I think awaitReactions is the best option here since the other two are for more global purposes,
const emojis = ["715383579059945512", "715383579059683349"];
pollchannel.send(helpembed).then(async msg => {
await msg.react(emojis[0]);
await msg.react(emojis[1]);
//generic filter customize to your own wants
const filter = (reaction, user) => emojis.includes(reaction.emoji.id) && user.id === message.author.id;
const options = { errors: ["time"], time: 5000, max: 1 };
msg.awaitReactions(filter, options)
.then(collected => {
const first = collected.first();
if(emojis.indexOf(first.emoji.id) === 0) {
msg.delete();
// certainChannel = <TextChannel>
certainChannel.send(helpembed);
} else {
//case you wanted to do something if they reacted with the second one
}
})
.catch(err => {
//time up, no reactions
});
});
I was working on a discord bot and for a verification channel. I want users to type only the /verify command: every message or command except /verify they type should get deleted automatically. How can I do this?
Current code:
if (command === "verify") {
if (message.channel.id !== "ChannelID") return;
let role = message.guild.roles.find(rol => rol.name === 'Member')
const reactmessage = await message.channel.send('React with 👌 to verify yourself!');
await reactmessage.react('👌');
const filter = (reaction, user) => reaction.emoji.name === '👌' && !user.bot;
const collector = reactmessage.createReactionCollector(filter, {
time: 15000
});
collector.on('collect', async reaction => {
const user = reaction.users.last();
const guild = reaction.message.guild;
const member = guild.member(user) || await guild.fetchMember(user);
member.addRole(role);
message.channel.send(`Verification Complete.. ${member.displayName}. You have got access to server. `)
});
message.delete();
}
You can add a check at the top of your client.on('message') listener:
client.on('message', message => {
let verified = !!message.member.roles.find(role => role.name == 'Member');
// ... command parsing ect...
if (!verified && command == 'verify') {...}
else if (verified) {
// other commands...
}
});