So, long story short I was making a bot that's supposed to send a direct message to a user after a command was executed, then wait a bunch of time before deleting it
It works fine and all now, but for a bit of time it didn't, and while I did some testing, my dms with that bot have been flooded with test messages
Is there any command I could add to delete every old messages that this bot sent to my dms ?
You could write a censor command that calls purge_from on the channel it's invoked from.
#bot.command(pass_context=True)
async def censor(ctx, limit: int= 100):
await bot.purge_from(ctx.message.channel,
check=lambda message: message.author == bot.user,
limit=limit)
Related
I have a discord.py command that makes feeds of memes, but when I use the command, all the images sent by the bot with exception of the first one have a "tap to see attachment" as if they were a response to the first image, is it possible to make it not appear? If so, how?
#bot.hybrid_command(name = "command", with_app_command = True, description = "description")
async def test1(ctx, number: int):
i = 0
while i < number:
await ctx.send("Message")
i = i+1
await asyncio.sleep(5)
ctx.send will either try to respond to the interaction, followups to the response if a response has been given, or just send if the interaction has expired. I believe the behaviour you're seeing is expected.
If you change your ctx.send to ctx.channel.send then that should act like a more regular send.
We can also add a defer to prevent discord saying we didn't respond whilst we sent lots of messages, and then use ctx.send at the end to finally respond and tell the user we're done. Using ephemeral=True means that we only send the message to the user that initiated the command.
async def test1(ctx, number: int):
# defer the interaction to prevent "bot didn't respond" messages
await ctx.defer(ephemeral=True)
# do the rest of your code here
# once you're done sending lots of messages
await ctx.send("Finished meme feed", ephemeral=True)
When my bot is very busy, it sometimes takes a few seconds to respond to the slash commands. However, before he can reply, Discord sends the message "The application did not respond". How can I make Discord wait longer for a message from the bot?
Have you tried using Interaction.defer()? Here's a quick example on how to use that:
#bot_instance.slash_command(name="hi")
async def hi(ctx):
await ctx.defer()
# fairly long task?
await ctx.followup.send( # Whatever you want to send...
For more information check out the API Reference: https://docs.pycord.dev/en/master/api.html#discord.Interaction
Also see a GitHub issue related to this question: https://github.com/Pycord-Development/pycord/issues/264
There is something called defer, you can do that to increase waiting time of the function
#bot_instance.command(description="Description of the command"
async def command(ctx:discord.Interaction,keyword:str)#Keyword if any
await ctx.response.defer(ephemeral=True)#This line defers the function
#Do your process here
await ctx.followup("Followup message")#This is the confirmation message
possible cause #2 is probably what's happening
Why I am using this:
I am trying to get my bot to detect a bot's embed message (to get the in-game currency of a player) using
await client.wait_for
Problem
However, it somehow does not detect the embeds sent by the bot. It still acknowledges it as long as it has plain text sent together with the embed or it sends the plain text on its own. The
#client.event
async def on_message(message):
code will still work if the bot has sent embeds with or without the text.
Possible causes:
1. ❌Already tested and proven not the cause❌ That my bot cannot read messages from bots
2. Possible: That my bot is slower that the bot I am testing with, so once my bot detects a message sent by a user for the bot to react, the bot has already responded with another message, so the bot is still waiting for a non-existent message. I have not found a viable, not time-consuming way to test this
3. Possible: {this question}
Others
All help will be appreciated! Please also point out any errors in my code here and whether I am using the right code to detect embeds and/or messages by bots. I would also appreciate alternative ways of doing my code.
Code
A portion of my current code is:
def pred(m):
return m.author == client.get_user(490707751832649738)
try:
msg = await client.wait_for('message', check=pred, timeout=10.0)
except asyncio.TimeoutError:
await message.channel.send('Looks like Taco-shack is down :/')
else:
await message.channel.send('You said {0.content}, {0.author}.'.format(msg))
Please ignore the indentations. It was fresh copypasta from my code. I modified it from the API https://discordpy.readthedocs.io/en/latest/migrating.html#waiting-for-events
output:
Looks like taco-shack is down which is the output of an asyncio timeout error
P.S. This is my first question after creating my stack overflow account, I realised that there were already so many articles that I could refer to. So I kept searching, but I could only not find the solution to this question. Please ignore my poor formatting!
Edit:
in response to my comments, I shall make it more clear
I have amended my above code because of Eric's help. He commented something that led me to improve my code ;)
Thanks
In response to Patrick's comment (thanks a lot for directing me to the https://stackoverflow.com/help/minimal-reproducible-examrple help page, really appreciate it ;)), here are a few steps you can go to reproduce the code.
Steps to reproduce the problem
Step 1:
Go to the Discord developer portal and create 2 bots, one for sending the embed and the other for this testing thing (one if you have a random bot that can send embeds
Step 2:
Invite the bot(s) to your server
Step 3:
Code the first bot to send an embed once you sent a message inside any channel maybe a simple embed like the one in How can I send an embed via my Discord bot, w/python? and also maybe an else added to it and that else sends some plain text. Remember to use client.run()!
Step 4
Code the second bot like this:
#client.event
async def on_message(message):
def pred(m):
return m.author == client.get_user(490707751832649738)
try:
msg = await client.wait_for('message', check=pred, timeout=10.0)
except asyncio.TimeoutError:
await message.channel.send('Looks like Taco-shack is down :/')
else:
await message.channel.send('You said {0.content}, {0.author}.'.format(msg))
client.run('token')
Step 5:
Run the two bots!
More questions:
I don't seem to understand whats the use of using message.embeds. I am trying to wait for a message to be sent under the on.message to continue the thread after someone types .balance to see the value of their account so that the bot can get the information. However, it does not recognise a message was sent by the bot
Legality/ethicality
The idea of making this bot came because Carl could not send the message ID.
This part is to see how much money the user has left along with whether the person has successfully sent the donation so that false donations do not clutter the channel
This bot is not meant to be a self bot.
and should not be thought as one.
** If and when you find out that this is not legal, please give a 'no' answer or comment that it is not legal (I prefer the latter) **
I can't reproduce this. Here's what I'm doing
#bot.event
async def on_message(message):
if message.author.id == bot.user.id:
print(message.content)
print(message.embeds)
await bot.process_commands(message)
#bot.command()
async def comm(ctx):
msg = await bot.wait_for('message', check=lambda m: m.author.id == bot.user.id)
await ctx.send(f"{msg.content} {msg.embeds}")
#bot.command()
async def send_content(ctx):
await ctx.send("content1")
#bot.command()
async def send_embed(ctx):
embed = Embed(title="Title1")
await ctx.send(embed=embed)
#bot.command()
async def send_both(ctx):
embed = Embed(title="Title2")
await ctx.send("content2", embed=embed)
I only have the one bot, so maybe that's the problem, but by running !comm and then !send_embed, the bot will detect its own embed-only message from wait_for. One thing I do in this code is to compare objects by id instead of by simple equality.
I edited my on_message to detect the response the second it hears the message. Thanks for all your help :) It was the 2nd thing I ruled out
So basically i have this simple 'World Chat' script that lets people who have my bot and a channel called "world_chat" chat with each other in that channel, they can receive and send messages but the problem here is, every time they create a channel either with a command I gave or manually, they will be able to send messages and others can see it but they won't be able to see what others send till i reset the bot on heroku which I really don't want to do as when the bot gets in a lot of servers it'd be a lot of work.
#This is the script that let's people chat to each other
saki_chans=[]
async def get_saki_chans():
for i in client.servers:
for x in i.channels:
if x.type == discord.ChannelType.text and x.name ==
'world_chat' and x.id not in saki_chans:
saki_chans.append(x.id)
print(saki_chans)
#client.event
async def on_message(message):
if message.server and message.channel.name == 'world_chat' and
message.author.id != client.user.id:
for i in saki_chans:
if i == message.channel.id:
pass
else:
emb=discord.Embed(title='',description='{}'.format(message.content),colour
= discord.Color.gold)
emb.set_author(name= message.author.name)
await client.send_message(discord.Object(id=i),embed=emb)
And this is the script that creates the channel on a command
#client.command(pass_context=True)
async def get_wchat(ctx):
servr = ctx.message.server
await client.create_channel(servr, 'world_chat',
type=discord.ChannelType.text)
I expect when someone says '(prefix)create_wchat' it creates a channel called 'world_chat' but I don't have to restart the bot or script for the person to receive messages others send.
You have to call await get_saki_chans() in your get_wchat command to update your global channels list every time one is created.
Currently you only call it once, on startup, so that's why you have to restart your bot.
However, instead of asking the user to invoke a specific command, I suggest you listen to on_channel_create, on_channel_delete and on_channel_update events so simply creating a channel called #world_chat, or renaming an existing one to this name ; makes it a world_chat channel.
Similarly you would avoid keeping a channel no longer named #world_chat or deleted.
I am trying to make a command called '!clear' that just removes the bots messages in a specific channel. This seems pretty straight forward using:
Client = discord.Client()
client = commands.Bot(command_prefix = "!")
#client.event
async def on_message(message):
if message.content.lower().startswith("!clear"):
async for x in client.logs_from(message.channel, limit = 100):
if str(message.author.id) == 'insert bots client id':
await client.delete_message(x)
client.run(token)
However, i found it wasn't deleting any messages. So before checking message.author.id i added a simple print(message.author.id) to see what ids it is picking up. It appears that it is spitting out only my client id and not seeing its own messages. The weird thing though is that if i change the author.id check to my client id then it will delete my messages and also the bots messages. So for some reason the bot thinks that its client id is the same as mine so when it is in a server that isn't my test server, it doesn't have the right permissions to delete my messages so it fails, even though I only want it to delete its own messages.
Any help would be great.
Don't you mean
if x.author.id == "bot id here":
await client.delete_message(x)
After all, each message is being put in x each iteration. Using message refers to the message in the async def on_message(message) function. Which would be the person who used the command. aka, you.