background task only running once discord.py - discord.py

I've been trying to create a discord bot that finds errors in a certain function and notify you
from discord.ext import commands
def alert(message):
bot = commands.Bot(command_prefix='!')
async def send_hi():
await bot.wait_until_ready()
channel = bot.get_channel(942139956938276997)
await channel.send(message)
bot.loop.create_task(send_hi())
bot.run(token)
def error_creator():
liste = [1, 2, 3, 4, "5", 6]
s = 0
for i in liste:
s = s+i
try:
error_creator()
except:
alert("there is an error")
try:
error_creator()
except:
alert('stop')
the problem is its only reporting the error once although ive called it two times, I can't figure it out
runnig the bot...
there is an error
and it doesn't continue

Related

Discord bot repeating the command but not an event in discord.py

I want to ask something.I got stuck on something.I wanted to add some new features to my bot such as swear words so that making cleaner server.I finished my code and tried to give command which is !dc greetings(!dc is my command_prefix btw).My bot sent 'Hi everyone' message for 7 times.That 7 times is same number as the number of swear words in "Badwords.txt".By looking these,that repeating issue is related to this file handling codes(or not idk).Interesting thins is when I write swear word into server's chatbox,bot send only one "Please do not use this word ever" message.So How can i prevent bot not to repeat for many times?Thank you
import discord
from discord.ext import commands
intents = discord.Intents(messages=True, guilds=True, reactions=True, members=True,presences=True)
client = commands.Bot(command_prefix="!dc ", intents=intents)
#Below command gets repeated 7 times everytime.That number is same as the number of swear words in "Badwords.txt"
#client.command(aliases=["sayHi"])
async def greetings(ctx):
await ctx.send('Hi everyone')
#My purpose in the below codes is countering profanity
with open("Badwords.txt", "r", encoding="utf-8") as f:
word = f.read()
badwords = word.split(",")
#In the below event,bot sends message only 1 time for 1 message
#client.event
async def on_message(message):
msg = message.content
for x in badwords:
if x in msg:
await message.delete()
await message.channel.send("Please do not use this word ever")
else:
await client.process_commands(message)
client.run(Token)
I would take the await client.process_commands(message) out of the else statement. I have also moved the with open inside the on message event so everything a message is sent, it will open the file to check if the message contained a bad word.
import discord
from discord.ext import commands
intents = discord.Intents(messages=True, guilds=True, reactions=True, members=True,presences=True)
client = commands.Bot(command_prefix="!dc ", intents=intents)
#client.command(aliases=["sayHi"])
async def greetings(ctx):
await ctx.send('Hi everyone')
#client.event
async def on_message(message):
msg = message.content
with open("Badwords.txt", "r", encoding="utf-8") as f:
word = f.read()
badwords = word.split(",")
for x in badwords:
if x in msg:
await message.delete()
await message.channel.send("Please do not use this word ever")
else:
return
await client.process_commands(message)
client.run(Token)
await client.process_commands(message) was taken out of the else statement because, with your current code, the bot would only process the commands if the message did NOT contain a bad word. But we need it to process the commands every time a message is sent.

Discord.py Bot is not online, but still works

i have a problem with my discord bot, whenever i run the code below using apraw to get the titles of the recent submissions on a subreddit the bot doesn't appear online anymore but still returns the titles in CMD :
Bot is not online when i execute this but still asks for subreddit name & prints the titles of the new posts of the subreddit in CMD:
import asyncio
import apraw
from discord.ext import commands
bot = commands.Bot(command_prefix = '?')
#bot.event
async def on_ready():
print('Bot is ready')
await bot.change_presence(status=discord.Status.online, activity=discord.Game('?'))
#bot.command()
async def online (ctx):
await ctx.send('Bot is online !')
reddit = apraw.Reddit(client_id = "CLIENT_ID",
client_secret = "CLIENT_SECRET",
password = "PASSWORD",
user_agent = "pythonpraw",
username = "LittleBigOwl")
#bot.event
async def scan_posts():
xsub = str(input('Enter subreddit name : '))
subreddit = await reddit.subreddit(xsub)
async for submission in subreddit.new.stream():
print(submission.title)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(scan_posts())
bot.run('TOKEN')
But is online when i execute this but obviously doesn't ask for sub name... :
import asyncio
import apraw
from discord.ext import commands
bot = commands.Bot(command_prefix = '?')
#bot.event
async def on_ready():
print('Bot is ready')
await bot.change_presence(status=discord.Status.online, activity=discord.Game('?'))
#bot.command()
async def online (ctx):
await ctx.send('Bot is online !')
bot.run('TOKEN')
So reddit is the problem here. But what exaclty do i ahve to change in order to make my bot apear online whilst still being able to retreive the titles of new submissions on a given subreddit? The code doesn't return any error:/
the #bot.event that you put above async def scan_posts(): should be changed to #bot.command(). It triggers by itself because you have this in your code:
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(scan_posts())
this is what causes the scan_posts to run automatically. You should remove this as you want scan_posts to be a bot command and not something that happens automatically. The bot also doesn't come online because of this code. What this does is check if this file has been run and then runs scan_posts. The rest of the code won't be triggered.
Also, you shouldn't change presence in on_ready as Discord has a high chance to completely disconnect you during the on_ready event and there is nothing you can do to prevent it. Instead you can use the activity and status kwargs in commands.Bot like:
bot = commands.Bot(command_prefix = '?', status=discord.Status.online, activity=discord.Game('?'))

My giveaway cog command isn't working for some reason

So I made a giveaway command in a cog, and for some weird reason it's not working. I'm not getting any errors or anything. Since it's "interactive", the first two questions work fine but once it asks for the prize, it just freezes and doesn't do anything after that. My friend is also working on a different bot and gave me his code which worked perfectly on his end, but not on mine. Here is my code:
import discord
from discord.ext import commands
from discord.ext.commands import BucketType, cooldown, CommandOnCooldown
import random
import json
import datetime
import asyncio
class Giveaway(commands.Cog):
"""Giveaway commands. You must have manage message permissions to use these"""
def __init__(self, bot):
self.bot = bot
# Helper functions
def convert(self, time):
pos = ["s", "m", "h", "d"]
time_dict = {"s": 1, "m": 60, "h": 3600, "d": 2600*24}
unit = time[-1]
if unit not in pos:
return -1
try:
val = int(time[:-1])
except:
return -2
return val * time_dict[unit]
# Bot Events
# Bot Commands
#commands.command()
#commands.has_permissions(kick_members=True)
async def giveaway(self, ctx, host: discord.Member):
await ctx.send("Let's start with this giveaway! Answer these questions within 15 seconds!")
questions = ["Which channel should it be hosted in?",
"What should be the duration of the giveaway? (s|m|h|d)",
"What is the prize of the giveaway?"]
answers = [f"{ctx.channel.mention}"]
def check(m):
return m.author == ctx.author and m.channel == ctx.channel
for i in questions:
await ctx.send(i)
try:
msg = await self.bot.wait_for('message', timeout=15.0, check=check)
except asyncio.TimeoutError:
await ctx.send('You didn\'t answer in time, please be quicker next time!')
return
else:
answers.append(msg.content)
try:
c_id = int(answers[0][2:-1])
except:
await ctx.send(f"You didn't mention a channel properly smh")
return
channel = self.bot.get_channel(c_id)
time = convert(answers[2])
prize = answers[3]
await ctx.send(f"The giveaway for {prize} will be in {channel.mention} and will last {answers[2]}!! Hosted by {host.mention}")
embed = discord.Embed(title="Giveaway!", description=f"{prize}", color=discord.Colour.dark_purple())
embed.add_field(name="Hosted by:", value=f"{host}")
embed.set_footer(text=f"Ends {answers[2]} from now!")
my_msg = await channel.send(embed=embed)
await my_msg.add_reaction("🎉")
await asyncio.sleep(time)
new_msg = await channel.fetch_message(my_msg.id)
users = await new_msg.reactions[0].users().flatten()
users.pop(users.index(self.bot.user))
winner = random.choice(users)
await channel.send(f"Congratulations! {winner.mention} won the prize: {prize} from {host.mention}!!")
def setup(bot):
bot.add_cog(Giveaway(bot))
Please let me know what I should do to fix it!!

Can't figure out how to correctly schedule my asyncio functions

I'm rather new to asyncio and I read through some documentation, examples, and other questions, but I can't find any answers as to what I'm doing wrong here. I don't quite understand enough about asyncio to diagnose why this is happening. I have a class with asyncio functions, one of which opens a websocket and then creates three asyncio tasks which it executes. The first executes completely fine. I'm confused with the execution of the second and third tasks. Even after the second one has executed asyncio.sleep, the third task seems to not execute websock.recv(), and so the second task executes websocket.recv() and gets sent the data that I meant for the third task to receive. What am I doing wrong here? Thanks in advance for any help.
Edit: Sorry the code isn't runnable unless you create or have a discord bot and use it's token in the code.
import websockets
import requests
import asyncio
import json
class GatewayConnection:
def __init__(self):
self.heartbeat = None
self.s = None
self.info = None
self.connected = False
self.uri = f"{self.get_gateway()}/?v=8&encoding=json"
#staticmethod
def get_gateway():
endpoint = requests.get(OAUTH+'gateway')
return endpoint.json()['url']
async def get_gateway_info(self, websock):
recv = json.loads(await websock.recv())
self.heartbeat = recv['d']['heartbeat_interval']
self.s = recv['s']
async def finish_gateway_connect(self, websock):
await websock.send(json.dumps({
'op': 2,
'd': {
'token': TOKEN,
'intents': 513,
'properties': {
'$os': 'windows',
'$browser': 'Sheepp',
'$device': 'Sheepp'
}
}
}))
print("waiting to received ready info")
self.info = json.loads(await websock.recv())
print("Ready info received")
print(self.info)
async def communicate(self):
async with websockets.connect(self.uri) as websock:
self.connected = True
get = asyncio.create_task(self.get_gateway_info(websock))
heartbeat = asyncio.create_task(self.send_heartbeat(websock))
finish = asyncio.create_task(self.finish_gateway_connect(websock))
await get # First task
await heartbeat # Second task
await finish # Third task
async def send_heartbeat(self, websock):
while self.connected:
await websock.send(json.dumps({'op': 1, 'd': self.s}))
print("Sent heartbeat")
response = json.loads(await websock.recv())
print("Received 'heartbeat'")
if response['op'] != 11:
self.connected = False # Discord api says to terminate connection upon not receiving a valid heartbeat response
print(f"The server did not send back a valid heartbeat response, but instead: {response}")
await asyncio.sleep(self.heartbeat/1000)
gateway = GatewayConnection()
try:
loop.run_until_complete(gateway.communicate())
except KeyboardInterrupt:
print("Keyboard Interruption")
finally:
loop.close()
To fix the error I was getting, I made a separate class for handling the websocket which makes sure that the recv and send functions are executed in time correctly. I'm not sure about how well I made the class but here it is:
class WebsocketHandler:
def __init__(self, websocket):
self.ws = websocket
self.sending = False
self.sends = []
self.recvs = []
async def send(self, data):
if self.sending:
self.sends.append(json.dumps(data))
else:
self.sending = True
await self.ws.send(json.dumps(data))
while self.sends:
data = self.sends[0]
self.sends.pop(0)
await self.ws.send(json.dumps(data))
self.sending = False
async def recv(self):
event = asyncio.Event()
self.recvs.append(event)
while self.recvs[0] != event:
await event.wait()
try:
data = await asyncio.wait_for(self.ws.recv(), timeout=1)
except asyncio.exceptions.TimeoutError:
self.recvs.pop(0)
raise asyncio.exceptions.TimeoutError
self.recvs.pop(0)
if len(self.recvs) > 0:
self.recvs[0].set()
return json.loads(data)
The error I was getting was RuntimeError: cannot call recv while another coroutine is already waiting for the next message
Edit: Feel free to critique my code.
Edit 2: I made a couple changes as needed to fix some errors I was getting as well as for convenience sake.

Discord.py bot, category isn't being created at the required position

import discord
from discord.ext import commands
botToken = "*"
client = commands.Bot(command_prefix = '*')
#client.event
async def on_ready():
print("I'm ready!")
#client.command()
async def start(ctx):
a = await ctx.guild.create_category("TEST", position=0)
a.position = 0
client.run(botToken)
position= int and channel.position = int ain't working..Haven't found any question related to my problem, gave bot Administrator permissions at https://discord.com/developers/applications and got the link let him in my server, create a role with everything allowed and gave him the role, didn't work..
create_text_channel and create_voice_channel nothing changes, The channels are being set as if I didn't assign a position to them.
Picture showing where the category position
It's not working because there's no position 0, the first position is always 1
category = await ctx.guild.create_category("TEST", position=1)
If it still creates the category in another position you can manually edit it:
await category.edit(position=1)

Resources