You could use on_message
to override the bot from invoking commands automatically, then build some logic for you to decide decide it doesn't want to take any commands anymore (aka sleep). But be sure you have the option as the bot owner to awaken it or you're SOL and will need to restart.
Something like the following should work.
The assumption in my code being you're using the rework and f-strings are acceptable, but the logic is here and very little needs to be changed I think for it to be compatible with the async
version.
Basic control flow:
bot.py
from discord.ext import commands
class MyBot(commands.bot):
def __init__(self, command_prefix = '!', description=None):
super().__init__(command_prefix, description)
#you could just say False here but if you
#want to start the bot asleep here's a decent way to do it.
self.asleep = kwargs.get('asleep', False)
async def is_owner(obj):
owner = self.application_info().owner
return obj.author == owner
async def on_message(self, message):
ctx = await self.get_context(message)
is_owner = client.is_owner(ctx):
if is_owner or not self.asleep:
self.invoke(ctx)
...
owner.py - or wherever you keep your "bot owner only" commands.
from discord.ext import commands
...
@commands.command()
async def sleep(self, ctx):
self.bot.asleep = True
await ctx.say(f"I am now asleep, I will only respond to {ctx.author}")
@commands.command()
async def awaken(self, ctx):
self.bot.asleep = False
await ctx.say("Ahhh, just woke up! Ready to take commands!")
...
launcher.py
import MyBot
...
bot = MyBot(...)
bot.load_extension("path/to/owner_py_file")
...
I came up with this based on how RDanny bot assign's it's Database to each context before a command is called. It's a very well written bot that the owner has put out the source code publicly for educational purposes.
Edit
to accommodate your current build
For your case, I assume you're just creating a bot using something like client = commands.bot(...)
this is again pretty cookiecutter and won't allow you to leverage any power you'd gain from subclassing bot
, but you could just implement the following and gain the same functionality as above:
client = commands.bot(...)
client.asleep = False
Then for the commands that you showed in the question:
@client.command(pass_context=True)
async def sleep(ctx):
client.sleep = True
@client.command(pass_context=True)
async def awake(ctx):
client.asleep = False
Then for the on_message
override. Please reference: this answer to help explain why this works. or even the docs. hint hint
async def _is_owner(obj):
owner = self.application_info().owner
return obj.author == owner
@client.event()
async def on_message(message):
ctx = await self.get_context(message)
is_owner = _is_owner(ctx):
if is_owner or not self.asleep:
client.invoke(ctx)
If the above implementation fails to work for you then you can give the method described in the answer I linked just above:
@client.event
async def on_message(message):
is_owner = _is_owner(ctx):
if is_owner or not client.asleep:
await bot.process_commands(message)
Please note I don't know how you're module is structured but if this is being done within a class, and you define _is_owner(...)
within that class, you will need to use is_owner = self._is_owner(...)
although this could be defined elsewhere.