Stop event handling by another event - python-3.x

I am developing bot with telegram client api and telethon. I created a command handler.
#client.on(events.NewMessage(outgoing=True, forwards=False, pattern=r'some_pattern'))
async def my_event_handler(event):
send_messages = []
while True:
send_messages.append(await client.send_message((await event.get_chat()).id, 'valueable_info'))
await asyncio.sleep(2)
I would like to delete send_messages and stop my_event_handler execution when events.NewMessage(outgoing=True, forwards=False, pattern=r'another_pattern') is triggered. How do i achive that?

Found a way to do that:
ids = []
def start_handler(event):
ids.append(event.id)
while event.id in ids:
do_stuff()
def stop_handler(event):
try:
ids.remove(event.id)
except ValueError:
pass

Related

Discord.py V2 not recognizing command, mistaking for message event

Wanted to drop an odd issue i've been having.
It seems, despite having process_commands in my message event function, it is still processing any commands as simple messages. This is odd because the file was working before. What I end up with with this code and sending >helloworld is a print out of the message object from the message event function.
Here's my code, if anybody could tell me what they know that would be huge.
intents = discord.Intents.default()
bot = commands.Bot(command_prefix='>', intents=intents)
#bot.event
async def on_ready():
print(f'[*] bot connected.')
class Menu(discord.ui.View):
def __init__(self, args, *kwargs):
self.guild_id = kwargs.pop('guild_id')
super().__init__(timeout=None)
self.value = None
#discord.ui.button(label="Yes", custom_id="yes", style=discord.ButtonStyle.green)
async def button_yes(self, button: discord.ui.Button, interaction: discord.Interaction):
print(True)
#bot.event
async def on_message(message):
print(message)
do stuff here
await bot.process_commands(message)
#bot.command()
async def helloworld(ctx):
view = Menu()
await ctx.channel.send('test', view=view())

Make sure that message has been sent

Let's say you are sending a message through your bot to all servers.
If you do too many actions through the api at the same time, some actions will fail silently.
Is there any way to prevent this? Or can you make sure, that a message really has been sent?
for tmpChannel in tmpAllChannels:
channel = bot.get_channel(tmpChannel)
if(not channel == None):
try:
if(pText == None):
await channel.send(embed= pEmbed)
else:
await channel.send(pText, embed= pEmbed)
except Exception as e:
ExceptionHandler.handle(e)
for tmpChannel in tmpAllChannels:
channel = bot.get_channel(tmpChannel)
if(not channel == None):
try:
if(pText == None):
await channel.send(embed= pEmbed)
else:
await channel.send(pText, embed= pEmbed)
except Exception as e:
ExceptionHandler.handle(e)
finally:
await asyncio.sleep(1) # this will sleep the bot for 1 second
Never hammer the API without any delay between them. asyncio.sleep will put a delay between messages, and you will send all of them without failing.

How do I get the discord bot to trigger commands on it's own message using discord.py?

Let's just say the user enters an invalid command, the bot suggests a command with (y/n)? If y, then the bot should trigger the suggested command.
I feel this can be achieved in 2 ways:
If the bot can trigger commands on its own message
If I can call the command from the other cogs
I can't seem to get either of em working.
Here is an example to help you guys help me better:
Let's just say this below code is from a cog called Joke.py:
#commands.command()
async def joke(self,ctx):
await ctx.send("A Joke")
And then there another cog "CommandsCorrection.py" that corrects wrong commands used by the user that are saved on data.json file:
#commands.Cog.listener()
async def on_message(self, message):
channel = message.channel
prefix = get_prefix(self,message)
if message.author.id == bot.id:
return
elif message.content.startswith(prefix):
withoutprefix = message.content.replace(prefix,"")
if withoutprefix in data:
return
else:
try:
rightCommand= get_close_matches(withoutprefix, data.keys())[0]
await message.channel.send(f"Did you mean {prefix}%s instead? Enter Y if yes, or N if no:" %rightCommand)
def check(m):
return m.content == "Y" or "N" and m.channel == channel
msg = await self.client.wait_for('message', check=check, timeout = 10.0)
msg.content = msg.content.lower()
if msg.content == "y":
await channel.send(f'{prefix}{rightCommand}')
elif msg.content == "n":
await channel.send('You said no.')
except asyncio.TimeoutError:
await channel.send('Timed Out')
except IndexError as error:
await channel.send("Command Not Found. Try !help for the list of commands and use '!' as prefix.")
in the above code await message.channel.send(f"Did you mean {prefix}%s instead? Enter Y if yes, or N if no:" %rightCommand) suggests the right command and await channel.send(f'{prefix}{rightCommand}') sends the right command.
So,for example:
user : !jok
bot : Did you mean !joke instead? Enter Y if yes, or N if no:
user : y
bot : !joke **I want to trigger the command when it sends this message by reading its own message or my just calling that command/function
How should I go about this?
One solution would be to separate the logic of your commands from the command callbacks and put it in it's own coroutines. Then you can call these coroutines freely from any of the command callbacks.
So you would turn code like this:
#bot.command()
async def my_command(ctx):
await ctx.send("Running command")
#bot.command()
async def other_command(ctx, arg):
if arg == "command":
await ctx.send("Running command")
Into something like this:
async def command_logic(ctx):
await ctx.send("Running command")
#bot.command()
async def my_command(ctx):
await command_logic(ctx)
#bot.command()
async def other_command(ctx, arg):
if arg == "command":
await command_logic(ctx)
#Patrick Haugh suggested this idea, he was on to something but wasn't really working but I got a way to get it working.
If you use the following method for a cog, you'll be able to read bot commands as well:
import discord
from discord.ext import commands
async def command_logic(self, ctx):
await ctx.send("Running command")
class Example(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command()
async def my_command(self, ctx):
await command_logic(self,ctx)
#commands.Cog.listener()
async def on_message(self, message):
if message.content == '!command':
ctx = await self.client.get_context(message)
await command_logic(self,ctx)
def setup(client):
client.add_cog(Example(client))

Python Discord Bot - Keep real time message parser from blocking async

I am writing a Discord Bot to take messages from a live chat and relay them to Discord channel, but want it to have other responsive features. Currently the script relays messages by entering a while loop which runs until the right message is recieved.
def chat_parser():
resp = sock.recv(4096).decode('utf-8')
#print(' - ', end='')
filtered_response = filter_fighter_announce(resp)
if resp.startswith('PING'):
# sock.send("PONG :tmi.twitch.tv\n".encode('utf-8'))
print("Ponging iirc server")
sock.send("PONG\n".encode('utf-8'))
return ''
elif (len(filtered_response) > 0):
if (filtered_response.count('ets are OPEN for') > 0):
filtered_response = get_fighters(filtered_response)
return filtered_response
return ''
fight = fight_tracker('') #initialize first fight object
def message_loop():
global first_loop_global
while True:
chat_reception = chat_parser()
if (chat_reception == ''):
continue
fight.set_variables(chat_reception)
return fight.announcement
return ''
The issue with this is that responsive functions for Discord are stuck waiting for this loop to finish. Here is the other code for reference.
#client.event
async def on_ready():
print('Finding channel...')
for guild in client.guilds:
if guild.name == GUILD:
break
channel = guild.get_channel(salty_bet_chat_id)
print('Connected to Channel.')
try:
print('Beginning main loop.')
while True:
message_out = await message_loop()
if (message_out != None and message_out != None):
print('Sending to Discord: ', message_out)
msg = await channel.send(message_out)
await msg.add_reaction(fight.fighter_1[1])
await msg.add_reaction(fight.fighter_2[1])
print('message sent...')
except KeyboardInterrupt:
print('KeyboardInterrupt')
sock.close()
exit()
#client.event
async def on_raw_reaction_add(reaction):
print(reaction)
#client.event
async def on_message(message):
print(message.author)
print(client.user)
client.run(TOKEN)
I have tried making async functions out of chat_parser() and message_loo() and awaiting their return where they are called, but the code is still blocking for the loop. I am new to both async and coding with Discord's library, so I am not sure how to make an async loop function when the only way to start the Discord client is by client.run(TOKEN), which I could not figure out how to incorporate into another event loop.

Is There A Way i Can Make A Auto-Warn And Auto-Kick Thing

Error: No, because i haven't made the code/ i don't know how to make the code, the code is below
#bot.event
async def on_message(message):
test = 'test'
if test in message.content.lower():
await message.author.send('you have been warned for using "bad words" in the server')
I want my code to warn the user 3 times then in the 4th time the bot kicks the user for writing test in the the server, is that possible?
You need to create a map of user ids to the number of times they have been warned. The easiest way to persist this map while the bot is offline is to store it in a JSON file, though as your bot scales you should eventually adopt a database.
from discord.ext.commands import Bot
from json import load
bot = Bot("!")
try:
with open("warns.json") as f:
warns = load(f)
except:
warns = {}
def should_warn(message):
return 'test' in message.content.lower()
async def warn_or_kick(member):
id = str(member.id)
if id not in warns:
warns[id] = 0
warns[id] += 1
if warns[id] >= 4:
await member.send("You have been kicked")
await member.kick()
else:
await member.send(f"This is warning number {warn[id]}")
with open("warns.json") as f:
dump(warns, f)
#bot.event
async def on_message(message):
if bot.user == message.author:
return
if should_warn(message):
await warn_or_kick(message.author)
else:
await bot.process_commands(message)
bot.run("TOKEN")

Resources