Messages repeating infinitely -- Discord.py - discord.py

So this is 100% a wip and I'm super confused on how to stop the discord bot from reading the same user message over and over again.
import discord
class MyClient(discord.Client):
async def on_ready(self):
print('Logged in as')
print(self.user.name)
print(self.user.id)
print('------')
async def on_message(self, message):
global choice
global r
# we do not want the bot to reply to itself
if message.author.id == self.user.id:
return
if message.content.startswith('!hello'):
await message.reply('Hello!', mention_author=True)
r=0
basic = True
#upgrade1 = False
choice = '!idle'
while(choice != '!end'):
if message.content.startswith('!idle'):
choice= await message.reply('!click / !bank / !upgrade / !minigame / !end')
if message.author.id == self.user.id:
return
if message.content.startswith('!click' or '!c'):
r = r + 1
await message.reply("You have " + str(r) + " Renown")
elif message.content.startswith ('!bank'):
await message.reply ("You have " + str(r) + " Renown")
#elif message.content.startswith ('!upgrade' and r >= 10):
#await message.reply('Upgrading..')
#r = r - 10
#basic = False
#elif message.content.startswith ('!upgrade' and r < 10):
#await message.reply ('Not Enough Renown')
elif message.content.startswith('!minigame' or '!mg'):
#random number choosing game
await message.reply ("Game")
elif message.content.startswith ('!end'):
basic = False
#while time.time() < future:
#r =r + .00001
client = MyClient()
client.run

Your issue comes from the while(choice != '!end') loop. Once the bot enters that loop, the messages he is sending within that loop of course will be repeated because you are not changing the value of choice unless the message is !idle.
Notice in your code how if the command is for example !click, you are sending the following message:
await message.reply("You have " + str(r) + " Renown")
But you are not changing the value of choice, so in the next iteration of the while loop it will repeat the same, once and again.
I'm not sure what you are trying to achieve, but having a while loop in the on_message event does not seem a good idea for me, as this is a blocking feature. In my opinion you should replace it with an if.

Related

discord.py problems with the checking

im trying to do a trivial discord bot, but with a "helper" it reveals you letter by letter the answer, each "x" senconds, but the problem is i can't to send the answer till the help is fully displayed
in the image the problem is cleary visible
this is the whole code
await ctx.send(a) #question
respuestas = b #answer
#reveal
string = respuestas[0]
blanked_string = [x if x.isspace() else "-" for x in string]
nonspace_indexes = [i for i, _ in enumerate(string)]
random.shuffle(nonspace_indexes)
for i in nonspace_indexes:
blanked_string[i] = string[i]
await ctx.send(''.join(blanked_string))
await asyncio.sleep(2)
#checking
def check(msg=discord.Message) -> True:
return msg.content.lower() in respuestas and msg.channel == ctx.message.channel
try:
guess = await bot.wait_for('message', timeout=6, check=check)
return await ctx.send(f"{guess.author.mention} first")
except asyncio.TimeoutError:
await ctx.send("time over")
#problem
https://i.stack.imgur.com/jlatG.png
note: im not trying to do a hangman
async def letters(response: str, channel: discord.TextChannel):
blanked_string = [x if x.isspace() else "-" for x in response]
nonspace_indexes = [i for i, _ in enumerate(response)]
random.shuffle(nonspace_indexes)
for i in nonspace_indexes:
blanked_string[i] = response[i]
await channel.send(''.join(blanked_string))
await asyncio.sleep(1)
#client.command()
async def game(ctx: commands.Context):
await ctx.send("Author of Python programming language...")
response = "Guido van Rossum"
letters_func = asyncio.create_task(letters(response, ctx.channel))
try:
player_response = await client.wait_for('message', check=lambda m: m.author == ctx.author and m.channel == ctx.channel, timeout=30)
except asyncio.TimeoutError:
letters_func.cancel()
await ctx.send("Time's up!")
else:
letters_func.cancel()
if player_response.content == response:
await ctx.send("Correct!")
else:
await ctx.send("Incorrect!")
Here is a possible resolution path for your problem. I took advantage of asyncio's presence to do this. You can test it, it works very well.
Be careful to adapt your response time to the length of your answer

Check which reaction a user picked [Discord.py]

This should be fairly simple and I've been trying what I've googled but no luck. All I want to do is send a message regarding which emoji had more reactions. But nothing is being sent out.
#bot.event
async def on_message(message):
if 'aoe2' in message.content and message.channel.id == 1048127088688889866:
BlueEmbed = discord.Embed(title='AOE Lobby',
description='**Lobby Link:** ' + '<' +
str(message.content) + '>',
colour=discord.Colour.blue())
message = await message.channel.send(embed=BlueEmbed)
await message.add_reaction('❤️')
await message.add_reaction('💙')
msg = await message.channel.fetch_message(message.id)
highest_reaction = ""
highest_reaction_number = 0
for reaction in msg.reactions:
if reaction.count - 1 > highest_reaction_number:
highest_reaction = reaction.emoji
highest_reaction_count = reaction.count - 1
await message.channel.send(f"{highest_reaction} wins with {highest_reaction_count} votes!")
the issue seems to be the program not waiting to check for votes, but rather executing the code instantly. Ignoring future reactions added. Not sure on a work around at this time. Seems I may need some sort of delay before running the if statement.
Use asyncio.sleep()
#bot.event
async def on_message(message):
if 'aoe2' in message.content and message.channel.id == 1048127088688889866:
BlueEmbed = discord.Embed(title='AOE Lobby',
description='**Lobby Link:** ' + '<' +
str(message.content) + '>',
colour=discord.Colour.blue())
message = await message.channel.send(embed=BlueEmbed)
await message.add_reaction('❤️')
await message.add_reaction('💙')
await asyncio.sleep(5) #however long u want in seconds
msg = await message.channel.fetch_message(message.id)
highest_reaction = ""
highest_reaction_number = 0
for reaction in msg.reactions:
if reaction.count - 1 > highest_reaction_number:
highest_reaction = reaction.emoji
highest_reaction_count = reaction.count - 1
await message.channel.send(f"{highest_reaction} wins with {highest_reaction_count} votes!")
or you can have another phrase trigger it
#bot.event
async def on_message(message):
global messageid
if 'aoe2' in message.content and message.channel.id == 1048127088688889866:
BlueEmbed = discord.Embed(title='AOE Lobby',
description='**Lobby Link:** ' + '<' +
str(message.content) + '>',
colour=discord.Colour.blue())
message = await message.channel.send(embed=BlueEmbed)
await message.add_reaction('❤️')
await message.add_reaction('💙')
messageid = message.id
if "trigger" in message.content and message.channel.id == 1048127088688889866::
msg = await message.channel.fetch_message(messageid)
highest_reaction = ""
highest_reaction_number = 0
for reaction in msg.reactions:
if reaction.count - 1 > highest_reaction_number:
highest_reaction = reaction.emoji
highest_reaction_count = reaction.count - 1
await message.channel.send(f"{highest_reaction} wins with {highest_reaction_count} votes!")

Wait for time, then DM with bot, with multiple users at once

I have a discord bot I am working on for practice that reminds the users with a dm after a certain amount of time. My issue is that I am using time.sleep() to handle the delay. This stops other users from setting up reminders because it is waiting for the previous time.sleep() to end. I want to have multiple requests for a reminder happen simultaneously, rather than wait for each request to end before the next one starts. Below is my code. My discord tokens are hosted in a seprate .env file.
# bot 2
import os
import discord
import time
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN2')
client = discord.Client()
#client.event
async def on_ready():
print(
f'{client.user} has connected to Discord!')
#client.event
async def on_message(message):
if message.author == client.user:
return
remind_me = 'You will be reminded '
if 'remindme!' in message.content.lower():
if message.content[-1] == 'h' or \
message.content[-1] == 's' or\
message.content[-1] == 'm':
response = remind_me + '\'' + message.content[10:-3] + '\' in' + message.content[-3::]
await message.channel.send(response)
else:
await message.channel.send('I don\'t understand.')
if message.content[-1] == 'h':
time.sleep(3600 * int(message.content[-2]))
await message.author.send('Reminder! \n' + message.content[10:-3])
if message.content[-1] == 's':
time.sleep(int(message.content[-2]))
await message.author.send('Reminder! \n' + message.content[10:-3])
if message.content[-1] == 'm':
time.sleep(int(message.content[-2])*60)
await message.author.send('Reminder! \n' + message.content[10:-3])
client.run(TOKEN)
I know I can clean up the if statements, so dont worry about that.
Use asyncio.sleep instead of time.sleep.
import asyncio
[...]
if message.content[-1] == 'h':
asyncio.sleep(3600 * int(message.content[-2]))
await message.author.send('Reminder! \n' + message.content[10:-3])
[...]

I'm having a problem with my modmail bot code that was written my discord.py

So, I'm making a modmail bot for my discord server. But when I run, the bot can connect but when I send a test messange in the bot DM, I receive this error: AttributeError: 'NoneType' object has no attribute 'send'.
I'm using python 3.9.1 on Arch Linux. Here is my code:
import discord
from discord.ext.commands import Bot
from discord.ext import commands
import asyncio
client = commands.Bot(command_prefix="!")
#client.event
async def on_ready():
await client.change_presence(activity=discord.Activity(type=discord.ActivityType.watching, name='for moderation mail'))
print("Thunderbird is ready")
#client.event
async def on_message(message):
empty_array = []
modmail_channel = discord.utils.get(client.get_all_channels(), name="modmail-box")
if message.author == client.user:
return
if str(message.channel.type) == "private":
if message.attachments != empty_array:
files = message.attachments
await modmail_channel.send("<#" + message.author.id + ">: ")
for file in files:
await modmail_channel.send(file.url)
else:
await modmail_channel.send("<#" + str(message.author.id) + ">: " + message.content)
elif str(message.channel) == "modmail" and message.content.startswith("<"):
member_object = message.mentions[0]
if message.attachments != empty_array:
files = message.attachments
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
for file in files:
await member_object.send(file.url)
else:
index = message.content.index(" ")
string = message.content
mod_message = string[index:]
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: " + mod_message)
client.run('No leaking here')
I am assuming that the error is on this line:
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
and member_object is coming from this block:
elif str(message.channel) == "modmail" and message.content.startswith("<"):
member_object = message.mentions[0]
if message.attachments != empty_array:
files = message.attachments
await member_object.send("**[MOD]** " + "**" + message.author.display_name + "**: ")
for file in files:
await member_object.send(file.url)
You are defining member_object as the first element in the message.mentions array, however your error of NoneType has no attribute suggests that there are no elements in that array and so member_object is actually equal to None not an instance of a class which has a send method.
You need to check your input to that function and ensure that when your code reaches that block it actually has the attributes that you are expecting

Call function outside of #client.event (discord.py)

I'm making a discord bot to play a game, using direct and open message commands to register player actions.
The message event handler is here. When getting a message to start the game, it'll start doing various things to get the game running.
import discord
import random
import datetime
client = discord.Client()
#client.event
async def on_ready():
print('We have logged in as {0.user}'.format(client))
#client.event
async def on_message(message):
if message.author == client.user:
return
if "!ww start" == message.content.lower() and not(discord.ChannelType == "private"):
# Do stuff
night(message)
if "!ww save " in message.content.lower() and discord.ChannelType == "private":
save(message)
if "!ww kill " in message.content.lower() and discord.ChannelType == "private":
kill(message)
if "!ww vote " in message.content.lower() and discord.ChannelType == "private":
vote(message)
if "!ww view " in message.content.lower() and discord.ChannelType == "private":
view(message)
if "!ww remove" == message.content.lower():
remove(message)
if ("!ww add" == message.content.lower()):
add(message)
if (message.content == '!ww count'):
count(message)
if discord.ChannelType == "private":
night(message)
day(message)
'''
One example of a function I want to call is here, like others it makes use of the message and channel. This is in line with the above block of code.
'''
async def night(message):
with open("GameData.txt", mode="r", encoding="utf-8") as my_file:
gameData = my_file.read().replace('\n', '')
if gameData[-1] != " ":
gameData = gameData + " "
gameData = list(gameData.split(", "))
if gameData[4] != "Night":
return
for i in range(len(gameData)):
if gameData[i] == ".":
return
# Read who was killed
channel = client.get_channel(int(gameData[1]))
if gameData[2] == gameData[0]:
await channel.send("Someone was saved in the night")
else:
killed = gameData[2]
await channel.send(killed + " was killed in the night")
remove(message)
await message.channel.send("It is now day, the game will continue when you all make your decision")
nightClean()
client.run("No")
Eventually there is a loop between two functions that call each other once run. They will only run when other inputs have been made through additional message inputs handled in other functions.
Currently I'm getting an error saying: RuntimeWarning: "coroutine 'day' was never awaited day(message)" as with another function.
How can I work around this?
Thanks!
To create a command use:
#client.command()
async def command_name(ctx, commands args like user to ban etc):
Do stuff
And this is a command. Don't use the on_message function.

Resources