You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何检测Discord频道X分钟内无消息发送?(discord.py)

解决Discord频道无消息检测的问题

看起来你在实现定时触发话题的机器人时,计时逻辑有点偏差——原代码的问题在于你一开始就固定了一个未来的timer时间,没有持续跟踪频道的最新消息状态,而且循环逻辑也没处理好。我来帮你修正这个问题,同时优化代码的健壮性。

原代码的核心问题

  1. 固定的timer变量:你一开始就把timer设为当前时间加指定时长,但如果在asyncio.sleep(time)期间频道有新消息,这个timer不会更新,到点还是会发送话题,不符合“频道X分钟无消息才触发”的需求。
  2. 全局变量冲突global keepLooping会导致多个频道同时使用命令时互相干扰,比如一个频道停止监控会影响所有频道。
  3. 缺乏异常处理:如果频道从未有过消息,ctx.channel.last_message会是None,直接访问created_at会报错。
  4. 无限循环无等待:进入while keepLooping后没有asyncio.sleep,会疯狂占用资源,甚至导致机器人被限制。

修正后的实现方案

下面是优化后的代码,解决了上述问题,还支持多频道独立监控、停止监控等功能:

import discord
import asyncio
import datetime as dt
import random
from discord.ext import commands

bot = commands.Bot(command_prefix='@')
# 替换成你的话题列表
TOPIC_LIST = ["你最近发现了什么有趣的小众爱好?", "如果能和五年前的自己说一句话,你会说什么?", "推荐一部你反复刷过的电影吧!"]

# 用字典跟踪每个频道的监控任务,避免全局变量冲突
monitoring_tasks = {}

@bot.command(name="timedtopic")
async def start_timed_topic(ctx, minutes: int):
    channel = ctx.channel
    
    # 检查频道是否已在监控中
    if channel.id in monitoring_tasks:
        await ctx.send(f"👉 这个频道已经在进行{monitoring_tasks[channel.id]['minutes']}分钟的话题监控啦!")
        return
    
    monitor_seconds = minutes * 60
    await ctx.send(f"✅ 已启动监控:当{channel.mention}连续{minutes}分钟无消息时,自动发送随机话题!")
    
    async def monitor_channel_activity():
        try:
            while True:
                now = dt.datetime.utcnow()
                
                # 处理频道从未有过消息的情况
                if channel.last_message is None:
                    embed = discord.Embed(title="💬 来聊点什么吧!", description=random.choice(TOPIC_LIST))
                    await channel.send(embed=embed)
                    await asyncio.sleep(monitor_seconds)
                    continue
                
                # 计算最后一条消息与当前时间的差值
                time_since_last_msg = now - channel.last_message.created_at
                
                # 满足触发条件:时间差≥设定时长,且最后一条不是机器人发的
                if time_since_last_msg.total_seconds() >= monitor_seconds and channel.last_message.author != bot.user:
                    embed = discord.Embed(title="💬 来聊点什么吧!", description=random.choice(TOPIC_LIST))
                    await channel.send(embed=embed)
                    # 发送后等待设定时长再继续监控,避免频繁刷屏
                    await asyncio.sleep(monitor_seconds)
                else:
                    # 每分钟检查一次,平衡实时性和资源占用
                    await asyncio.sleep(60)
        except asyncio.CancelledError:
            # 任务取消时清理记录
            del monitoring_tasks[channel.id]
            await ctx.send(f"🛑 {channel.mention}的话题监控已停止!")
    
    # 创建并启动监控任务
    task = bot.loop.create_task(monitor_channel_activity())
    monitoring_tasks[channel.id] = {"task": task, "minutes": minutes}

@bot.command(name="stopmonitor")
async def stop_timed_topic(ctx):
    channel = ctx.channel
    if channel.id in monitoring_tasks:
        monitoring_tasks[channel.id]["task"].cancel()
    else:
        await ctx.send("❌ 这个频道目前没有在进行话题监控哦!")

# 替换成你的机器人Token
bot.run("YOUR_BOT_TOKEN")

代码关键细节说明

  • 多频道隔离:用monitoring_tasks字典存储每个频道的监控任务,避免全局变量冲突,支持同时监控多个频道。
  • 动态时间检测:每次循环都计算当前时间与最后消息的时间差,确保只有当频道真的安静了指定时长才触发话题。
  • 异常处理:处理了频道无消息的情况,避免报错。
  • 资源优化:每分钟检查一次频道状态,既保证不会错过触发时机,又不会过度占用机器人资源。
  • 停止功能:添加了stopmonitor命令,让用户可以随时停止监控。

使用方法

  1. 输入@timedtopic 5启动监控:当频道连续5分钟无消息时,机器人会自动发送随机话题。
  2. 输入@stopmonitor停止当前频道的监控。

这样应该就能完美实现你想要的功能啦!

内容的提问来源于stack exchange,提问作者Libby

火山引擎 最新活动