我可以使用外部方式控制 discord.py 机器人吗?
Posted
技术标签:
【中文标题】我可以使用外部方式控制 discord.py 机器人吗?【英文标题】:Can I control a discord.py bot using external means? 【发布时间】:2021-05-25 21:25:26 【问题描述】:我想在 python 中创建一个外部 GUI 来控制我的不和谐机器人。到目前为止,我只看到 discord.py 与侦听器和命令前缀一起使用。 (我对协程不是很有经验)
我正在尝试做的一个例子:
async def mute(member):
await member.edit(mute=True)
while True:
member = client.fetch_member(int(input('member id: ')))
mute(member)
这样的事情可以实现吗?怎么样?
【问题讨论】:
这能回答你的问题吗? Discord.py get user object from id/tag 【参考方案1】:这是可以实现的,但是命令 bot.run(my_token) 正在阻塞,这意味着线程的执行在该命令处停止,因此在机器人关闭之前不会达到您的 while True。
我会写一个例子,但使用命令say
而不是ban,因为它更容易测试和使用
首先要做的是在单独的线程中运行机器人以避免阻塞。为此,只需使用这段代码
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
这将在另一个线程中启动机器人以避免阻塞。然后我们可以将主线程用于 while True 循环。但是由于不和谐命令是协程,我们不能简单地从主线程调用该方法,我们需要通过asyincio.run_coroutine_threadsafe运行协程。可以这样做:
在 Main.py 中,在不同线程中启动机器人后
while True:
text_to_send = input()
asyncio.run_coroutine_threadsafe(cog.say(text_to_send), loop)
其中 cog 是您通过 bot.add_cog() 添加到机器人的 Cog 对象,其中包含命令 say
在你的 cog 中,创建命令
@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)
使用此代码,如果您将the_guild_id_to_say
替换为您希望发送消息的公会ID,并将the_channel_to_say
替换为您希望发送消息的公会中的频道ID
从终端或外部方式调用命令的唯一问题是您没有Context,因此您必须找到不同的方法来获取命令的公会/频道。您可以在终端中将其写入要禁止的用户 ID 之前。我将很快编辑我的答案以使其更完整,但这应该足以让您开始
编辑/更新:
这是一个完全正常工作的机器人(假设您有所需的库),它可以通过//say Hello
或在终端上键入810277254592200737 Hello
发送消息,其中810277254592200737
是您希望机器人所在频道的ID发送消息
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)
参考资料: 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
【讨论】:
以上是关于我可以使用外部方式控制 discord.py 机器人吗?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以使用我的机器人在 discord.py 中附加大于 150Mb 的文件