Discord.py How to fix looping message (on_message) - events

Anybody can help me with code i programmed simple event but not working bot ignores one part of the code and the next part works, but when the bot send a message, bot spamming this message, thx for help.
#bot.event
async def on_message(ctx):
if ctx.content.startswith("-") or ctx.content.startswith("+") :
await bot.process_commands(ctx)
if ctx.channel.category.id == 909114663868973106 or ctx.channel.category.id == 838806063418966057 or ctx.channel.category.id == 909114621980454962:
admin1 = ctx.guild.get_member(640961296665149440)
admin2 = ctx.guild.get_member(708704382828544071)
admin3 = ctx.guild.get_member(838159011605512202)
admin4 = ctx.guild.get_member(895743036338884689)
if admin1.status == discord.Status.offline and admin2.status == discord.Status.offline and admin3.status == discord.Status.offline and admin4.status == discord.Status.offline :
await ctx.add_reaction('⏳')
await ctx.channel.send("Wait for support!")
elif ctx.mentions:
if ctx.channel.category.id == 909114663868973106 or ctx.channel.category.id == 838806063418966057 or ctx.channel.category.id == 909114621980454962:
if ctx.author.guild_permissions.administrator:
print(ctx.author.status)
user2 = ctx.mentions[0].id
user = await ctx.guild.query_members(user_ids=user2)
user = user[0]
await ctx.add_reaction('✅')
embed=discord.Embed(color=0xe5f476)
embed.add_field(name="You have been mentioned by an administrator!!", value=f"You have been mentioned by an administrator in **{ctx.channel.mention}** channel.\nMention usually is for an update in ur ticket, most likely something important!\nCheck the server for more information about this staff mention.\n", inline=False)
embed.set_footer(text=f"⭐ Use -tagnotif on #{ctx.channel.name} for stopping this messages. ⭐")
await user.send(embed=embed)
await bot.process_commands(ctx)```

Related

Check whether the mentioned member is not author and offline and a bot

I have made a discord bot in which there is a rob command as follow:-
#client.command(aliases=['rb'])
#commands.cooldown(2, 60, commands.BucketType.user)
async def rob(ctx,member : discord.Member):
if not member == ctx.author and discord.Status.offline and member.bot:
await open_account(ctx.author)
await open_account(member)
bal = await update_bank(member)
if bal[0]<100:
await ctx.send('It is useless to rob them :(')
return
earning = random.randrange(0,bal[0])
await update_bank(ctx.author,earning)
await update_bank(member,-1*earning)
await ctx.send(f'{ctx.author.mention} You robbed {member} and got ֍{earning} ')
else:
await ctx.send('hey stupid, you seem stupid cuz u r either robbing urself or a bot')
I have added the if function wanting to check whether the mentioned member is not the author and offline and a bot but it doesn't work. The command works even on offline users and bots (it doesn't work on the author, but I want it to not work on any of the three)
You can add my bot too to check the feature - https://discord.com/api/oauth2/authorize?client_id=892376302831677520&permissions=8&scope=bot
try this
i have tested this my self it worked so it should also work for you
#client.command(aliases=['rb'])
#commands.cooldown(2, 60, commands.BucketType.user)
async def rob(ctx,member : discord.Member):
if member == ctx.author or ctx.author.status == discord.Status.offline or member.bot:
await ctx.send('hey stupid, you seem stupid cuz u r either robbing urself or a bot')
return
await open_account(ctx.author)
await open_account(member)
bal = await update_bank(member)
if bal[0]<100:
await ctx.send('It is useless to rob them :(')
return
earning = random.randrange(0,bal[0])
await update_bank(ctx.author,earning)
await update_bank(member,-1*earning)
await ctx.send(f'{ctx.author.mention} You robbed {member} and got ֍{earning} ')
Though #idk answer is quite near to it the correct code will be
#client.command(aliases=['rb'])
#commands.cooldown(2, 60, commands.BucketType.user)
async def rob(ctx,member : discord.Member):
if member == ctx.author or member.status == discord.Status.offline or member.bot:
await ctx.send('hey stupid, you seem stupid cuz u r either robbing urself or a bot')
return
await open_account(ctx.author)
await open_account(member)
bal = await update_bank(member)
if bal[0]<100:
await ctx.send('It is useless to rob them :(')
return
earning = random.randrange(0,bal[0])
await update_bank(ctx.author,earning)
await update_bank(member,-1*earning)
await ctx.send(f'{ctx.author.mention} You robbed {member} and got ֍{earning} ')
The main thing is that if member(the user to be robbed) is offline, the code won't work, so it protects them. Here we can add bonus for the victim too

Discord buttons all triggering at once. Discord.py

I am attempting to create moderation on my discord bot that flags words as inappropriate and then allows the moderation team to easily ban/timeout the user without having to be present during the event. All of the moderation works, but only if I run the code once. If there are multiple button sets, they all trigger at once when one of them is pressed. For example, if I have press the ban button on one message, it will ban all users that have spoken inappropriately, rather than just banning the one person.
How do I fix this?
EDIT: I managed to fix the problem that all my button are pressed at once, and have run into a new button. Now, when one button is pressed, the rest of them fail if pressed. It's clear the code is resolving all instances of button_cxt, but I'm not sure how to prevent that or work around it.
Updated Code:
#bot.event
async def on_profanity(message, word):
try:
guildID = message.guild.id
guild = bot.get_guild(guildID)
channel = discord.utils.get(guild.text_channels, name="moderation-logs")
channel_id = channel.id
except:
return None
channel = bot.get_channel(channel_id)
embed = discord.Embed(title="Profanity Alert!", description=f"{message.author.name} just said ||{message.content}||. The bad word was: ||{word}||", color=discord.Color.blurple()) # Let's make an embed!
await channel.send(embed=embed)
buttons = [
manage_components.create_button(
style=ButtonStyle.red,
label="Ban!",
custom_id="ban"
),
manage_components.create_button(
style=ButtonStyle.gray,
label="Give them a Warning",
custom_id="warning"
),
manage_components.create_button(
style=ButtonStyle.green,
label="Nope!",
custom_id="noBan"
),
]
ActionRow = manage_components.create_actionrow(*buttons)
if "warning" in [y.name.lower() for y in message.author.roles]:
botMessage = await channel.send("They have already been warned. Do you wish to ban them?", components=[ActionRow])
else:
botMessage = await channel.send("Do you wish to ban them?", components=[ActionRow])
button_ctx: ComponentContext = await manage_components.wait_for_component(bot, components=ActionRow)
origin_id = button_ctx.origin_message.id
if (botMessage.id == origin_id):
await botMessage.delete()
if button_ctx.custom_id == "ban":
await channel.send("The deed has been done.")
bot.dispatch('ban', message, guild)
elif button_ctx.custom_id == "warning":
await channel.send("The warning has been sent!")
bot.dispatch('warning', message, guild, channel)
elif button_ctx.custom_id == "noBan":
await channel.send("No action taken")
so it took me a long time, and some thinking, but I did finally solve the problem. The issue was with these two sections:
button_ctx: ComponentContext = await manage_components.wait_for_component(bot, components=ActionRow)
The button context is listening for any buttons with the components ActionRow, which is all of the components for all of my buttons. Therefore, all buttons trigger their instance of the function at once. My small check means that only the one pressed does it's action, but it didn't stop the rest of the buttons from triggering that event listener.
So, the fix I thought of is to recursively restart all of the listeners if they aren't pressed. Do the action of the button pressed, and restart the function for the rest. Therefore, my now functioning code looks like this:
#bot.event
async def on_profanity(message, word):
try:
guildID = message.guild.id
guild = bot.get_guild(guildID)
channel = discord.utils.get(guild.text_channels, name="moderation-logs")
channel_id = channel.id
except:
return None
channel = bot.get_channel(channel_id)
embed = discord.Embed(title="Profanity Alert!", description=f"{message.author.name} just said ||{message.content}||. The bad word was: ||{word}||", color=discord.Color.blurple())
await channel.send(embed=embed)
buttons = [
manage_components.create_button(
style=ButtonStyle.red,
label="Ban!",
custom_id="ban"
),
manage_components.create_button(
style=ButtonStyle.gray,
label="Give them a Warning",
custom_id="warning"
),
manage_components.create_button(
style=ButtonStyle.green,
label="Nope!",
custom_id="noBan"
),
]
ActionRow = manage_components.create_actionrow(*buttons)
if "warning" in [y.name.lower() for y in message.author.roles]:
botMessage = await channel.send("They have already been warned. Do you wish to ban them?", components=[ActionRow])
else:
botMessage = await channel.send("Do you wish to ban them?", components=[ActionRow])
await modButtons(guild, message, channel, botMessage, ActionRow)
async def modButtons(guild, message, channel, botMessage, ActionRow):
button_ctx: ComponentContext = await manage_components.wait_for_component(bot, components=ActionRow)
origin_id = button_ctx.origin_message.id
if (botMessage.id == origin_id):
await botMessage.delete()
if button_ctx.custom_id == "ban":
#await channel.send("The deed has been done.")
bot.dispatch('ban', message, guild)
elif button_ctx.custom_id == "warning":
#await channel.send("The warning has been sent!")
bot.dispatch('warning', message, guild, channel)
elif button_ctx.custom_id == "noBan":
await channel.send(f"No action taken for {message.author.name}")
else:
await modButtons(guild, message, channel, botMessage, ActionRow) #recursion HERE!

How to make a verify ban command?

Right, I want to make it so when I do "/ban #user reason" the bot responds with an embed saying are you sure you want to ban this user and reacts to its message with a tick, and awaits for the reaction off of the person who made the ban.
Try this:
#bot.command(name="ban")
async def ban(ctx, member, reason=""):
if not ctx.message.mentions:
await ctx.channel.send("You must mention a user to use this command")
embed = discord.Embed(
title="Confirm ban",
description=f"Are you sure you want to ban {member.mention}",
color=0xff0000
)
message = await ctx.channel.send(embed=embed)
await message.add_reaction(u"\U0001F44D")
def check(pay):
pay.member == member and pay.message_id == ctx.message.id
await bot.wait_for("raw_reaction_add", check=check)
await member.ban(reason=reason)

Using CTX in on_reaction_add event -- Discord.py

async def on_reaction_add(reaction, user):
emoji = reaction.emoji
if emoji == "💌":
await user.channel.send("HI")
I got problem here with user.
I want to use here with ctx like ctx.channel.send.
but also it occured error how to use ctx in here?
Instead of using the on_reaction_add event, it's better in this case to use a wait_for command event. This would mean the event can only be triggered once and only when the command was invoked. However with your current event, this allows anyone to react to a message with that emoji and the bot would respond.
By using client.wait_for("reaction_add"), this would allow you to control when a user can react to the emoji. You can also add checks, this means only the user would be able to use the reactions on the message the bot sends. Other parameters can be passed, but it's up to you how you want to style it.
In the example below shows, the user can invoke the command, then is asked to react. The bot already adds these reactions, so the user would only need to react. The wait_for attribute would wait for the user to either react with the specified emojis and your command would send a message.
#client.command()
async def react(ctx):
message = await ctx.send('React to this message!')
mail = '💌'
post = '📮'
await message.add_reaction(mail)
await message.add_reaction(post)
def check(reaction, user):
return user == ctx.author and str(
reaction.emoji) in [mail, post]
member = ctx.author
while True:
try:
reaction, user = await client.wait_for("reaction_add", timeout=10.0, check=check)
if str(reaction.emoji) == mail:
await ctx.send('Hi you just received')
if str(reaction.emoji) == post:
await ctx.send('Hi you just posted...')
You need to use reaction.message.channel.send
async def on_reaction_add(reaction, user):
emoji = reaction.emoji
if str(emoji) == "💌": await reaction.message.channel.send("HI")

Discord.py Reaction Roles with Embed dont work

Im Trying to make a discord bot which sends an embed message with a reaction, and if a user reacts to that message he/she would get a role. This is for the Rules of the Server.
The Problem is, the Embed message gets sent but there is no reaction. If I manually react to it, and get someone else to react too he/she will get no role. (The embed message is the only message in that channel). I also get no Errors in the console.
The 'channel_id_will_be_here' is always replaced with the correct channel Id.
Thank you.
import discord
from discord.ext import commands
client = discord.Client()
#client.event
async def on_ready():
Channel = client.get_channel('channel_id_will_be_here')
print("Ready as always chief")
#client.event
async def on_message(message):
if message.content.find("|rules12345654323") != -1:
embedVar = discord.Embed(title="**Rules**", description="The Rules Everybody needs to follow.", colour=discord.Colour.from_rgb(236, 62, 17))
embedVar.add_field(name="Rule 1", value="Be nice etc", inline=False)
await message.channel.send(embed=embedVar)
async def on_reaction_add(reaction, user):
Channel = client.get_channel('channel_id_will_be_here')
if reaction.message.channel.id != Channel:
return
if reaction.emoji == ":white_check_mark:":
Role = discord.utils.get(user.server.roles, name="Player")
await client.add_roles(user, Role)
In if reaction.message.channel.id != Channel you compare the id to the Channel object, not the Channel.id.
You don't need to use the object there, just the id (which you use to create the channel object in the first place) would be fine
if reaction.message.channel.id != channel_id_will_be_here:
return
You could also use the message id like(So it'll only trigger when reacting to that exact message):
if reaction.message.id != rules_message_id_will_be_here:
return
The way you do your check is pretty strange too, why check to make the function return if False? Why not just make it add the role when True?
async def on_reaction_add(reaction, user):
if reaction.message.channel.id == channel_id_will_be_here and reaction.emoji == ":white_check_mark:":
Role = discord.utils.get(user.server.roles, name="Player")
await client.add_roles(user, Role)
You could even leave out the if reaction.emoji == ":white_check_mark:": part if it is the only message/emote reaction in that channel

Resources