I am making a discord chatbot, but something I would like it to do is to join a random voice channel. I have tried the following from a different example, but you need to specify a channel ID. Which doesn’t suit my needs.
const channel = message.guild.channels.get('voiceChannelID');
I've also tried this from Check if a channel is a voice channel but it also requires a specific channel ID.
const channelObject = message.guild.channels.cache.get('channel id here'); // Gets the channel object
if (channelObject.type === 'voice') return; // Checks if the channel type is voice
It would be greatly appreciated if you could answer with some code that would find a random voice channel.
You can fetch all channels, filter them by their type and use Collection#random() to pick a random one from the returned collection:
let channels = await message.guild.channels.fetch();
let voiceChannels = channels.filter(ch => ch.type === 'GUILD_VOICE');
let randomVoiceChannel = voiceChannels.random();
Please note that in discord.js v13, VoiceChannel#type is GUILD_VOICE instead of voice. For more info see this answer.
Update: If you're using discord.js v12, you can use the following:
let channels = message.guild.channels.cache;
let voiceChannels = channels.filter((ch) => ch.type === 'voice');
let randomVoiceChannel = voiceChannels.random();
... and it's probably time to upgrade :)
I've had to grab all of the channels and filter out the voice channels before, so I just grabbed that code and flipped it around and added some random to it.
What I did:
let channels = Array.from(message.guild.channels.cache.keys());
const c = channels.filter(v => message.guild.channels.resolve(v).isVoice() == true);
const index = Math.floor(Math.random() * c.length);
const randomVoiceChannel = c[index];
The first line grabs all of the channels in the server.
The 2nd line removes the non-voice channels.
And finally the last 2 lines generate a random index from the array and outputs a value.
const randomVoiceChannel = Array.from(message.guild.channels.cache.keys()).filter(v => message.guild.channels.resolve(v).isVoice() == true)
[Math.floor(Math.random() * Array.from(message.guild.channels.cache.keys()).filter(v => message.guild.channels.resolve(v).isVoice() == true).length)];
nifty 1-liner (please don't use this its incredibly unreadable I just thought it was funny)
Related
I have this command to execute every day at 9 pm, but there is always a chance that my bot targets one of the two bots I have on my server with random(). How do I make it so it doesn't target them? perhaps there is a way to exclude members with a certain role since I have both bots with a role to separate them from the regular member list.
let KillerMessage = new cron.CronJob('00 00 21 * * *', () => { //seconds, minutes, hours, month, day of month, day of week
const guild = client.guilds.cache.get('ID');
const channel = guild.channels.cache.get('ID');
const user = client.users.cache.random(); //random user
const exampleEmbed = new MessageEmbed()
.setColor('#0099ff')
.setTitle(`The BLACKENED for this trial is: ${user.username}`)
.setImage(user.displayAvatarURL())
channel.send({ embeds: [exampleEmbed] });
});
KillerMessage.start();
We can do this in different ways, and some of them are:
Using the filter() JavaScript method:
// Get the cache users list and filter the users that aren't a bot, creating a new array with only non-bot users.
let user = client.users.cache.filter(user => !user.bot).random();
Using a while loop:
// This loop randomizes again, until the chosen user is not a bot.
let user = client.users.cache.random();
while (user.bot) user = client.users.cache.random();
let user = client.users.cache.random();
while (user.bot) user = client.users.cache.random();
Basically what this does is it tries to get a random user from cache until it gets a non-bot user.
I am trying to build an RPS game in my Discord bot. I want to add the functionality that if the word you choose does not exist in the list, it will return a message. This is my code so far:
async execute(message, args, cmd, client, Discord, profileData) {
if (!args.length)
return message.channel.send('To keep it fair, also send your pick!'); //If you don't
//send a second
//argument.
const list = ['rock', 'paper', 'scissor']; // What the bot accepts.
const rps = ['Rock! - ⛰', 'Paper! - 📄', 'Scissor! - ✂']; // Where the bot can
// randomly pick from
const random = rps[Math.floor(Math.random() * rps.length)];
for (var i = 0; i < list.length; i++) {
if (message.content.includes(list[i])) {
// If it does exits,
// just execute the
// command.
message.channel.send(random);
break;
} else {
message.channel.send(`\`${args}\` is not a valid option.`); //Return if the
//argument you are
//sending does not exist
//in the list.
break;
}
}
},
I thought this would work, and already did many other variants of this one. But still, even though for example paper is in the list, it still sends me ".. is not a valid option". It only works with rock. So what I want here is that if you send anything other than the values inside the array, it returns.
To make it short, I have two questions:
How can I fix this issue?
If I capitalize the values in the list (Rock), will it still work if I send rock?
Here is the link to my problem:
https://imgur.com/rhESIZM
You don't have to use a for loop. Instead of checking the whole message again, you only need to check the first argument (args[0]). You can simply use Array#includes and to make it case insensitive, convert this argument to lowercase. Your list already includes lowercase letters only, so the following will work:
async execute(message, args, cmd, client, Discord, profileData) {
if (!args.length)
return message.channel.send('To keep it fair, also send your pick!');
const list = ['rock', 'paper', 'scissors'];
const rps = ['Rock! - ⛰', 'Paper! - 📄', 'Scissors! - ✂'];
const random = rps[Math.floor(Math.random() * rps.length)];
if (!list.includes(args[0].toLowerCase())) {
return message.channel.send(`\`${args[0]}\` is not a valid option.`);
}
// args[0] is valid
message.channel.send(random);
},
serverinfo interaction slash command showing 3 channels, but I have only 2 channels in the server.
It is including the category too, how I fix it?
Here is the code -
if (commandName === 'serverinfo') {
let serverinfoembed = new MessageEmbed()
.setAuthor(`Info for ${interaction.guild.name}`)
.setColor('#4269f5')
.addField('Owner', `<#${interaction.guild.ownerId}>`, true)
.addField('Channels', `${interaction.guild.channels.cache.size}`, true)
return interaction.reply({ embeds: [serverinfoembed] });
};
In Discord.js, it counts categories as channels. To filter out categories, you need to do the following:
interaction.guild.channels.cache.filter(c => c.type !== "GUILD_CATEGORY").size
This will display the amount of cached text and voice channels. Filtering out voice/text channels are just as easy:
//Getting text channels
interaction.guild.channels.cache.filter(c => c.type === "GUILD_TEXT").size
//Getting VCs
interaction.guild.channels.cache.filter(c => c.type === "GUILD_VOICE").size
You need to filter what channels you want to count for example text channels
interaction.guild.channels.cache.filter(ch => ch.type === 'GUILD_TEXT').size
All of the channel types you can see from here
I am trying to make a command, with discord.js, that will display the roles of a guild and member count of each role! So far everything I am trying , it returns me all time to an error !
Here is the code I am trying:
const roles = message.guild.roles.cache.map(role => role).sort((a, b) => b.position - a.position).slice().join('')
I am struggling to find a way how to display member count for each role!
I have been trying this :
const size = message.guild.roles.cache.get(roles).members.map(m=>`${m}`).size;
But it is returning an error :
TypeError: Cannot read property 'members' of undefined
All I want to display is like the photo:
What you can do is fetch the server roles, and sort them from the highest position to the lowest and map them to look like you want.
Here's an example:
let roles = await message.guild.roles.fetch();
message.channel.send(
roles.cache.sort((a, b) => a.position - b.position).map((r) => `${r.name} - ${r.members.size}`),
{ split: true, code: true }
)
This should send the message like the one in the image
Use this:
await <message>.guild.roles.fetch(); //<message> is a placeholder for whatever variable you use for message
const roleArray = <message>.guild.roles.cache.array().sort((a, b) => b.position - a.position)
var members = roleArray.map((r) => {
members.push(r.members.size) //idk if this is right
});
//Now members and roleArray will have paired indexes (roleArray[0] has as many members as members[0])
Sorry if it doesn’t work, I sometimes mess up .toArray() and .array(), and I didn’t test it.
This would do it i guess
function getRoleCount() {
message.channel.send(message.guild.roles.cache.map(x => `${x.name} - ${x.members.size}`).join('\n'));
}
getRoleCount();
each element of message.channel.send(message.guild.roles.cache has name and members property which corresponds to the role name and members with the role. members.size returns the number of people who has the role. Therefore the output of the function would be
roleA - 10
roleB - 15
etc on every roles in the guild
Whats a good way to find all users to execute a kick on them if they all contained a phrase in their name like "ihatemelons" for example.
let server = message.guild.id
//grab all discord names
let list = client.guilds.cache.get(server)
console.log(`All Users In Guild: ${list}`)
list.members.cache.forEach(member => console.log(member.user.username));
//Regex term to search
let re = (/_/ig)
//Search all of them
let usersFound = list.members.cache.forEach.match(re)(member => console.log(member.user.username))
list.members.cache.forEach(usersFound => console.log(member.user.username));
//What to do with the users that have the phrase in their name
message.reply(`Found:${usersFound}`)
Except I am stuck on where I search because
let usersFound = list.members.cache.forEach.match(re)(member => console.log(member.user.username)) doesnt work
Well you can use a regex to find the phrases you don't like, for example if you don't like the word creepy in username, you can simply do this:
let regex = /creepy/ig
regex.test("creepyUsername"); // Outputs true
for more info about regex:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
message.guild.members.cache.filter(member => member.user.username.includes('ihatemelons'))
Since GuildMemberManager.cache returns a Collection, you can utilise the methods provided by Collection and Map. Collection.filter() acts like Array.filter(), but returns a Collection instead.
Edit
This works for me:
const members = await message.guild.members.fetch();
let usersFound = members.filter(member => member.user.username.includes('ihatemelons'));
// OR: case-insensitive:
let usersFound = members.filter(member => /ihatemelons/i.test(member.user.username));
// OR
let usersFound = members.filter(member => member.user.username.toLowerCase().includes('ihatemelons'));
usersFound.forEach(member => console.log(member.user.username));
Make sure you have enabled the privileged intent for receiving full member lists in the Discord Developer Portal.