来自命令的 Discord Bot 循环任务

Discord Bot Looping Task from Command

大家下午好, 我应该在 post 开头声明我是 Python 的新手并且知道足以让自己陷入麻烦,但还不足以总能摆脱麻烦......这就是其中一个例子我出不去了。

我正在尝试使用 discord.py 创建一个 Discord Bot,其最终目标是从 Discord 中的命令启动,开始计算启动命令发出后的天数,并向 Discord 发送消息每天早上和伯爵在一起。我还会有一个命令来重置计数,另一个命令来取消计数器。 出于测试目的,我创建了代码来计算分钟数而不是天数,并创建了一个仅 10 秒而不是一整天的任务循环。

我的问题是我试图在循环中使用 discord.ext 任务,但我显然不知道如何正确使用它,我的在线研究也没有更清楚地说明我。我希望这里的一些人可以引导我朝着正确的方向前进。我在下面提供了我的代码。

当我执行我的代码时我期望发生什么:

实际发生了什么:

代码目前托管在 replit.com 上,因此 keep_alive 函数使用 UpTimeRobot 来保持机器人的活动。 需要注意的是,我最初使用 asyncio.sleep() 只是等待发送新消息。这在较短的时间内(比如几分钟到几小时)效果很好,但即使有 UpTimeRobot 做它的事情,我也无法获得机器人 100% 的正常运行时间,我认为每当机器人离线几分钟,它就会停止我的柜台循环就是这样。这就是促使我研究任务的原因,正如我所读,如果机器人离线一段时间,它们可用于在重新连接时继续循环。

import discord
import os
import keep_alive
from datetime import date, datetime, time, timedelta
from discord.ext import commands, tasks

bot = commands.Bot(command_prefix="$")
init_count = 0
count = 0
channel_id = My_Channel_ID_Here

@bot.event
async def on_ready():
    print('We have logged in as {0.user}'.format(client))

@tasks.loop(seconds=10, count=None, reconnect=True)
async def min_counter():
    global count
    global init_count
    count = init_count
    today = datetime.today()
    now = datetime.today()
    channel = bot.get_channel(channel_id)

    if today.minute != now.minute:
            # increment count by 1
      count = count + 1
      today = now
      print('Count: ' + str(count))
      await channel.send('It Has Been ' + str(count) + ' Minutes.') # Send message of minutes count

@bot.command() # Command to start the counter
async def start (ctx, arg: int): # arg is initial number of minutes to start with
    global init_count
    init_count = arg
    await ctx.send('It Has Been ' + str(init_count) + ' Minutes.') # Send message of minutes count
    min_counter.start()

@bot.command() # Command to reset counter
async def reset (ctx):
    global count
    count = 0
    await ctx.send('It Has Been 0 Minutes.') # Send message that count is not zero

@bot.command() # Command to stop the counter
async def stop (ctx):
    min_counter.cancel()
    await ctx.send('Counter Stopped.')

keep_alive.keep_alive() # keep alive function call
bot.run(os.getenv('TOKEN')) # Discord bot private token call

经过快速检查,您正在循环方法 min_counter(),但每次调用它时,您都会将 nowtoday 的值更改为 datetime.today()

所以当你去比较这里的值时:

if today.minute != now.minute:
  # increment count by 1
  count = count + 1
  today = now
  print('Count: ' + str(count))
  await channel.send('It Has Been ' + str(count) + ' Minutes.') # Send message of minutes count

这将始终评估为 False

轻松修复

虽然我不太喜欢使用全局变量,但我们可以通过以下方法解决此问题,同时保持您现在的风格。

启动计数器并在全局范围内初始化一个名为 start_time 的变量:

@bot.command() # Command to start the counter
async def start (ctx, arg: int): # arg is initial number of minutes to start with
    global init_count, start_time
    start_time = datetime.today()
    await ctx.send('It Has Been ' + str(init_count) + ' Minutes.') # Send message of minutes count
    min_counter.start()

然后在循环中检查start_time是否等于now

@tasks.loop(seconds=10, count=None, reconnect=True)
async def min_counter():
    global count, start_time, init_count
    now = datetime.today()
    channel = bot.get_channel(channel_id)

    if start_time != now:
      # increment count by 1
      count = count + 1
      print('Count: ' + str(count))
      await channel.send('It Has Been ' + str(count) + ' Minutes.') # Send message of minutes count

如果一切都适合您,请告诉我,如果需要,我很乐意提供进一步帮助。