I'm trying to make it so that only one instance of my bot can connect to Discord at a time and that the other connects only if the other one isn't connected. How could I achieve this? I'm using Discord.py. Also, if possible, I'd like it to work across multiple machines.
If you're asking what I think you're asking, that is, the bot should only be allowed to have one version of itself running on the machine at any one time, then this should work for all cases where you only want to have one of a script running at once.
One way we can do this is by having the script create a "lock" file, and exiting if said file already exists. Just remember to delete it when we're finished, even if the bot crashed.
(There are likely better ways to handle errors here and your bot code itself should do its best to handle errors that the bot may generate. For the most part discord.py will just keep going even when there are errors. This will just get the serious bot-crashing stuff and makes sure you can see what happened, while still gracefully closing and ensuring the lock file is deleted.)
import discord
from discord.ext import commands
import os # for file interactions
import traceback
# etc.
bot = commands.Bot(description="Hard Lander's lovely bot", command_prefix="!")
#bot.event
async def on_ready():
print("I'm ready to go!")
print(f"Invite link: https://discordapp.com/oauth2/authorize?client_id={bot.user.id}&scope=bot&permissions=8")
def main():
bot.run("TOKEN")
if __name__ == '__main__':
running_file = "running.txt"
if os.path.isfile(running_file): # check if the "lock" file exists
print("Bot already running!")
exit() # close this instance having taken no action.
else:
with open(running_file, 'w') as f:
f.write("running")
try: # catch anything that crashes the bot
main()
except: # print out the error properly
print(traceback.format_exc())
finally: # delete the lock file regardless of it it crashed or closed naturally.
os.unlink(running_File)
A simple way to do this to run the second bot after the bot.run() in the first bot.
Why? Because of the fact that it's blocking any other code that comes after it unless the bot stopped.
so I would suggest this:
bot.run("Your first bot token here")
import secondbot # you may use another method to run the bot script
Another way to do this is to make a third script for the second bot, this script will run periodically to check the first bot status (in this case, offline status), if the first bot status is offline, it will turn on the second bot. I'm not recommending this method for your case because you may want to change your first bot presence to offline which will make the third script think the bot goes offline.
Edit: After writing this answer I found a method of Bot called "is_closed" wich return bool wether or not the bot connected to the websocket, the link is here
Related
Thats my function what checks broadcast
def broadcast1():
if 'isLiveBroadcast' in contents:
return True
And thats my function what must send messages to specific text channel about broadcast
#bot.event
async def broadcast2(broadcast1):
if broadcast1 is True:
channel = bot.get_channel(1067083439263727646)
await channel.send('ЖАБА СТРИМИТ')
I have been written two functions which must work together and sends messages in text channel when broadcast is live but they dont work
No Errors, just doesnt working
There's quite a few fundamental issues with your code and the program logic.
Firstly, #bot.event is typically used for registering "listeners" to Discord events. There is no broadcast2 event to listen out for. Therefore, the function will never be executed. You can look at the event reference here and see all the events that we can respond/react to.
Secondly, as the commenter above as pointed out, you've not actually invoked the function. Saying if broadcast1 is Truedoesn't work how you think it works. By itself,broadcast1is a function, and thereforebroadcast1is a function object. It will never equal True; so event if we were listening for the right event, it would never do what you want it do anyways. What we _should_ be doing, is actually invoked the function:broadcast1()`. This means the function and the code gets run. There's lots of tutorials online about how functions in python work. Linked is just one example.
Thirdly, in the broadcast1 channel, you're checking if "isLiveBroadcast" is in contents. What contents? Where is that defined? You might need to rethink that as well.
All in all, you should probably look at following a Python basics course and then following some tutorials for putting together Discord bots. The docs are a good place to start - trying following the quickstart stuff and then adapting as you go along.
I only have one console open, I think this is because of the on_message because once I remove those it only responds once like it should. I am using await self.client.process_commands(message) after so really not sure why it would repeat. Please let me know if you have any suggestions.
I thenk you are using Cog and Cog.listener().
event and listener in discord.py is 2 different decorator. for example listeners called in events.
remove this line:
await self.client.process_commands(message)
I'm creating a Discord bot to play poker. I've a function wait_for_betting_to_end which is defined like this:
def wait_for_betting_to_end():
while not_all_players_have_bet():
pass
I've a command poker inside a cog which contains the following code fragment:
#commands.command(name='poker')
async def poker(self, ctx):
self.game_started = True
# ...
await preflop()
wait_for_betting_to_end()
# ...
I've a Discord command bet inside a cog:
#commands.command(name='bet')
async def bet(self, ctx, amt):
if not self.game_started:
print("You're not playing a game.")
return
# does something that would make wait_for_betting_to_end stop
The problem is that the user is never able to run the bet command while playing poker; the execution flow remains stuck in wait_for_betting_to_end forever. While not playing, bet correctly displays the error and exists.
How can I fix this?
The problem with your code is that you make an infite loop in your wait_for_betting_to_end() function. This is a mistake stemming from the thought that discord.py uses multithreading to get its asynchronous functionality(I can guess that much looking at the tags), however it doesn't. asyncio works in a single thread, where it does a task (like receiving a message, processing a command, etc) and does the next task on completion of that one, the power of asyncio stems from the ability to temporarily 'freeze' a task when no progress can be made (like waiting for a response or just plain sleeping) to continue on to the next task, and resuming the frozen task when it needs to. (I'm pretty sure 'freezing' is completely wrong terminology btw). Every command that your bot gets is handled in its own task. You making the infinite loop never release the poker task, so it's blocking the whole loop.
To fix your problem there are a few possibilities, like:
Instead of just infinitely looping, call await asyncio.sleep(0.1) instead of pass in your loop, this will allow your bot to get messages from discord in that time, and thus react to responses from your users. To stop your while loop you could use a self.value which you set to False when it needs be(in your bet command) (maybe use something like a dictionary with games for this as you probably want to run different games at the same time).
I don't really work with cog so I can't confidently give you a worked out example how you could do your code (at least not without risking missing some thing that can easily be done with cogs). But this should put you on the right path I believe.
I have a discord bot written in python. It doesn't do much, however if you spam commands while it is in the middle to replying to another command, it freaks out. is there a way to make it refuse other commands until it has finished with the current process?
Maybe some global variable "ready" and just allow to run commands if ready is true?
At start of command set ready to false and at the end to true.
I'm making a discord bot.
What my discord bot does listens to messages throughout the server and prints it real-time.
However, I also want the code to constantly recieve input from me from the console and print it out in a particular server ID. The following is my code:
#bot.event
async def on_message(message):
# Prints message
#bot.event
async def on_ready():
# Execute on-ready stuff
while True:
kb = input(">>>")
#Delivers the message into a certain channel
The problem is after the while True loop is executed, the other on_message functions stop working. I have seen other similar questions but I don't understand the async functions.
Could someone tell me how to both receive input continuously and print out incoming messages real-time?
The problem is not in while True, the problem is in the built-in input function, which is blocking and not async. Asyncio is based on cooperative multi-tasking, which means that your coroutine must choose to allow other code to run by awaiting something. Since your while loop doesn't await anything, it blocks everything else.
Look into the aioconsole package which provides an async version of input.