It would be achievable, but the command bot.run(my_token) is blocking, it means the execution of the thread stops at that command, so your while True will not be reached until the bot is shutdown.
I will write an example but using the command say
instead of ban, since it is easier to test and work with
The first thing to do would be to run the bot in a separate thread to avoid blocking. To do that, simply use this bit of code
threading1 = threading.Thread(target=bot.run, args=[bot_token])
threading1.daemon = True
threading1.start()
loop = asyncio.get_event_loop() # this is needed for the While True
This will start the bot in another thread to avoid blocking. Then we can use the main thread for the while True loop. However since discord commands are coroutines, we cannot simply call the method from the main thread, we need to run the coroutine via asyincio.run_coroutine_threadsafe. This can be done like this :
In Main.py, after starting the bot in a different thread
while True:
text_to_send = input()
asyncio.run_coroutine_threadsafe(cog.say(text_to_send), loop)
where cog is the Cog object that you added to the bot via bot.add_cog() that contains the command say
In your cog, create the commmand
@command()
async def say(self, text: str = "hello"):
guild: Guild = self.bot.get_guild(the_guild_id_to_say)
channel: TextChannel = guild.get_channel(the_channel_to_say)
await channel.send(content=text)
With this code, if you replace the_guild_id_to_say
with the id of the guild in which you wish to send the message, and the_channel_to_say
with the id of the channel in the guild in which you wish to send the message
The only problem with calling a command from the terminal or external means, is that you do not have the Context so you have to find a different way to get the guild/channel of your command. You could write it in the terminal, before the id of the user to ban. I will soon edit my answer to be more complete but this should be more than enough for you to get started
EDIT/UPDATE :
Here is a fully working bot (given that you have the required libraries) that can send a message via either //say Hello
or by typing 810277254592200737 Hello
on the terminal where 810277254592200737
is the id of the channel on which you wish the bot to send the message
Bot.py
import asyncio
from discord.ext.commands import Bot
import threading
import sys
from View.OutsideCommunicationCog import OutsideCommunicationCog
class MyBot(Bot):
def __init__(self, command_prefix, **options):
super().__init__(command_prefix, **options)
def get_channel_id_and_text_from_input(text_to_parse):
input_as_list = text_to_parse.split()
channel_id = int(input_as_list[0])
text_to_send = " ".join(input_as_list[1:])
return channel_id, text_to_send
if __name__ == '__main__':
bot_token = sys.argv[1]
bot = MyBot(command_prefix="//")
bot_run_thread = threading.Thread(target=bot.run, args=[bot_token])
bot_run_thread.daemon = True
bot_run_thread.start()
cogs = [OutsideCommunicationCog(bot)]
outside_communication_cog = cogs[0]
for cog in cogs:
bot.add_cog(cog)
loop = asyncio.get_event_loop()
while True:
raw_input = input()
c_id, text = get_channel_id_and_text_from_input(raw_input)
print(c_id, text)
asyncio.run_coroutine_threadsafe(outside_communication_cog.say(None, message=text, channel_id=c_id), loop)
OutsideCommunicationCog.py
from typing import Optional
from discord import TextChannel
from discord.ext.commands import command, Context, Bot, Cog
class OutsideCommunicationCog(Cog):
bot: Bot
def __init__(self, bot):
self.bot = bot
@command()
async def say(self, ctx: Optional[Context], message: str, *, channel_id=None):
channel: TextChannel = self.bot.get_channel(channel_id) if channel_id is not None else ctx.channel
if ctx is None:
if channel_id is None:
print("No information to communicate")
await channel.send(content=message)
References :
How to use threading to get user input realtime while main still running in python
RuntimeError: Timeout context manager should be used inside a task
https://docs.python.org/3/library/asyncio-task.html#asyncio.run_coroutine_threadsafe