Discord.py not sending dm? - python

#MassDM Command
#bot.command()
async def massdm(ctx, msg):
await ctx.message.delete()
show_cursor()
wipeinput = input(Fore.RED+"Are you sure you want to mass dm? (WARNING: This happens really fast so it will probably flag your account)(y or n): ")
hide_cursor()
if wipeinput == "y" or wipeinput == "Y":
for user in ctx.guild.members:
if user != bot.user:
try:
channel = await user.create_dm()
await channel.send(msg)
print(Fore.GREEN + f'Sent to user "{user.name}"')
except:
print(Fore.YELLOW + f'Failed to DM user "{user.name}"')
pass
print(Fore.GREEN+"Finished")
When I run this it just says "Finished" and doesnt do anything. when i remove the try/except it gives not error? I have all the proper intents set up i think

You're making a mistake in this line:
wipeinput = input(Fore.RED+"Are you sure you want to mass dm? (WARNING: This happens really fast so it will probably flag your account)(y or n): ")
It seems that you're waiting for a response. The way to do that is with the wait_for function. You should change that to this:
await ctx.send("Are you sure you want to mass dm? (WARNING: This happens really fast so it will probably flag your account)(y or n)?")
wipeinput = bot.wait_for('message') # You can add another parameter to check if the input is valid and what you want.
In addition, I am unsure of what the functions show_cursor() and hide_cursor() are. They may also be causing something to not work.
EDIT: (Thanks to IPSDSILVA for pointing this out) Even though the code that I gave doesn't revolve around the issue in the post, any issue in the code may cause your code to not work

Here is the full code with everything working.
#client.command(pass_context=True)
async def massdm(ctx):
await ctx.message.delete()
for member in list(client.get_all_members()):
try:
embed = discord.Embed(title="Test",
description="Test!",
color=discord.Colour.blurple())
embed.set_thumbnail(
url="test")
embed.set_footer(
text=
"test"
)
await asyncio.sleep(30)
await member.send(embed=embed)
except:
pass
#await ctx.send(f"Messaged: {member.name}")
print(f"Messaged: {member.name}")

Related

How do i code an afk command that comes out the way dyno runs

I need help making a afk command for my discord server. When the afk command is triggered, my bot doesn't respond with a reasoning when you ping the person whos afk. Also, when you return from being afk and type, the bot doesn't send a message saying "(user) is no longer afk". Please help me and tell me what i'm doing wrong and how can I fix this?
afkdict = {User: "their reason"} # somewhere in the code
#bot.command("afk")
async def afk(ctx, reason=None):
afkdict[ctx.user] = reason
await ctx.send("You are now afk. Beware of the real world!")
#bot.event
async def on_message(message):
afkdict = {user: "their reason"}
# some other checks here
for user, reason in afkdict.items():
if user in message.mentions:
if reason is None:
reason = ""
embed = discord.Embed(title=f"{user} is AFK", color=0xFF0000, description=reason[:2500])
await message.reply()
I was expecting this to work, the way dyno works. When i ran the command i got a message back saying user has no context. I dont know what to do anymore.
I think there's a couple of issues. Firstly, you are redefining afkdict in your on_message function it doesn't matter that you're adding users to it in the afk command. Secondly, when you're doing await message.reply(), you're not actually sending the created embed along with it.
I've resolved those problems and changed the logic slightly. Instead of iterating over the users in the afk_dict and checking if they're mentioned, we're iterating over the mentions and seeing if they're in the afk_dict. I'm also using user.id rather user objects as keys.
# defined somewhere
afk_dict = {}
#bot.command()
async def afk(ctx, reason=None):
afk_dict[ctx.user.id] = reason
await ctx.send("You are now afk. Beware of the real world!")
#bot.event
async def on_message(message):
# do whatever else you're doing here
for user in message.mentions:
if user.id not in afk_dict:
continue
# mentioned used is "afk"
reason = afk_dict[user.id] or ""
embed = discord.Embed(title=f"{user.mention} is AFK", color=0xFF0000, description=reason[:2500])
await message.reply(embed=embed)
It looks like you are missing some pieces in your code. Here is an updated version of the code:
afkdict = {}
#bot.command("afk")
async def afk(ctx, reason=None):
user = ctx.message.author
afkdict[user] = reason
await ctx.send(f"You are now AFK. {'Reason: ' + reason if reason else ''}")
#bot.event
async def on_message(message):
for user, reason in afkdict.items():
if user in message.mentions:
if reason is None:
reason = ""
embed = discord.Embed(title=f"{user} is AFK", color=0xFF0000, description=reason[:2500])
await message.channel.send(embed=embed)
if message.author in afkdict:
afkdict.pop(message.author)
await message.channel.send(f"{message.author} is no longer AFK")
In this code, the afk command will add the user who runs the command to the afkdict dictionary along with the reason for being AFK. The on_message event handler will then check if any of the mentioned users are in the afkdict and if so, it will send an embed with the AFK status and reason. Finally, if the author of the message is in the afkdict, it will remove them from the dictionary and send a message indicating that they are no longer AFK.

Discord bot adding and waiting for reactions for a quiz game

I am writing a discord quiz bot using discordpy.
The bot sends a message that contains the questions and the 4 possible answers.
The bot also adds reactions to his message with the emojis 1️⃣, 2️⃣, 3️⃣ and 4️⃣.
The idea is, that the bot waits 30 seconds for people to click on one fo the reactions. If the clicked reaction is the correct/wrong answer, the bot replies with either correct or wrong. The bot should also stop waiting for new reaction once one person answered. Aka: Once a person clicks on one of the 4 reaction emojis, the bot should reply, and not process any future reactions to this message.
Currently, I got the bot to send the message (an embed) and add the reaction emojis to it. However, obtaining the results from the people is where I have problems with.
For one, the bot still seems to get triggered by his own reactions for some reason, even I excluded that in the check function. (Or so I thought).
In general, I'd like to have a very well structured approach for this. I am familiar with all the api calls/events, such as on_message() and on_reaction_add(), but I have trouble putting everything together correctly.
This is what I have so far:
#commands.command(name="quiz")
async def on_command_quiz(ctx):
#if ctx.message.author.bot:
# return
print("Quiz command!")
quiz = QuizGame()
# Send quiz
reply = await ctx.message.channel.send(embed=quiz.format())
# Add reply emojis
for x in range(0, len(quiz.quiz_answers)):
await reply.add_reaction(Utils.get_number_emoji_by_number(x + 1))
print("Correct Answer:", quiz.quiz_correct_answer)
# Evaluate replies
async def check_answer(reaction, user):
emojis = ["1️⃣","2️⃣","3️⃣","4️⃣"]
return user != ctx.message.author and str(reaction.emoji) in emojis
# Wait for replies
try:
reaction, user = await bot.wait_for('reaction_add', timeout=30.0, check=check_answer)
except asyncio.TimeoutError:
print("Timeout")
else:
if user != ctx.message.author:
if str(reaction.emoji) == "1️⃣":
print("1")
elif str(reaction.emoji) == "2️⃣":
print("2")
elif str(reaction.emoji) == "3️⃣":
print("3")
elif str(reaction.emoji) == "4️⃣":
print("4")
else:
print("Unknown reaction")
How can I get this right?
There are several errors and some inaccuracies in your code; first I'll list them and then I'll show you what I think is the best way to set up this type of commands.
Please note that some of the following are not actual fixes but more efficient ways to organize your code.
-You should use decorators to define bot commands, instead of using functions like on_command:
#bot.command()
async def quiz(ctx)
-The ctx class provides the channel attribute already, so ctx.message.channel is kind of redundant, use ctx.channel instead.
Same applies for ctx.message.author.
-If the number of answers is always the same, then you can add the numeric emojis with a very simple for loop (also, there is no need to call Utils to get the relevant emojis):
for emoji in ["1️⃣","2️⃣","3️⃣","4️⃣"]:
reply.add_reaction(emoji)
-The check_answer function is redundant as well, and logically wrong too.
It is redundant because there is no need to verify that the reaction emoji is one of the 4 available, since it will be determined later in the try block anyway.
It is logically wrong because it should return True if the user who added the reaction matches the author of the command, and not the opposite (you will notice that this will also prevent the bot from being triggered by its own reactions).
Then, there is no need for the function to be asynchronous.
def check_answer(reaction, user):
return user == ctx.author
-Finally, the whole try-except-else block is not really functional here. In order for the bot to remain responsive until the first reaction of the specific user or until the 30 seconds timeout expires, you should integrate the try-except block into an infinite while loop:
while True:
try:
reaction, user = await bot.wait_for("reaction_add", timeout=30, check=check_answer)
# The following line is optional: it removes the reaction added by the user
# to let them react again with the same emoji; not really necessary in your case,
# but very helpful if your bot would still be responsive after the first reaction.
await reply.remove_reaction(reaction, user)
# Here goes the if-else block of reactions.
except asyncio.TimeoutError:
print("Timeout")
Remember that somewhere in the try block you will have to stop the loop with a break statement when the operation is finished, otherwise it will continue indefinitely.
I am developing a Discord bot too and am still a beginner, so I hope I've been able to explain well.
Anyway, to sum it up, here is an example of how I would personally implement that command:
#bot.command()
async def quiz(ctx):
print("Quiz command!")
quiz = QuizGame()
reply = await ctx.send(embed=quiz.format())
emojis = ["1️⃣","2️⃣","3️⃣","4️⃣"]
for emoji in emojis:
await reply.add_reaction(emoji)
def check_answer(reaction, user):
return user == ctx.author
while True:
try:
reaction, user = await bot.wait_for("reaction_add", timeout=30, check=check_answer)
await reply.remove_reaction(reaction, user)
# Shorter representation of that if-else block.
if reaction.emoji in emojis:
print(emojis.index(reaction.emoji) + 1)
break
else:
print("Unknown reaction")
except asyncio.TimeoutError:
print("Timeout")
Then of course you should define how to recognize the correct answer and how to notify the user.
If you need some clarification on what I wrote, feel free to comment on this answer and I will be happy to answer you.
You didn't really ignore the bots reaction, at least from what I can see in the code.
You can try the following method:
try:
reaction, user = await self.bot.wait_for('reaction_add', timeout=15)
while user == self.bot.user:
reaction, user = await self.bot.wait_for('reaction_add', timeout=15)
if str(reaction.emoji) == "YourEmoji":
A check function could be:
reactions = "YourReactions"
def check1(reaction, user):
return user == ctx.author and str(reaction.emoji) in [reactions]
Here we check if the reaction comes from the author of the command and also check if the emoji is in the reactions "list".

Discord.py Mass DM sometimes Bugs

i am Making a MassDM command but it dont works well, it sends a Message not to Everyone it stops automatically i think because they turn their DM's off thats why how can i Bypass it? or how can i Fix this error?
Code
#client.command()
async def massdm(self, ctx, *, message):
await ctx.message.delete()
embed = discord.Embed(description=f'**Sent everyone a DM with:** ``{message}``',color=embcolor)
await ctx.send(embed=embed, delete_after=delemb)
for user in list(ctx.guild.members):
try:
await asyncio.sleep(0.1)
await user.send(message)
except:
pass
To debug it properly, the first step would be to remove the try, except block and find out what exceptions are you actually getting. It's a bad habit to catch every exceptions at once. Without knowing what exception is it throwing, I'm unable to help more.
Another thing I would recommend is to benefit from the discord.py being an asynchronous package, and instead of iterating over the users synchronously, try something like that:
coros = [await user.send(message) for user in ctx.guild.members]
await asyncio.gather(*coros)
This way it will send the message to every user at the same time.
EDIT:
I also found another bug while using a loop like that. At some point the bot will try to send the DM to itself, and that is raising AttributeError. Make sure that you handle that, for example:
coros = [user.send(message) for user in ctx.guild.members if user != ctx.guild.me]
await asyncio.gather(*coros)
Maybe that was your issue all along.
Try this:) Hope it helps
#client.command(pass_context=True)
async def massdm(ctx):
await ctx.message.delete()
for member in list(client.get_all_members()):
try:
embed = discord.Embed(title="Test",
description="Test!",
color=discord.Colour.blurple())
embed.set_thumbnail(
url="test")
embed.set_footer(
text=
"test"
)
#delay. Set it to 10 to 20 seconds to avoid flagging
await asyncio.sleep(30)
await member.send(embed=embed)
except:
pass
#await ctx.send(f"Messaged: {member.name}")
print(f"Messaged: {member.name}")

Discord.py ping user who inputted message

I've made a command that prompts the server with 2 numbers, and the users add the numbers in the shortest time possible. I'm trying to figure out a way to ping the user who got the correct answer, but I can't seem to get it to work. One thing I've tried applying is adding m.author == message.author to the return line, as seen here, but I get an error saying message is undefined. I'm still pretty new to this, so it'd be nice to know how to implement it into my code, or if there's a different way, as all I want is to be able to have the bot ping the user who sent the right answer first.
#client.command()
async def math(ctx):
num_one = random.randint(1, 98)
num_two = randint(1, 98)
answer = num_one + num_two
answer_string = str(answer)
await ctx.send(f'{num_one} + {num_two}?')
def check(m):
return m.content == answer_string
msg = await client.wait_for('message', check=check)
await ctx.send(f"got the correct answer!")```
You should be able to do await ctx.send(f"{msg.author.mention} got the correct answer!").
client.wait_for returns a Message object, which means it has an author attribute. You can then use the .mention attribute of a Member object(the author), which will ping them.

DM commands to discord bot

I recently had the idea of DMing my bot commands. For example, a command which would unban me from every server that the bot is on.
Unfortunately I don't have any starting point for the command because I'm not even sure DMing commands is possible.
Keywords like discord.py, command or DM are so common in google that finding any good info on the topic is very hard.
I'm looking for a way for the bot to receive DMs as commands and only accept them from me (my ID is stored in the variable ownerID if anyone wants to share any code).
While I'm mostly looking for the above, some code for the DM unban command would also be very helpful.
EDIT: I was asked to show some example code from my bot. Here is the code for the command number which generates a random number and sends it in a message. I hope this gives you an idea of how my bot is made:
#BSL.command(pass_context = True)
async def number(ctx, minInt, maxInt):
if ctx.message.author.server_permissions.send_messages or ctx.message.author.id == ownerID:
maxInt = int(maxInt)
minInt = int(minInt)
randomInt = random.randint(minInt, maxInt)
randomInt = str(randomInt)
await BSL.send_message(ctx.message.channel, 'Your random number is: ' + randomInt)
else:
await BSL.send_message(ctx.message.channel, 'Sorry, you do not have the permissions to do that #{}!'.format(ctx.message.author))
You can send commands in private messages. Something like
#BSL.command(pass_context=True)
async def unban(ctx):
if ctx.message.channel.is_private and ctx.message.author.id == ownerID:
owner = await BSL.get_user_info(ownerID)
await BSL.say('Ok {}, unbanning you.'.format(owner.name))
for server in BSL.servers:
try:
await BSL.unban(server, owner) # I think having the same name should be fine. If you see weird errors this may be why.
await BSL.say('Unbanned from {}'.format(server.name))
except discord.HTTPException as e:
await BSL.say('Unbanning failed in {} because\n{}'.format(server.name, e.text))
except discord.Forbidden:
await BSL.say('Forbidden to unban in {}'.format(server.name))
else:
if ctx.message.author.id != ownerID:
await BSL.say('You are not my owner')
if not ctx.message.channel.is_private:
await BSL.say('This is a public channel')
should work. I'm not sure what happens if you try to unban a user who is not banned, that may be what raises HTTPException

Categories