Python:通过 cog 和后台任务向 Discord 中的特定频道发送消息

Posted

技术标签:

【中文标题】Python:通过 cog 和后台任务向 Discord 中的特定频道发送消息【英文标题】:Python: Send message to specific channel in Discord via cog and background task 【发布时间】:2020-10-12 23:06:44 【问题描述】:

我有一个 Discord Python 机器人,我正在尝试运行一个后台任务,该任务将每隔 X 秒不断地向频道发送一条消息 - 不需要命令。目前有任意 5 秒用于测试目的。

这是有问题的 cog 文件(为提高效率而删除了导入和其他内容)

class TestCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.mytask.start()

    @tasks.loop(seconds=5.0)
    async def mytask(self):
        channel = client.get_channel(my channel id here)
        await channel.send("Test")

def setup(bot):
    bot.add_cog(TestCog(bot))

我有一种感觉,这是因为 self 参数是唯一传递的参数,但我有点困惑阅读 API 文档,了解这里究竟要做什么。

我试过client 而不是bot,我试过定义discord.Client()(但就我所读的内容而言,我不应该使用我一直试图避免的那个。

在使用实际命令的其他 cogs 中,我将其设置为这样有效:

    @commands.command(name='test')
    async def check(self, ctx):
        if ctx.channel.name == 'channel name':
            await ctx.send("Response message")

这让我相信我传递的参数是错误的。我明白,因为我正在传递 ctx 我可以获取频道名称,但我不太确定如何仅使用 self.尝试传递 ctx 参数时,我没有收到任何错误,但由于明显的原因,消息没有发送。

我到底错过了什么?感谢您的帮助!

【问题讨论】:

【参考方案1】:

discord.Client 对象没有 get_channel() 方法。您必须改用 discord.Guild 对象:

await client.get_guild(guild_id_here).get_channel(channel_id_here).send("Test")

Read the docs.

【讨论】:

【参考方案2】:

您可以使用.loop.create_task(mytask(arguments)) 将任务添加到您的异步循环中,您将在启动机器人之前调用该任务。 Read all about asyncio here

您可以像使用async def mytask(argument) 的普通命令一样定义任务,但是忽略 ctx,因为 ctx 基本上是您通常会获得的有关用于调用该函数的命令的所有上下文。 相反,您需要使用频道 ID 手动获取带有 channel = bot.get_channel(id) 的频道对象,然后您可以使用 await channel.send("Your message") 向所述频道发送消息。

要让它循环,只需使用带有asyncio.sleep(delay)while True 循环来计时。 由于您必须等待消息发送,这可能会导致计时不准确,因此我建议您在函数前面使用 clock = asyncio.create_task(asyncio.sleep(delay)) 开始计时任务,并在函数之后使用 await clock 捕获它

现在,如果您希望它在每个时间间隔的某个时间运行,而不仅仅是在您启动函数时的设定时间间隔,您需要延迟函数的启动以匹配您设置的时间。您可以使用divmod(time.time(), interval) 来执行此操作,它返回商和剩余时间以及您的间隔,剩余时间是自上次间隔开始以来的时间。如果要在间隔开始时启动函数,可以使用await asyncio.sleep(interval-remainder) 使函数休眠,直到下一个间隔开始。如果您想在该时间间隔内设置一个时间,您需要将其分成两部分,一个用于您设定的时间已过,另一个用于您设置的时间尚未到来。

if remainder < set_time: 
    await asyncio.sleep(set_time - remainder)
else:
    await asyncio.sleep(interval + set_time - remainder)

现在,如果你将所有这些加到一个函数中,你会得到类似这样的东西(这是我在我的机器人中使用的一段代码:

async def reminder(channel, interval, set_time, message):
    await bot.wait_until_ready()
    channel = bot.get_channel(channel)
    quotient, remainder = divmod(time.time(), interval)
    if remainder < set_time:
        await asyncio.sleep(set_time-remainder)
    else:
        await asyncio.sleep(set_time + interval - remainder)
    while True:
        clock = asyncio.create_task(asyncio.sleep(interval))
        await channel.send(message)
        quotient, remainder = divmod(time.time(), interval)
        if remainder-set_time > 1:
            clock.cancel()
            await asyncio.sleep(interval-1)
        await clock

bot.loop.create_task(reminder(774262090801479740, 3600, 3300, "This is the 55th minute of the hour"))
bot.run(TOKEN)

(我知道这不是 100% 回答问题,但正如你所说,你尝试了 botclient 这个解决方案应该适合你)

【讨论】:

以上是关于Python:通过 cog 和后台任务向 Discord 中的特定频道发送消息的主要内容,如果未能解决你的问题,请参考以下文章

WC2001cogs358高性能计算机(动态规划)

python3-disc和set

DISC测试工具,帮助你成为行为判断专家

程序被送入后台后,向 iOS 借时间,完成长期任务-备

cogs 1254. 最难的任务 Dijkstra + 重边处理

python多线程并行计算通过向线程池ThreadPoolExecutor提交任务的实现方法