Detect if member has a role - javascript

I am building a Discord bot, more specific, a rolecolor command. I made a version of this command, that worked. Only problem was that it was extremly inefficient, it took like 5 minutes for it to respond. This was because there where a lot of 'if' statements and other things the bot had to check before executing anything. The file had 129K+ lines, and my whole editting program was lagging. I now have a new plan, that is probably much more efficient:
The bot checks if a member has any roles that start with "SRC -". SRC means server role color, just a name every role has that is dedicated to being cosmetic. All my colorrole names start with "SRC - name" If it detects any, delete them. Await this process, and after that, add the new color. I have like 205 roles for colors. I CAN just do:
message.guild.members.cache
.get(user.id)
.roles.remove(roleone);
message.guild.members.cache
.get(user.id)
.roles.remove(roletwo);
This works, but then again, inefficient. Discord isn't that fast with deleting and adding roles. When I ran a test, it didn't give me any errors. Despite this, I thought something was going wrong because my roles wheren't changing. When I was running a debug, and checked again, the roles where finally updated. It just takes a while before updating. I would like to have this more efficient. Here are some code samples:
Role adding, after the role removal:
if (args[0] === "1") {
message.guild.members.cache
.get(user.id)
.roles.add(roleone);
message.channel.send(errmsg);
console.log(logmsg);
else if (args[0] === "2") //etc
So my question is, does someone know how to detect if the member has any roles that start with name, so that only those roles can be deleted?

.remove() takes either a RoleResolvable, Array of RoleResolvables, or a Collection of RoleResolvables. You can filter the roles and pass it in
const member = message.guild.members.resolve(user.id)
const roles = member.roles.cache.filter(r => r.name.startsWith(`SRC -`))
await member.roles.remove(roles) // remove all roles from the member that start with "SRC -"

Related

Hiding messages from a discord user through javascript - Soft blocking

Blocking a user is a good feature of discord, but often enough I find myself wanting to block someone temporarily: not see their messages, but only for a certain period of time and without them knowing that I did so. Theoretically such a thing should be possible to do. I found a userscript that you are supposed to paste into the discord console once you start discord that serves the purpose of hiding messages from blocked users completely. Using the same principle, if instead of searching for blocked messages I could search for messages from a specific user, and then hide them, I could soft-block them for the duration of my current session. So the idea of this is to search all messages in a channel, check if a message was posted by a certain user that I want blocked, and if so, hide it.
To do so I have to figure out how to tie messages to their authors. There appears to be a different class for each new message that a user sends. But when a user sends multiple messages in a row, the classes are different. The first message contains the link to the user's avatar, which in turn contains the user's unique discord ID that he could be identified with. But his follow-up messages don't contain his avatar. And I can't find anything else that I could use to identify a user with except for that.
In the image above the classes that have groupStart contain the avatar links, whereas the classes without it are the follow-up messages from the same user that do not. Like so:
What kind of a loop would be able to include both the messages with some specified avatar, and the follow up messages without it?
As I see it, here's how you'll have to do it:
first identify the groupStart message, and then keep looking at the next messages until you reach a new groupStart message.
Luckily JavaScript keeps elements in the order that they're displayed when you use document.getElementsByClassName so you should just be able to set a variable to true when you hit the target, and then back to false when you hit a new person. This is my code:
function block(userid) {
return setInterval(() => {
let deleteMessages = false;
[...document.getElementsByClassName('message-2qnXI6')].forEach(i => {
if(i) {
if(i.className.match('groupStart-23k01U')) {
if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid) {
i.style.display = 'none'
deleteMessages = true
} else deleteMessages = false
}
else if(deleteMessages) i.style.display = 'none'
}
})
deleteMessages = false
}, 300)
}
The function block sets an interval for 300 seconds to:
First, get all the messages: [...document.getElementsByClassName('message-2qnXI6')]
Then for each message check to see if it's a groupStart element: if(i.className.match('groupStart-23k01U'))
If it is, it'll check to see if it's a message from the blocked user:
if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid)
If it is, it'll delete that message and set deleteMessages to true:
i.style.display = 'none'
deleteMessages = true
If it isn't, it'll set deleteMessages to false, so that the next messages don't get deleted.
Going back, if the message isn't a groupStart message, it'll check to see if deleteMessages is true (which would be the first message in the group was from a blocked user, and therefore this message is from a blocked user). If it is, it'll delete it.
Everything should be reset with a simple ctrl+r
Just copy and paste this (the minified version of my code):
function block(e){return setInterval(()=>{let t=!1;[...document.getElementsByClassName("message-2qnXI6")].forEach(n=>{n&&(n.className.match("groupStart-23k01U")?([...n.children].find(e=>e.className.match("contents-2mQqc9")).children[0].src||"/1/").split("/").find(e=>e.match(/^\d+$/))===e?(n.style.display="none",t=!0):t=!1:t&&(n.style.display="none"))}),t=!1},300)}
into the console, and then to block someone type block('<userid>') (make sure the user id is a string and not a number), and it should start working. Also, when you do, it should return a number, just type clearInterval(number) to stop it from blocking new messages.
If you're wondering about this line:
if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid)
There's a few hackey things I did here:
I start by getting an array of all the messages children, then I find the child with the userID in it (i.className.match('contents-2mQqc9')). If I don't I just use a placeholder to avoid errors.
Then I split via /s because the user id is one of the paths. Then I find which part of the path is the user id by checking to see if it's only numbers (i.match(/^\d+$/)). Finally once I've done all that I check to see if it's the same as the userid.
Here's a quick example:
https://cdn.discordapp.com/avatars/847295719724247388/c9af8fff1110025e6aae862492b4aa29.webp?size=256 (this isn't a real link) => ['https:', '', 'cdn.discordapp.com', 'avatars', '847295719724247388', 'c9af8fff1110025e6aae862492b4aa29.webp?size=256'] => '847295719724247388' is made completely of numbers, so: '847295719724247388'
Unfortunately, if you use this on too many messages by the same person in a row discord will really glitch out, so you'll have to watch for that (note this was testing it on 1000+ messages in a row by the same person). It seems like problems start to happen at around 100, but don't become an issue until it's up to 200 - 300, and even then it'll sometimes work if you wait for a second.
Hopefully if this doesn't work for you you'll at least have an idea of what to do.

Roles checker bot - Discord.js - ReferenceError: member is not defined

I'm trying to set up a bot for my Discord server. Basically, whenever anyone type "test" to a specific channel (help-channel) the bot will display their roles. If they have a role, say, Baker, the bot will say "You're all set, enjoys them sweet cakes!". If they don't, the bot will say "You do not have the Baker role."
Here's my code:
client.on('message', (message) => {
if (message.content === 'test') {
if (member.roles.cache.some((role) => role.name === '<Baker>'))
message.reply("You're all set , enjoys them sweet cakes !");
else message.reply('You do not have the Baker role.');
}
});
I can't get it to work; the error log said:
ReferenceError: member is not defined.
Also, I have multiple roles on the server (Baker, Tester, Chief, etc.). So, do I have to write the code for each of them?
You're getting this error because member is in fact, not defined. Instead, you'll want to use message.member
As for your second question, probably yes. Something that comes to mind would be creating an array of every role name and then creating a for...of loop.
const roles = ['<Baker>', '<Dancer>', '<Programmer>', '<Actor>'];
// iterate a loop through all elements in the array
for (role of roles) {
if (message.member.roles.cache.some((r) => r.name === role))
console.log(`${message.author.username} has the ${role} role.`);
}
You could also mess around with the .filter() method.
const roles = ['<Baker>', '<Dancer>', '<Programmer>', '<Actor>'];
console.log(
`Out of the roles in the array, ${
message.author.username
} has these roles: ${roles
.filter((role) => message.member.roles.cache.some((r) => r.name === role))
.join('\n')}`
);
member is not defined that's right. If you want member to be the person who initiated the command you would need to use message.member, if you want to get a specified member you could use message.guild.members.cache.get(<user id here>).
And you can shorten your code, by checking for roles using roles' ids, then it would look like if(message.member.roles.cache.has(<role id>). It would also prevent from checking for roles that have same names

Issues Looping members in an Async function, Discord.js

I am new here, and myself and my friend are very stuck with our Discord bot code where we are trying to have my discord bot check if someone is "streaming" to twitch by looping through members that have a Role called "Twitch Streamer". The problem is, we know the first half of the code works which checks if the owner, Me, is streaming, but for some reason, the second half of the code stopped working and is spitting out something in the console of "undefined". If I paste the code, could someone be willing to help us out? We are completely lost and running out of ideas.
My approach on task like this would be like this Discord.js v12 approach
Filter out the users with specific role - loop iteration decrease - optimization.
const streamers = server.members.cache.filter(user => user.roles.cache.has(StreamerRole);
To check if streamer is currently streaming at a time we are using loop. We are pushing streamers that are streaming to array with their IDs (d.js snowflakes).
const activeStreamers = [];
const IS_STREAMING = new Discord.Activity({
type: 'STREAMING',
...rest
})
streamers.forEach(streamer => {
const streamerActivity = streamer.presence.activities.has(IS_STREAMING);
if(streamerActivity) activeStreamers.push(streamer.user.id);
}

Check if a mention is a user - discord

I want to make a simple kick function that kicks a player with mention.
But I first want to check if a mention is a user. which I have no idea how.
let member = message.mentions.members.first();
if ("member.something") { // if member is a user in the server.
member.kick().then((member) => {
channel.send(`${member} has been kicked! :wave:`)
});
} else {
channel.send(`Error: ${member} can't be kicked!`)
}
Here are the options that I can think of:
User.bot Documentation
if (!member.user.bot)
To check if the user is not a bot
GuildMember.kickable Documentation
if (member.kickable)
To check if the member is kickable
To check if a member exists first, check out:
https://stackoverflow.com/a/53284678/11425141
You can do this in multiple ways.
You can either check for which permissions have in order to disallow other's from kicking them (For instance, KICK_MEMBERS). That would look something like this:
let member = message.mentions.members.first();
if (member.hasPermission("KICK_MEMBERS)) return message.channel.send("That member can also kick!")
You can also check if they got a certain role which disallows them to be kicked. (Could be moderator role, could be a protected role)
//Get role by ID (Allows you to later change its name, ID will remain the same)
let modRole = message.guild.roles.get("MODROLE_ID");
if (member.role.has(modRole.id)) return message.channel.send("This member is a moderator")
//Find role by name. Means if you change the name of this, you need to change code too.
let protectedRole = message.guild.roles.find(r => r.name === "Protected from kicking")
if (member.role.has(protectedRole.id)) return message.channel.send("This member is protected")
Lastly (that I know of), you can check if they're kickable. But all that does is, say if someone above them is trying to kick them, it will do it.
So if, say an admin, is testing or something, it will just kick the user if kickable = true
if (member.kickable) {
member.kick()
} else {
message.channel.send("This member is above you!)"
}
If you just want to check if they're an actual user, throw this line in at the top:
if (!member.bot) {
//If they're a user
} else {
//If they're a bot
}
There are obviously a lot of fun things you can do with this. But these are the basics.
Hope I helped a bit, and sorry for this late response, I was pretty much just scrolling through the forum and found this unanswered question.

How to create a command that only who have one of the roles can use?

let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
How do you make a command that only people who have one of the roles can use it?
Thank you!
What you can do is that, on a message event, you run the command, and you can check the member's roles for one of the ones in the array.
Heres what that would look like:
client.on("message", msg => {
if(command === "whateverItIs") {
let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
for(i=0;i<staffrole.length;i++) {
if(msg.member.roles.filter((role) => role.id == staffrole[i]).size > 0) {
//run the code
return;
}
}
}
})
On a message event, with the determined command, the bot will check through each of the staff roles and if the message author 's roles includes one of the staffrole's then the command will run.
I would recommend doing something like this:
First, set your command name in the client's message listener:
// ... (in client message listener)
switch(command) {
case '<your command>':
runIfRoleIncluded(message);
break;
}
Next, get the role Id from the message that was sent and check if that message's role Id is in your staffrole array:
function runIfRoleIncluded(message) {
let rolesCollection = message.member.roles;
let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
// only 1 member can send a message, so get role collection's first key (id)
let messageRoleId = rolesCollection.firstKey();
// check if message's role id is in staff role array
if (staffrole.includes(messageRoleId)) {
// do stuff here
// ...
}
}
The .roles property of the .member object is a Collection, which is why you have to use the .firstKey() method. You can also turn the Collection into a normal js Array, but the way I outlined above is easier.
Started looking at this... Don't know the discord space very well but got an example bot and with a hello world ping, also found this pretty sweet Github gist that lays out fairly well how to build what amounts to a command switch statement. Making a lot of guesses here -- as a note for future questions it would be very helpful for you to add in some code on what you are trying to do -- a single variable set to an array isn't much to go on...
After Reading what #Raymond Zhang said, because, yeh that's what I was doing...
this is straight out of the Github gist I linked ->
...
if(command === "kick") {
if(!message.member.roles.some(r=>["Administrator","Moderator"].includes(r.name)) )
return message.reply("Sorry, you don't have permissions to use this!");
...
I have tested this and it works great, although it checks against the roles name not a number. It would help if you updated you answer to explain your process. More info = better answer. :)

Categories