I am already building a discord.py bot. However, I want to make it assign roles without the use of prefix in a specific channel - I mean in #roles channel. If a member writes "Mage", and if Mage role is already created, bot will assign the role to member. I looked for a reaction role but I need something more specific. I am waiting for your ideas and help. Have a great day!
#client.event
async def on_message(message): # Using on_message event reference you dont need to have a prefix
guild = message.author.guild
if message.content.lower() == "what the message name should be": # Checks if the WHOLE message is that one word, so not if that one word was part of a message
role = discord.utils.get(guild.roles, name="role name") # Gets the role
if role is not None: # makes sure role exists
await message.author.add_roles(role) # Assigns role to the message author
Related
I'm new to python, so can someone help me with my code, because it is not working properly. When the user that I want joins it doesn't give it a role. I want to make it work for a specific user only to give a role when joining discord server.
#client.event
async def on_member_join(member):
member = get(member.id, id=member_id)
role = get(member.guild.roles, id=role_id)
await member.id(member)
await member.add_roles(role)
I don't even know why you're making this so complicated.
Since you already have the member as an "argument" you can work with it and don't have to define member again.
We can get the ID of member very easily with member.id. If we want to compare this with a real ID, we do the following:
if member.id = TheIDHere:
# Do what you want to do
The function for the role is correct, yet I cannot find a use for await member.id(member). What is the point of this/has it any use?
How you add the role at the end is also correct, but the code must be indented properly and best you work with an if / else statement, otherwise the bot will still give an error at the end in the console if always the wrong member joins.
The whole code:
#client.event
async def on_member_join(member):
role = discord.utils.get(member.guild.roles, id=IDOfTheRole) # Get the role from member.guild and the id
if member.id == TheIDHere: # If the member.id matches
await member.add_roles(role) # Add the role for the specific user
else: # If it does not match
return # Do nothing
You may also need to enable the members Intent, here are some good posts on that:
https://discordpy.readthedocs.io/en/stable/intents.html
How do I get the discord.py intents to work?
I am using async def on_raw_reaction_remove(payload) to track when a user removes a reaction..
How do I get the user who triggered the event? In my code i have my bot trigger this event by removing reactions in certain scenarios - but when this happens user = await client.fetch_user(user_id) always equals to the user who had reacted with the removed reaction and not the bot that removed it (i need to get the bot as user when the bot removes someone's reaction, so i can say if user == bot: return
I also tried
message = await channel.fetch_message(payload.message_id)
guild = message.guild
member = await guild.fetch_member(payload.user_id)
but it's the same.. the member is always pointing to the owner of the reaction that was removed, not the bot that's removing the reaction...
How can i get the one who is removing the reaction when using on_raw_reaction_remove?
(if it's relevant - i enabled intents in discord's developer portal and updated my code with
intents = discord.Intents.all()
client = discord.Client(intents=intents)
Thanks for your help, i wasted so much time on this already :frowning: (new to the discord api)
The answer is - there is nothing in the discord python API that can tell you who removed the reaction.
For my case, I solved it with a workaround - I just had to track if my bot removed a reaction with a variable - I am using a global variable to track when my bot removes a reaction and then just check later if the variable is True or False and respond accordingly and reset the variable back.
Thanks
What I did in this case was this:
guild = discord.utils.find(lambda g: g.id == payload.guild_id, bot.guilds)
member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)
You now just have to build this into your code
I made a command that anyone in the server can use, but i'm trying to make that when used on me the member loses his highest role and replace it with a specific one. And i'm having a bit of trouble, i can't remove roles from the member, tried the following codes:
role=member.top_role
await member.remove_roles(role)
and
roles=member.roles
role_list=roles[:-1]
await member.edit(roles=role_list)
edit:
here's the command i'm using to test if the "removing role function" is working:
#client.command()
async def take(ctx , member:discord.Member):
roles = member.roles
roles.reverse()
top_role = roles[0]
await member.remove_roles(top_role)
await ctx.send('top role removed')
I tried these and nothing happened, no errors, nothing. I made some tests dividing the code in parts and all of it works ok until the parts "await member.remove_roles(role)" in the first case and "await member.edit(roles=role_list)" in the second. Am i missing something for it to work?
edit: answer updated.
The ctx.author is a member.
You can find everything in the official Documentation. Discord.py
#client.command()
async def take(ctx):
roles = ctx.author.roles #list of roles, lowest role first
roles.reverse() #list of roles, highest role first
top_role = roles[0] #first entry of list
await ctx.author.remove_roles(top_role)
await ctx.send('top role removed')
right now I'm trying to make a command to delete a role and I'm trying to go off of what I used to create a role
#client.command()
async def createrole(ctx):
guild = ctx.guild
await guild.create_role(name="role")
and I can't figure out how to.
In order to delete a role, you need to do a bit more work than with creating a role. You would need to use the delete function in the Role object. So if you wanted to create a command named "delete role", you would need to first get the role object before you delete it. You could do that with the following:
#client.command(name="delete_role", pass_context=True)
async def delete_role(ctx, role_name):
#find role object
role_object = discord.utils.get(ctx.message.guild.roles, name=role_name)
#delete role
await role_object.delete()
I simply want my bot to add a role to a user in discord. Although the syntax seems simply, apparently I'm doing something wrong.I'm new to python, so I'd appreciate some pointers in the right direction!
bot = commands.Bot(command_prefix='!')
def getdiscordid(discordname):
for guild in bot.guilds:
for member in guild.members:
if member.name == discordname:
return member.id
#bot.command(name='role')
async def role(ctx):
await ctx.message.channel.send("Testing roles")
discordid = getdiscordid("Waldstein")
print ("id: " , discordid)
member = bot.get_user(discordid)
print ("member: ", member)
role = get(ctx.message.guild.roles, name="Egg")
print("role: ", role.name)
await member.add_roles(role)
print("done")
# error handler
#bot.event
async def on_command_error(ctx, error):
if isinstance(error, commands.errors.CheckFailure):
await ctx.send(error)
bot.run(TOKEN)
In this example he successfully retrieves the member, he can't find the Egg role, and doesn't add the role. [Edit: I corrected the line to retrieve the role, that works but still no added role. Added the error handler]
The key issue is that add_roles() adds roles to a Member object not a user.
Made a couple of tweaks...
Changed the get id to get member and return the member object.
changed the name of the command to add_role() to avoid using role as the command and a variable.
changed to await member.add_roles(role)
Try:
def get_member(discordname):
for guild in bot.guilds:
for member in guild.members:
if member.name == discordname:
return member
#bot.command(name='add_role')
async def add_role(ctx):
await ctx.message.channel.send("Testing roles")
member = get_member("Waldstein")
print(f'member is {member} type {type(member)}')
role = get(ctx.guild.roles, name="Egg")
print("role: ", role.name)
await member.add_roles(role)
print("done")
For the answer's sake, I'm writing the whole discord.utils.get instead of just get. Here's your command rewritten:
import discord
#bot.command()
async def role(ctx):
await ctx.send("Testing roles!")
member = discord.utils.get(bot.get_all_members(), name="Waldstein")
# be careful when getting objects via their name, as if there are duplicates,
# then it might not return the one you expect
print(f"id: {member.id}")
print(f"member: {member}")
role = discord.utils.get(ctx.guild.roles, name="Egg") # you can do it by ID as well
print(f"role: {role.name}")
await member.add_roles(role) # adding to a member object, not a user
print("Done!")
If this doesn't work, try printing out something like so:
print(ctx.guild.roles)
and it should return each role that the bot can see. This way you can manually debug it.
One thing that might cause this issue is that if the bot doesn't have the necessary permissions, or if its role is below the role you're attempting to get i.e. Egg is in position 1 in the hierarchy, and the bot's highest role is in position 2.
References:
Guild.roles
Client.get_all_members()
Member.add_roles()
utils.get()
commands.Context - I noticed you were using some superfluous code, take a look at this to see all the attributes of ctx