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
Related
I have a code to remove one role from everyone on the server, but it doesn't work:
When I enter a command, the bot simply ignores it, there is nothing in the cmd and the bot does not do anything either
Code -
intents = discord.Intents()
intents.members = True
#client.command()
async def clearrole(ctx):
role = discord.utils.get(ctx.guild.roles, id = 795410455848812565)
members = ctx.guild.members
for member in members:
if role in member.roles:
await member.remove_roles(role)
Make sure the intents are enabled, otherwise your bot might not be able to get a list of all the members of your server : https://discordpy.readthedocs.io/en/latest/intents.html
Then, make sure the id indeed correspond to a role by typing <#795410455848812565> in your server, it should transform into the role mention, otherwise the ID is wrong
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
I made a stupid discord bot a few months ago to change my friends name every minute, but I updated it today and now the get_member function is returning none.
#client.event
async def on_ready():
print('bot is ready!')
status = discord.Activity(name="Sam be a loser", type=discord.ActivityType.watching)
await client.change_presence(activity=status)
name_change.start()
#tasks.loop(minutes=1)
async def name_change():
server = client.get_guild(id=584112137132048387)
user = server.get_member(376388277302984714)
global english_words
global wordNumber
wordNumber = wordNumber + 1
#changes nickname to current word
await user.edit(nick=f"{english_words[wordNumber]} lookin' ass")
print(f'Word number {wordNumber}: {english_words[wordNumber]}')
#updates number in file
file = open("currentWord.txt", "w")
file.write(str(wordNumber))
file.close
I tried the same function with every user in the server, but it returned none for all of them except when I put the bot's id in. I have no clue why this is happening since I didn't even edit this part of the code.
This is most likely due to the recent discord.py 1.5 update. You are required to configure your intents when you're declaring your Bot.
What are intents?
Version 1.5 comes with the introduction of intents. This is a radical change in how bots are written. An intent basically allows a bot to subscribe into specific buckets of events. The events that correspond to each intent is documented in the individual attribute of the Intents documentation. Here's an example:
import discord
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True # Subscribe to the privileged members intent.
bot = commands.Bot(command_prefix='!', intents=intents)
You will also have to enable privileged intents for guild related events: Here
You can read more about intents: Here
You may be able to not use Intents, Privileged or otherwise, by not using get_member() and instead use
guild.fetch_member()
Im trying to make a command that will send in an embed and that has two reactions, a tick and a cross, i want to make the user just react to one of the reaction, rather than reacting to both of them. I also need some help in making a system to ensure that the person reacting has a specific role. Any help would be highly appreciated!
This is possible using the on_raw_reaction_add() event.
#bot.event
async def on_raw_reaction_add(payload): # checks whenever a reaction is added to a message
# whether the message is in the cache or not
# check which channel the reaction was added in
if payload.channel_id == 112233445566778899:
channel = await bot.fetch_channel(payload.channel_id)
message = await channel.fetch_message(payload.message_id)
# iterating through each reaction in the message
for r in message.reactions:
# checks the reactant isn't a bot and the emoji isn't the one they just reacted with
if payload.member in await r.users().flatten() and not payload.member.bot and str(r) != str(payload.emoji):
# removes the reaction
await message.remove_reaction(r.emoji, payload.member)
References:
on_raw_reaction_add()
Message.remove_reaction()
Reaction.users()
User.bot
RawReactionActionEvent - (the payload)
Message.reactions
Client.fetch_channel()
TextChannel.fetch_message()
I think you can store the userId or something that is unique for all the user.
And then create a function check this ID appeared more than once or other logic.
https://discordpy.readthedocs.io/en/latest/api.html#userUser API
Here, you can get user ID from this object.
Further more, you can get author id from message your client receive.
def on_message(message):
print(message.author.id)
I'm trying to make a ticketing system in which a user does .ticket.
I'm having an issue where 'bot' doesn't have the attribute 'delete_channel', and I also want to make it so the bot ignores the reaction if a bot reacts to the message, but acknowledges that a normal guild member has reacted to it.
Here's my code:
#bot.command()
async def ticket(ctx):
global ticket_channel
name = "tickets"
category = discord.utils.get(ctx.guild.categories, name=name)
guild = ctx.message.guild
ticket_id = randint(0, 100)
ticket_channel = await guild.create_text_channel(f"ticket-0{ticket_id}", category=category)
embed = discord.Embed(title="Tickets", description="Support will be with you shortly.\nTo close this ticket, react with :lock:.")
message = await ticket_channel.send(embed=embed)
await message.add_reaction(emoji="\N{LOCK}")
#bot.event
async def on_reaction_add(reaction: discord.Reaction, user: discord.Member):
if reaction.message.channel != ticket_channel:
return
if reaction.emoji == "\N{LOCK}":
await bot.delete_channel(ticket_channel)
I've been trying for a while to figure out the issue, but I'm clueless.
Seems like you're asking several questions here:
I'm having an issue where 'bot' doesn't have the attribute 'delete_channel'
The bot does not have a delete_channel() function. However, a Discord.TextChannel class has a .delete() function (shown in the docs).
and I also want to make it so the bot ignores the reaction if a bot reacts to the message
Alternative 1
Every user, including bot users, have the attribute .bot. You can use that to check if the user is a bot, and if so, return the function early.
#bot.event
async def on_reaction_add(reaction, user):
if user.bot: return
# Code goes here
Note that this listens for all reactions, not just that specific message; thus comes:...
Alternative 2
As Patrick Haugh mentions, you could use the discord.Client.wait_for() function (doc link) and parse a function to as the check argument of the function.
reaction, user = bot.wait_for('reaction', check=lambda reac: reac.author == ctx.author)
*Note that this approach doesn't add this code under any event (as in the first alternative), except the command event. It will only be run once per command received unless put in a loop of some sorts.