Automatically sending gifs in discord - python

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.

Related

How do I send a message to a specific discord channel while in a task loop?

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

Discord.py Bot Takes too Long to Respond

Goal:
I'm developing a discord bot which scans a url every 5 seconds or so, checks for a specified change on that webpage, and will send a message in the discord channel if that change occurs. I've done this by sending the url to the bot using an if statement in on_message. The url is then passed to a tasks.loop() function, where it is scanned and processed in another function for the change.
Problem:
I'd like to be able to send a message in the discord channel which quickly ends the process taking place in the tasks.loop(), so that I can pass it a different url to scan using the on_message function. In its current form, it works-- just very slowly. From the time the cancel trigger is sent, it takes around 3 minutes to send the verification message that the process has been cancelled. I need to make this 5 seconds or less. For what its worth, the bot is kept running using replit and uptime robot, but I am sure that the long response time is not related to the frequency the repl is awoken by uptime robot.
Code:
My code is much more complex and riddled with obscurely named variables, so here is a much simpler snippet of code with the same general structure.
client = discord.Client()
channel = client.get_channel(CHANNEL_ID)
#tasks.loop()
async def myloop(website, dataframe):
channel = client.get_channel(CHANNEL_ID)
try:
# iteratively scrape data from a website for
# a predefined change in the dataframe
if change = True:
await channel.send(notification)
except:
pass
#client.event
async def on_message(message):
channel = client.get_channel(CHANNEL_ID)
msg = message.content
if msg.startswith('track'):
website = msg[6:]
await channel.send('Now tracking '+str(website))
myloop(website,df)
if msg.starswith('stop'):
myloop.cancel()
await channel.send('Done tracking, awaiting orders.')
Attempted Solutions:
I have tried using some forms of threading, which I am very new to, and I haven't found a way to make it work any faster. Any suggestions or solutions would be greatly appreciated! I've been combing the web for help for quite some time now.
Looks like you could use client.loop.create_task to create asyncio task objects, and their cancel method to immediately cancel those asyncio tasks at the right time, e.g.
import asyncio
from replit import db
_task = None
async def myloop():
website = db['website']
dataframe = db['dataframe']
channel = client.get_channel(CHANNEL_ID)
while not client.is_closed():
await asyncio.sleep(5)
try:
# iteratively scrape data from a website for
# a predefined change in the dataframe
if change:
await channel.send(notification)
except:
pass
#client.event
async def on_message(message):
global _task # This gives the function access to the variable that was already created above.
msg = message.content
if msg.startswith('track'):
website = msg[6:]
await message.channel.send('Now tracking '+str(website))
db['website'] = website
db['dataframe'] = df
if _task is not None:
_task.cancel()
_task = client.loop.create_task(myloop())
if msg.startswith('stop'):
if _task is not None:
_task.cancel()
_task = None
await message.channel.send('Done tracking, awaiting orders.')
The argument create_task takes is a coroutine that takes no arguments, so the website URL and dataframe need to be accessible to the function a different way (I'm not sure which way you would prefer or would be best; using replit's db is just an example).
With this approach, you should be able to use track again to change which website is being monitored without using stop in between.
More details in the docs:
discord.Client.loop
loop.create_task
Task.cancel
asyncio.sleep
discord.Client.is_closed
Replit db

Im trying to setup a clear/purge command for my discord.py bot. There are no errors but when I run the command, nothing happens

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! :)

Messages not purging - discord.py rewrite

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.

Why is my discord bot spamming?

I have previously posted on this same bot and got it working thanks to the people who responded. But, while it finally came to life and turned on, it started spamming messages for no apparent reason. I've looked over the code for typos and can't find any.
Here's the code:
import discord
from discord.ext.commands import bot
from discord.ext import commands
import asyncio
import time
Client = discord.Client()
client = commands.Bot (command_prefix = discord)
#client.event
async def on_ready() :
print("Bepis machine fixed")
#client.event
async def on_message(message) :
if message.content == "bepis" :
await client.send_message (message.channel, "bepis")
client.run("Censored Bot Token")
after #client.event is where i need help. also the bottom line if fine this time! turns out i had hit the space bar before the parenthesis and it didn't like that. Help is very appreciated so i can continue adding on to this awesome bot.
It looks like you are sending a message "bepis" in response to the first, then every, message "bepis" - presumably your first response will appear as an entry on the incoming feed which will trigger a second, etc.
Turns out I was not using proper formatting for my bot.
Whenever you say "bepis" in the discord server, the bot will see it and then say "bepis" back, as its intended to do, but, because of my improper formatting, the bot saw itself say "bepis" and responded as if someone else was saying "bepis".
Old lines:
if message.content == "bepis" :
await client.send_message(message.channel, "bepis")
New lines:
if message.content.startswith('bepis'):
await client.send_message(message.channel, "bepis")
So make sure you're using the right format if you're making a bot!
You seemed to already know what the problem is, from this answer you posted. But your solution is far from being able to solve the problem.
on_message is called whenever a new message is sent to anywhere accessible by the bot; therefore, when you type in "bepis" in discord, the bot replies with "bepis", then the message sent by the bot goes into on_message, which the bot re-replies "bepis", and so on...
The simple solution is to check if the message's author is any bot account, or if you want, if the message's author is your bot.
from discord.ext import commands
client = commands.Bot(command_prefix=None)
#client.event
async def on_ready():
print("Bepis machine fixed")
#client.event
async def on_message(message):
# or `if message.author.bot:` # which checks for any bot account
if message.author == client.user:
return
if message.content == "bepis":
await client.send_message(message.channel, "bepis")
client.run("Token")
Note: I also fixed many of your other problems, such as multiple unused imports, another Client, and indentation.
And FYI, command_prefix is only used when command is being processed by a functional command. When you use on_message it has no use, which means you can set it to None.

Categories