Add role when react to emoji discord.py - python

im trying to add a role when the user react to this emojis but i cant get
Setup Roles
#bot.command()
async def roles(ctx):
global IDMessage
reaction = await ctx.reply("Select your Game" + '\n' + '\n' + "- Valorant 🦸‍♀️" '\n' + "- World of Warcraft ⚔" + '\n' + "- League of Legends 🧙‍♀️" + '\n' + "- Cs:Go 🔫")
await reaction.add_reaction('🦸‍♀️')
await reaction.add_reaction('⚔')
await reaction.add_reaction('🧙‍♀️')
await reaction.add_reaction('🔫')
IDMessage = reaction.message_id
And this is the part of the code that doesnt work for me
Add role on reaction
#bot.event
async def on_reaction_add(reaction, user):
ChID = '920320584032870424'
if reaction.message.channel.id != ChID:
return
if reaction.emoji == "🦸‍♀️":
Valorant = discord.utils.get(user.server.roles, name="Valorant")
await bot.add_roles(user, Valorant)

ChID = '920320584032870424' (string) is being compared to an integer reaction.message.channel.id.
ChID = '920320584032870424'
Instead, use
ChID = 920320584032870424
Which is an integer.

There are some issues here. Instead of on_reaction_add, use on_raw_reaction_add. Most bots use the latter instead of the former.
Why you may ask? Because, on_reaction_add only works for messages in bot's cache.
So every message sent after your bot can read messages is stored in a dictionary or list (this is what a cache is). By default the limit of caching is 1000 messages.
So if you ever restarted your bot, the message will never be in cache, and thus the event won't trigger.
Another issue is that you are comparing a string (ChID) variable and an integer (reaction.message.channel.id), they can never be equal so if reaction.message.channel.id != ChID will always return True and thus won't do anything (as you return for that condition being True).
Third issue is that bot.add_roles does not exist. add_roles is a method of discord.Member object.
Fourth issue is, Member.server is not a thing, Member.guild is
So your updated code will be like:
#bot.event
async def on_raw_reaction_add(payload: discord.RawReactionActionEvent):
ChID = 920320584032870424
if payload.channel.id != ChID:
return
if str(payload.emoji) == "🦸‍♀️":
valorant = discord.utils.get(payload.member.guild.roles, name="Valorant")
await payload.member.add_roles(valorant)
Also my personal advice of not using global
there are very rare few cases where you would actually require this keyword
But it is highly unlikely for you to use this in a bot made with discord.py lib
More on this:
discord.on_reaction_add
discord.RawReactionActionEvent
discord.Member.guild
discord.Member.add_roles
why-are-global-variables-evil

I had the same problem, and this is how I solved it.
You have the reactions being added, now you need to wait for the user to react.
For this, you can use discord.py’s wait_for function.
Check function:
def check(reaction):
if str(reaction.emoji) == “EMOJIHERE”:
return “emoji name”
elif str(reaction.emoji) == “SECONDEMOJI”:
return “emoji name”
elif str(reaction.emoji) == “THIRDEMOJI”:
return “emoji name”
elif str(reaction.emoji) == “FOURTHEMOJI”:
return “emoji name”
else:
return “error”
Code:
async def roles(ctx):
global IDMessage
reaction = await ctx.reply("Select your Game" + '\n' + '\n' + "- Valorant 🦸‍♀️" '\n' + "- World of Warcraft ⚔" + '\n' + "- League of Legends 🧙‍♀️" + '\n' + "- Cs:Go 🔫")
await reaction.add_reaction('🦸‍♀️')
await reaction.add_reaction('⚔')
await reaction.add_reaction('🧙‍♀️')
await reaction.add_reaction('🔫')
confirm = await bot.wait_for(“reaction_add”, check=check)
if confirm == "emoji name 1":
doSomething()
elif confirm == "emoji name 2":
doSomething()
elif confirm == "emoji name 3":
doSomething()
elif confirm == "emoji name 4":
doSomething()
else:
print("Error")
await ctx.send("An error occurred.")
Replace EMOJIHERE and emoji name with the appropriate values.

Related

Discord Py / How to remove a specific role from a server user

I plan to manage information of server personnel in conjunction with Google Spread.
And I want to remove the role from the server personnel by entering the name of the role.
Check the typos.
The part of the spreadsheet is complete, but it has not removed its role from the discord, has tried several searches, but it does not help, leaving questions.
I need help.
This is my code.
#bot.command()
async def removerole(ctx, team_name):
role = get(ctx.guild.roles, name=team_name)
team_mem = []
# type error check
role_list = ["TEAM_A", "TEAM_B", "TEAM_C", "TEAM_D"]
if role.name in role_list:
type_error = 1
else:
type_error = 0
cell_max = worksheet_list.acell('A1').value
range_list = worksheet_list.range('H2:H' + cell_max)
if type_error == 1:
for i, cell in enumerate(range_list):
#print(str(i) + " / " + cell.value)
if str(cell.value) == team_name:
temp = i + 2
data = worksheet_list.acell('H' + str(temp)).value
worksheet_list.update_acell('H' + str(temp), 'Any')
#print(temp, data)
if data == role:
team_mem.append(worksheet_list.acell('C' + str(temp)).value)
#await ctx.message.delete()
await ctx.send(content=f"{team_name} role has been removed")
else:
await ctx.send("Check the typos.")
empty = True
for member in ctx.guild.members:
if role in member.roles:
await ctx.guild.member.remove_roles(role)
empty = False
if empty == False:
await ctx.send("Anyone has this role")
You are not removing it right, you should reference to member not ctx.guild.member since you already got the member from the for loop.
for member in ctx.guild.members:
if role in member.roles:
await member.remove_roles(role)
Note: Make sure to enable intents.

how to check for file extension in discord.py

i am creating a python discord bot, and i have a function that if a message is sent in a certain channel,
it randomly sends out a response,everything works fine but i want to restrict the bot to react only when the sent message contains a png, jpg or jpeg file
heres the code(look for the bottom if str(message.channel) statement):
#client.event
async def on_message(message):
await client.process_commands(message)
if str(message.channel) not in restr:
if message.content == ".sabaton":
random.seed(time.time())
randnum = random.randint(0, len(songs) - 1)
await message.channel.send(file=discord.File(songs[randnum]))
elif message.content == ".time":
await message.channel.send(f"Current time is {time.localtime()}")
elif message.content == ".pmsh":
await message.channel.send(help)
if client.user.mention in message.content.split():
await message.channel.send('Дарова гандон(иха),мой префикс "."')
if str(message.channel) == "🥳творчество🥳":
random.seed(time.time())
rn3 = random.randint(1,2)
if rn3 == 1 and message.author.bot == False:
await message.channel.send("Заебись творчество")
elif rn3 == 2 and message.author.bot == False:
await message.channel.send("Фигня творчество")
Attachments in discord.py have information about their file type in their content_type attribute. This should hopefully make for cleaner code too!
Apart from the access, #Sofi's logic still applies:
for attachment in message.attachments:
if attachment.content_type in ('image/jpeg', 'image/jpg', 'image/png'):
# Your Logic Here
If you just need to check if something is an image, your code can be simpler:
for attachment in message.attachments:
if 'image' in attachment.content_type:
# Your Logic Here!
You can use the following conditions to restrict it:
if message.attachments[0].url.endswith('PNG') or message.attachments[0].url.endswith('JPG') or message.attachments[0].url.endswith('JPEG'):
pass
else:
pass
Change the pass according to your content.

Discord bot won't take in a new message

So I'm making this weird kinda discord bot. It displays a set of obstacles, and adds a corresponding key that you need to press to a string. It adds a 'w' for every '...', and an 's' for every '***'. In Discord, the player has to type the correct string in to pass the level. So it all works and displays properly. The call function is '!go', and that displays the level. But it fails me before I can type in the string. I want to know, why is it automatically activating? My message.content function is outside that loop. I think it is because I type '!go' and it doesn't reset my message. Here is the code:
#client.event
async def on_message(message):
global correct_answerS
correct_answerS = ""
obstacleList = []
for i in range (0, 24):
randNum = random.randint(1,2)
if randNum == 1:
obstacleList.append('...')
correct_answerS += 'w'
if randNum == 2:
obstacleList.append('***')
correct_answerS += 's'
if message.content == ('!practice'):
sky = str("```css\n A ... ... *** ...```")
skyembed = discord.Embed(title="!============================!")
skyembed.add_field(name='When you see three dots, it is a w. When you see 3 asteriks, it is an s.', value = sky)
await message.channel.send(embed=skyembed)
if message.content == ('wwsw'):
await message.channel.send("Success.")
if message.content == ('!go'):
randlev = (str("```css\n A "))
for i in range(0, 24):
randlev += (str(obstacleList[i]) + " ")
randlev += "```"
randlevembed = discord.Embed(title="!===============================================!")
randlevembed.add_field(name='Good luck!', value = randlev)
await message.channel.send(embed=randlevembed)
print(correct_answerS)
if message.content == (correct_answerS):
await message.channel.send("Success!")
else:
await message.channel.send("Fail.")
#client.event
async def on_ready():
print("Ready")
print(client.user.id)
print('--------------------------')
await client.change_presence(activity=discord.Game(name='up and away'))
client.run(Token)
There is no error message, just as soon as I type '!go', it displays the level and then continually says 'Fail.' until I stop it.
I don't know what to do, any help is just that, helpful. Thanks.
The bot is stuck in a loop where it's sending a message, and then processing that message, which causes it to send another message, etc. You can add a check to the beginning of on_message to force it to ignore bot-generated messages:
#client.event
async def on_message(message):
if message.author.bot:
return
...

discord.py how to wait for author message using wait_for?

I am making a command which waits for a user to reply to the bot, but I would like the bot to only accept the author's reply.
#client.command(name='numgame',
brief='Guess a number between 1 and 100',
pass_context=True)
async def numgame(context):
number = random.randint(1,100)
guess = 4
while guess != 0:
await context.send('Pick a number between 1 and 100')
msg = await client.wait_for('message', check=check, timeout=30)
attempt = int(msg.content)
if attempt > number:
await context.send(str(guess) + ' guesses left...')
await asyncio.sleep(1)
await context.send('Try going lower')
await asyncio.sleep(1)
guess -= 1
elif attempt < number:
await context.send(str(guess) + ' guesses left...')
await asyncio.sleep(1)
await context.send('Try going higher')
await asyncio.sleep(1)
guess -=1
elif attempt == number:
await context.send('You guessed it! Good job!')
break
My issue is that anyone can respond to "Pick a number," whereas I would only like the person who started the command to be able to respond.
I am not too sure what to try, but I think it may have something to do with arguments. I have no idea where to begin, though, so a solution would be appreciated! Thanks a ton.
You need rewrite your check so that it knows who the author is. One way of doing this is to use a closure. Let's say you have an existing check
def check(message):
return message.content == "Hello"
You can replace this with a function that generates equivalent check functions with the author you want to check for injected into them
def check(author):
def inner_check(message):
return message.author == author and message.content == "Hello"
return inner_check
Then you would pass the inner check to wait_for by calling the outer check with the appropriate argument:
msg = await client.wait_for('message', check=check(context.author), timeout=30)
For your check this would be
def check(author):
def inner_check(message):
if message.author != author:
return False
try:
int(message.content)
return True
except ValueError:
return False
return inner_check

Discord.py silence command

I have been asking lots of questions lately about discord.py and this is one of them.
Sometimes there are those times when some people spam your discord server but kicking or banning them seems too harsh. I had the idea for a silence command which would delete every new message on a channel for a given amount of time.
My code so far is:
#BSL.command(pass_context = True)
async def silence(ctx, lenghth = None):
if ctx.message.author.server_permissions.administrator or ctx.message.author.id == ownerID:
global silentMode
global silentChannel
silentChannel = ctx.message.channel
silentMode = True
lenghth = int(lenghth)
if lenghth != '':
await asyncio.sleep(lenghth)
silentMode = False
else:
await asyncio.sleep(10)
silentMode = False
else:
await BSL.send_message(ctx.message.channel, 'Sorry, you do not have the permissions to do that #{}!'.format(ctx.message.author))
The code in my on_message section is:
if silentMode == True:
await BSL.delete_message(message)
if message.content.startswith('bsl;'):
await BSL.process_commands(message)
All the variables used are pre-defined at the top of the bot.
My problem is that the bot deletes all new messages in all channels which it has access to. I tried putting if silentChannel == ctx.message.channel in the on_message section but this made the command stop working completely.
Any suggestions as to why this is happening are much appreciated.
Something like
silent_channels = set()
#BSL.event
async def on_message(message):
if message.channel in silent_channels:
if not message.author.server_permissions.administrator and message.author.id != ownerID:
await BSL.delete_message(message)
return
await BSL.process_commands(message)
#BSL.command(pass_context=True)
async def silent(ctx, length=0): # Corrected spelling of length
if ctx.message.author.server_permissions.administrator or ctx.message.author.id == ownerID:
silent_channels.add(ctx.message.channel)
await BSL.say('Going silent.')
if length:
length = int(length)
await asyncio.sleep(length)
if ctx.message.channel not in silent_channels: # Woken manually
return
silent_channels.discard(ctx.message.channel)
await BSL.say('Waking up.')
#BSL.command(pass_context=True)
async def wake(ctx):
silent_channels.discard(ctx.message.channel)
Should work (I haven't tested it, testing bots is a pain). Searching through sets is fast, so doing it for every message shouldn't be a real burden on your resources.

Categories