Bot executing the same command twice - python-3.x

I am making a discord bot with the rewrite, but when my command runs, it sends the message twice
There is 100% no other calls to send that message, and it is only the 1st message(Hold on, I'm gathering the data), that is sent twice.
Here is the command's code:
#bot.command()
async def testcmd(ctx):
print("called")
msgtemp = await ctx.message.channel.send("Hold on, I'm gathering the data")
print("sent")
time.sleep(3)
await msgtemp.delete()
with open("fileofthings.txt") as fl:
await ctx.send(fl.read())

I had the same issue with my bot sending responses twice, does this happen with this particular command or it happens with other commands as well.
My theory is that you are running 2 versions of the bot meaning you get 2 messages. I developed a shutdown command in case this happens to me again
This is my code for a shutdown command if you need it.
#commands.command()
async def shutdown(self,ctx):
if ctx.message.author.id == OWNERID: #replace OWNERID with your user id
print("shutdown")
try:
await self.bot.logout()
except:
print("EnvironmentError")
self.bot.clear()
else:
await ctx.send("You do not own this bot!")

Had the same issue and it literally drove me mad. The problem may be that either you are running the same bot file from multiple devices or you are running it multiple times with the same device. My problem was fixed by following this method:
Open Task Manager in your device
Click on 'More details'
In the processes tab, search for 'python 3.9 (or whatever version you are currently using)', and click on it and click 'End task'.
Hope this resolves your issue.

Related

Bot won't leave voice channel when left alone

I have a personal music bot that plays music for me and friends, I only have a play and leave commands which both work perfectly, but I was wondering if a little upgrade to the bot automatically leaving voice channel when left in it alone was possible. After some reading in documentation, I thought I got it but this piece of my code simply doesn't work, it's almost like python is ignoring it for some reason so I guess I am missing something here...
so I was wondering if there is a reason why my code:
#client.event
async def on_voice_state_update(member):
voice_state = member.guild.voice_client
if len(voice_state.channel.members) == 1:
await voice_state.disconnect()
won't work, I don't get any error messages and literally nothing happens. Is it all as it should be here?
You are missing some arguments for this event. Simply add before and after and you should be fine.
The full event could be:
#client.event
async def on_voice_state_update(member, before, after):
voice_state = member.guild.voice_client
if voice_state is not None and len(voice_state.channel.members) == 1:
# If the bot is connected to a channel and the bot is the only one in the channel
await voice_state.disconnect() # Disconnect the bot from the channel
You can see more in the docs here:
on_voice_state_update

How do I schedule a task to run every x hours using cron? Discord.py

Basically, what I want to do is use the package aiocron to schedule an automatic reboot every 5-8 hours because I've noticed some tasks just stop functioning after a certain amount of time being online. I don't know why they stop but they do, I'm not getting any errors either, weirdly enough. If you want the code to the task I'm talking about, here it is:
#tasks.loop(count=None, minutes=2.5)
async def autoh(self):
await self.bot.wait_until_ready()
with open("autoposting.json", 'r') as f:
auto = json.load(f)
embed = discord.Embed(title="Enjoy your poggers porn lmao",
description=f"Posting can be slow, please take into consideration how many servers this bot is in and how many are using auto posting. Please be patient. If I completely stop posting, please rerun the command or join the support server.\n[Add me]({Invite}) | [Join the server]({Server}) | [Vote]({Vote})", colour=EMBED_COLOUR)
try:
embed.set_image(url=(await self.get_hentai_img()))
except nekos.errors.NothingFound:
return print("no image found")
else:
for entry in auto.items():
if "hentai_channel" in entry[1]:
channel = self.bot.get_channel(
entry[1]["hentai_channel"])
await asyncio.sleep(2)
if channel != None:
if not channel.is_nsfw():
await channel.send(f"This channel seems to not be NSFW anymore.\nThis message will continually repeat until you fix this issue.")
else:
try:
await channel.send(embed=embed)
except discord.Forbidden:
#pass
await channel.guild.owner.send(f"I was unable to autopost due to missing permissions in {channel.guild.name}, please check that the channel still exists and that I have the permission to post to it.\nThis message will continually repeat until you fix the issue at hand.")

Input Messages in Discord.py

I'm trying to find a way to program my bot to clear a specific amount of messages in a channel. However, I do not know how to get my bot to run it's code based on the user's input data. For example, let's say I'm a user who wants to clear a specific amount of messages, like let's say 15 messages. I want my bot to then clear 15 messages exactly, no more, no less. How do I do that?
if message.content == "{clear":
await message.channel.send("Okay")
await message.channel.send("How many messages should I clear my dear sir?")
This is legit all I got lmao. I'm sorry that I'm such a disappointment to this community ;(
Using a on_message event, you'd have to use the startswith mehtod and create a amount variable which takes your message content without {clear as a value:
if message.content.startswith("{clear"):
amount = int(message.content[7:])
await message.channel.purge(limit=amount+1)
However, I don't recommend using on_message events to create commands. You could use the commands framework of discord.py. It will be much easier for you to create commands.
A quick example:
from discord.ext import commands
bot = commands.Bot(command_prefix='{')
#bot.event
async def on_ready():
print("Bot's ready to go")
#bot.command(name="clear")
async def clear(ctx, amount: int):
await ctx.channel.purge(limit=amount+1)
bot.run("Your token")
ctx will allow you to access the message author, channel, guild, ... and will allow you to call methods such as send, ...

Multithreading with Selenium using Python and Telpot

I'm coding my first telegram bot, but now I have to serve multiple user at the same time.
This code it's just a little part, but it should help me to use multithread with selenium
class MessageCounter(telepot.helper.ChatHandler):
def __init__(self, *args, **kwargs):
super(MessageCounter, self).__init__(*args, **kwargs)
def on_chat_message(self, msg):
content_type, chat_type, chat_id = telepot.glance(msg)
chat_id = str(chat_id)
browser = browserSelenium.start_browser(chat_id)
userIsLogged = igLogin.checkAlreadyLoggedIn(browser, chat_id)
print(userIsLogged)
TOKEN = "***"
bot = telepot.DelegatorBot(TOKEN, [
pave_event_space()(
per_chat_id(), create_open, MessageCounter, timeout=10),
])
MessageLoop(bot).run_as_thread()
while 1:
time.sleep(10)
when the bot recive any message it starts a selenium session calling this function:
def start_browser(chat_id):
global browser
try:
browser.get('https://www.google.com')
#igLogin.checkAlreadyLoggedIn(browser)
#links = telegram.getLinks(24)
#instagramLikes(browser, links)
except Exception as e:
print("type error: " + str(e))
print('No such session! starting webDivers!')
sleep(3)
# CLIENT CONNECTION !!
chrome_options = Options()
chrome_options.add_argument('user-data-dir=/home/ale/botTelegram/users/'+ chat_id +'/cookies')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--lang=en')
print("Starting WebDrivers")
browser = webdriver.Chrome(options=chrome_options)
start_browser(chat_id)
return browser
and then this one check if the user is logged:
def checkAlreadyLoggedIn(browser, chat_id):
browser.get('https://www.instagram.com/instagram/')
try:
WebDriverWait(browser, 5).until(EC.element_to_be_clickable(
(By.XPATH, instagramClicks.buttonGoToProfile))).click()
print('User already Logged')
return True
except:
print('User not Logged')
userLogged = login(browser, chat_id)
return userLogged
and if the user is not logged it try to log the user in whit username and password
so, basically, when I write at the bot with one account everithing works fine, but if I write to the bot from two different account it opens two browser, but it controll just one.
What I mean it's that for example, one window remain over the google page, and then the other one recive two times the comand, so, even when it has to write the username, it writes the username two times
How can I interract with multiple sessions?
WebDriver is not thread-safe. Having said that, if you can serialise access to the underlying driver instance, you can share a reference in more than one thread. This is not advisable. But you can always instantiate one WebDriver instance for each thread.
Ideally the issue of thread-safety isn't in your code but in the actual browser bindings. They all assume there will only be one command at a time (e.g. like a real user). But on the other hand you can always instantiate one WebDriver instance for each thread which will launch multiple browsing tabs/windows. Till this point it seems your program is perfect.
Now, different threads can be run on same Webdriver, but then the results of the tests would not be what you expect. The reason behind is, when you use multi-threading to run different tests on different tabs/windows a little bit of thread safety coding is required or else the actions you will perform like click() or send_keys() will go to the opened tab/window that is currently having the focus regardless of the thread you expect to be running. Which essentially means all the test will run simultaneously on the same tab/window that has focus but not on the intended tab/window.
Reference
You can find a relevant detailed discussion in:
Chrome crashes after several hours while multiprocessing using Selenium through Python

Discord Python: How to add cooldown command under an event

I have looked at other posts in regards to how to make a cooldown command. One answer did exactly what I wanted, but that was only because I did exactly what they did. Now I want to officially implement the command into my Discord bot. I noticed that the cooldown command that I tested only worked under #client.command rather than #client.event (client is the object). I have all of my commands listed under the event thing, so I need help on how to add the cooldown command without having to rewrite a lot of things. This is what I have so far regarding the cooldown command.
from discord.ext.commands import Bot
from discord.ext import commands
client = Bot(command_prefix="?")
#client.event
#command.cooldown(5, 30, commands.BucketType.user)
async def on_message(message):
if message.content.upper().startswith("?HELLO"):
msg = 'Hello {0.author.mention} :banana:'.format(message)
await client.send_message(message.channel, msg)
#on_message.error
async def on_message_error(self, error, ctx):
if isinstance(error, commands.CommandOnCooldown):
msg = ':exclamation: This command is on cooldown, please try again in {:.2f}s :exclamation:'.format(error.retry_after)
await self.send_message(ctx.message.channel, msg)
I'm just using one command as an example to show what kind of format I have. I get the error with the #on_message.error (it was a trial an error thing, so I didn't expect it to work). I want to set a cooldown for 30 seconds after 5 consecutive attempts of the same command as well as an error message for the bot to say in response with the timer. I don't really want to have to rewrite the whole thing just for one command to work considering how far I've come to make this bot :/
You should add:
#commands.cooldown(1, 30, commands.BucketType.user)
This will add a ratelimit of 1 use per 30 seconds per user.
You can change the BucketType to default, channel or server to create a global, channel or server ratelimit instead, but you can only have 1 cooldown on a command.
This will also cause a CommandOnCooldown exception in on_command_error

Resources