I'm trying to make a bot for my Discord server I want it to it to purge x amount of messages after x amount of days automatically when the bot starts.
I'm currently using discord.py rewrite.
This is how I'm trying to do the aforementioned
async def on_ready(self):
for guild in self.bot.guilds:
channel = self.bot.get_channel(494870373473583119)
if channel:
self.bot.loop.create_task(self.purge(channel))
async def purge(self, channel):
while True:
now = datetime.utcnow()
days_to_delete = now - timedelta(days=0)
await channel.purge(before=days_to_delete)
I've run this code through various changes to it and I'm unable to purge any messages. Could anyone tell me where I might be going wrong here. If you could break it down in an example or cite that would help.
You need to replace two_weeks_ago = now - timedelta(days=0) this line to two_weeks_ago = now - dt.timedelta(days=0) or change the way you are importing datetime and timedelta.
Related
I added a bot to Discord and added various functions in Python, but just as some work without any problems, the automatic sending of gifs at a specific time and on a specific channel doesn't work. After configuring everything and starting the bot, nothing happens, no error is displayed, and the console is also silent. What could be wrong? Below I'm sharing a part of the code responsible for this function, thank you in advance for your response.
import asyncio
import datetime
import discord
from discord.ext import commands
client = commands.Bot(command_prefix='.', intents=discord.Intents.all())
async def send_gif(channel):
print(f"Sending gif to channel {channel}")
gif_id = "Here's the gif id"
gif_url = f"Here's url"
await channel.send(gif_url)
#client.event
async def on_ready():
channel_id = "Here's the text channel ID"
channel = client.get_channel(channel_id)
await client.wait_until_ready()
while not client.is_closed():
now = datetime.datetime.now()
if now.hour == sample hour and now.minute == sample minutes:
await send_gif(channel)
await asyncio.sleep(60)
I would like the bot to send specific gifs at a specified time and on a specified channel, but I'm out of ideas. I tried using chatGPT, but it was unable to help. I also checked several times to make sure I was entering the correct gif IDs, channel IDs, and URLs, but it didn't help.
Check that you didn't miss any symbols on on_ready event.
Maybe the error is in
...
if now.hour == sample_hour and now.minute == sample_minutes:
...
Also, check that you defined sample_hour and sample_minutes variables before referring them in the code.
If still doesn't work try using the ext.tasks.loop decorator, if you don't know how to, take a look to the documentation
If it's not the thing causing the error, comment in this message and I will try to edit this message as fast as possible for solving doubts.
import discord
from discord.ext import commands, tasks
from discord_webhook import DiscordWebhook
client = discord.Client()
bot = commands.Bot(command_prefix="$")
#tasks.loop(seconds=15.0)
async def getAlert():
#do work here
channel = bot.get_channel(channel_id_as_int)
await channel.send("TESTING")
getAlert.start()
bot.run(token)
When I print "channel", I am getting "None" and the program crashes saying "AttributeError: 'NoneType' object has no attribute 'send' ".
My guess is that I am getting the channel before it is available, but I am unsure. Anybody know how I can get this to send a message to a specific channel?
Your bot cannot get the channel straight away, especially if it's not in the bot's cache. Instead, I would recommend to get the server id, make the bot get the server from the id, then get the channel from that server. Do view the revised code below.
#tasks.loop(seconds=15.0)
async def getAlert():
#do work here
guild = bot.get_guild(server_id_as_int)
channel = guild.get_channel(channel_id_as_int)
await channel.send("TESTING")
(Edit: Including answer from comments so others may refer to this)
You should also ensure that your getAlert.start() is in an on_ready() event, as the bot needs to start and enter discord before it would be able to access any guilds or channels.
#bot.event
async def on_ready():
getAlert.start()
print("Ready!")
Helpful links:
discord.ext.tasks.loop - discord.py docs
on_ready event - discord.py docs
bot.get_guild(id) - discord.py docs
guild.get_channel(id) - discord.py docs
"I can't get certain guild with discord.py" - Stackoverflow
This the start of the code. Did I type something wrong in the code that doesn't make the command work?
import discord
import os
from keep_alive import keep_alive
from discord.ext import commands
import random
client = commands.Bot(command_prefix= '>')
#client.event
async def on_ready():
print('The bot is online')
await client.change_presence(
activity=discord.Game('>help ┃ Created by ColeTMK'))
#client.command()
#commands.has_permissions(manage_messages=True)
async def clear(ctx, amount=6):
await ctx.channel.purge(limit=amount)
I have explained properly how to do that. Using the coroutine it is possbile.
There seems to be no error in your code. I would just say create the command as I have mentioned below and try again.
I created a purge command first which has the following code:
#nucleobot.command()
#commands.has_permissions(manage_messages=True)
async def purge(ctx, limit: int):
await ctx.message.delete()
await asyncio.sleep(1)
await ctx.channel.purge(limit=limit)
purge_embed = discord.Embed(title='Purge [!purge]', description=f'Successfully purged {limit} messages. \n Command executed by {ctx.author}.', color=discord.Colour.random())
purge_embed.set_footer(text=str(datetime.datetime.now()))
await ctx.channel.send(embed=purge_embed, delete_after=True)
How does this code work?
The command usage is deleted, i.e., !purge 10 would be deleted when sent into the chat.
It would pause for 1 second due to await asyncio.sleep(1). You would need to import asyncio in order to use it. (You might know that already :D)
The number of messages your entered are cleared from the channel using await ctx.message.delete(limit=limit) (This is a discord.py coroutine)
purge_embed is the embed variable which is used to send the embed after the deletion. I have used datetime module to add the time of the command completion on the embed. (You need to import datetime as well, but only if you want to use it. If not then remove the footer code.)
This would make up your complete and working purge command. :D
Examples with images.
I created a new channel and added 10 messages with numbers from 1 to 10 as shown below:
Then I entered the command in the message box and it was like (I know it was not needed but never mind):
After I sent this message and the command was executed, the purge successful embed was posted by the bot:
I was glad I could help. Any doubts of confusions are appreciated. Ask me anytime. :D
Thank You! :)
I have rewritten my existing Discord Bot so that commands work via #client.command.
Here is an example of the clear command so you can see how the language works.
#client.command()
async def echo(*args):
output = ""
for word in args:
output += word
output += " "
await client.say(output)
I would like to create 2 commands.
One which will -shutdown the bot, taking it offline, and unresponsive.
And the other which will -restart the bot, meaning that if I update the code, I run the restart command, and the bot will go offline, reboot, and then come back.
How would I go about doing this?
As I want the commands to only work for me, I have left by Discord User ID Below so you can include that in the code. 432234718860148749.
Thanks in advance,
H
https://discordpy.readthedocs.io/en/latest/ext/commands/api.html#discord.ext.commands.Bot.logout has your answer
#client.command()
#commands.is_owner()
async def shutdown(ctx):
await ctx.bot.logout()
However, I do not yet know how to restart a bot via a command
As of the latest version—Discord.py 1.3.3—try this:
# Close the bot
#client.command(aliases=["quit"])
#commands.has_permissions(administrator=True)
async def close(ctx):
await client.close()
print("Bot Closed") # This is optional, but it is there to tell you.
I need to implement some of the feature and one of the feature is implementing polls type feature. Can't use public discord bots due to some policies so we have to implement something on my own. Did some research yesterday and was able to make basic bot using python3 and commands api from discord.ext. Now what i need to figure out is:
Read reactions added by a user to a message?
Create a message with reactions (like bots which create reaction polls?)
Pin a message?
I believe from ctx i can get user tags (admin etc). Is there a better way to do so?
Couldn't find anything helpful on Commands reference page or probably i am looking at wrong documentation. any help would be appreciated.
thanks
Updated: Thanks guys. now i am stuck at how to add emoji, here is my code
poll_emojis = {0: ':zero:', 1: ':one:', 2: ':two:', 3: ':three:', 4: ':four:'}
#client.event
async def on_message(message):
if message.author == client.user:
return
if message.content.startswith('$create_poll'):
poll_content = message.content.split('"')
poll_text = poll_content[1]
poll_options = []
poll_option_text = ''
count = 0
for poll_option in poll_content[2:]:
if poll_option.strip() != '':
poll_options.append(poll_option)
poll_option_text += '{0}: {1}\t'.format(poll_emojis[count], poll_option)
count += 1
posted_message = await message.channel.send('**{0}**\n{1}'.format(poll_text, poll_option_text))
count = 0
for poll_option in poll_options:
await posted_message.add_reaction(Emoji(poll_emojis[count]))
count += 1
As an aside, given you're starting this project, and are already using the rewrite documentation, make sure you're using the rewrite version. There are some questions on here about how to make sure, and how to get it if you're not, but it's better documented and easier to use. My answers below assume you are using discord.py-rewrite
Message.reactions is a list of Reactions. You could get a mapping of reactions to their counts with
{react.emoji: react.count for react in message.reactions}
You could react to the message immediately after posting it:
#bot.command()
async def poll(ctx, *, text):
message = await ctx.send(text)
for emoji in ('👍', '👎'):
await message.add_reaction(emoji)
You can use Message.pin: await message.pin()
I'm not sure what you mean by "user tags". Do you mean roles?
I would write your command as
#bot.command()
async def create_poll(ctx, text, *emojis: discord.Emoji):
msg = await ctx.send(text)
for emoji in emojis:
await msg.add_reaction(emoji)
Note that this will only work for custom emoji, the ones you have added to your own server (This is because discord.py treats unicode emoji and custom emoji differently.) This would accept commands like
!create_poll "Vote in the Primary!" :obamaemoji: :hillaryemoji:
assuming those two emoji were on the server you send the command in.
With the new commands.Greedy converter, I would rewrite the above command like so:
#bot.command()
async def create_poll(ctx, emojis: Greedy[Emoji], *, text):
msg = await ctx.send(text)
for emoji in emojis:
await msg.add_reaction(emoji)
So invocation would be a little more natural, without the quotes:
!create_poll :obamaemoji: :hillaryemoji: Vote in the Primary!
I have just seen what you are stuck and I was stuck at this too. The solution is that reactions are not actually things like ":one:" it is actual emojis, there are different ways to fix this, the simplest being adding them to the dictionary yourself. Or you can use python3 -m pip install discordhelp and use the functions for it listed here.