You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py抽奖命令计时器失效问题求助

解决Discord.py抽奖命令的倒计时与抽奖逻辑问题

原代码核心问题

  • 阻塞的wait_for调用:原代码中await self.bot.wait_for('reaction_add')会暂停整个函数执行,必须等到有用户添加反应才会继续,导致倒计时完全无法运行
  • 剩余时间未实时更新:倒计时循环里一直使用初始计算的天/时/分/秒数值,嵌入消息的剩余时间不会变化
  • 用户收集时机错误:提前获取了用户列表,后续添加反应的用户无法被统计到抽奖池中
  • 变量名冲突:参数winners被重新赋值为空列表,导致后续抽奖循环逻辑混乱
  • 重复冗余代码:抽奖结束后的逻辑写了两次,增加维护成本

修复后的完整代码

import asyncio
import random
import datetime
import discord
from discord import app_commands

@app_commands.command(name="giveaway", description="Start a giveaway")
@app_commands.guild_only()
async def giveaway(self, interaction: discord.Interaction, winners: int, duration: str, prize: str):
    await interaction.response.defer()
    embed = discord.Embed(description="**Creating giveaway...**", color=discord.Color.blue())
    await interaction.followup.send(embed=embed)
    msg = await interaction.original_response()

    # 将时长参数转换为秒数
    pos = ["s", "m", "h", "d"]
    time_dict = {"s": 1, "m": 60, "h": 3600, "d": 3600*24}
    unit = duration[-1]
    if unit not in pos:
        await interaction.followup.send(f'请使用正确的时间单位 (s, m, h, d)')
        return
    try:
        val = int(duration[:-1])
    except ValueError:
        await interaction.followup.send(f'时间数值必须是整数!')
        return
    time_in_sec = val * time_dict[unit]

    # 计算结束时间
    end_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=time_in_sec)

    # 定义格式化剩余时间的辅助函数
    def format_remaining_time(seconds):
        days = seconds // (3600 * 24)
        hours = (seconds % (3600 * 24)) // 3600
        minutes = ((seconds % (3600 * 24)) % 3600) // 60
        secs = ((seconds % (3600 * 24)) % 3600) % 60
        
        parts = []
        if days > 0:
            parts.append(f"{days}天")
        if hours > 0:
            parts.append(f"{hours}小时")
        if minutes > 0:
            parts.append(f"{minutes}分钟")
        if secs > 0 or len(parts) == 0:
            parts.append(f"{secs}秒")
        return " ".join(parts)

    # 创建初始嵌入消息
    embed = discord.Embed(title="🎉 新抽奖开始! 🎉", color=discord.Color.blue())
    embed.description = f"**奖品:** {prize}\n**发起者:** {interaction.user.mention}\n**剩余时间:** {format_remaining_time(time_in_sec)}"
    embed.timestamp = end_time
    await msg.edit(embed=embed)
    await msg.add_reaction('\U0001f389')

    # 倒计时循环:每5秒更新一次剩余时间
    while time_in_sec > 0:
        await asyncio.sleep(5)
        time_in_sec -= 5
        # 更新嵌入消息的剩余时间
        embed.description = f"**奖品:** {prize}\n**发起者:** {interaction.user.mention}\n**剩余时间:** {format_remaining_time(time_in_sec)}"
        await msg.edit(embed=embed)

    # 倒计时结束,收集所有参与用户
    msg = await interaction.channel.fetch_message(msg.id)
    reaction = msg.reactions[0]
    users = [user async for user in reaction.users()]
    # 移除机器人自身的反应
    if self.bot.user in users:
        users.remove(self.bot.user)
    
    selected_winners = []
    # 抽取获奖者
    if len(users) >= winners:
        for _ in range(winners):
            winner = random.choice(users)
            selected_winners.append(winner.mention)
            users.remove(winner)
    elif len(users) > 0:
        # 参与人数不足,抽取所有参与者
        selected_winners = [user.mention for user in users]

    # 更新抽奖结束的嵌入消息
    embed = discord.Embed(title="🎉 抽奖结束! 🎉", color=discord.Color.blue())
    if not selected_winners:
        embed.description = f"**奖品:** {prize}\n**无人参与本次抽奖 :( **"
        await msg.edit(embed=embed)
        await interaction.channel.send("本次抽奖无人参与!")
    else:
        embed.description = f"**奖品:** {prize}\n**获奖者:** {' '.join(selected_winners)}"
        await msg.edit(embed=embed)
        await interaction.channel.send(f"恭喜!{' '.join(selected_winners)} 赢得了 {prize}!")

关键修复说明

  1. 移除阻塞的wait_for:取消等待单个反应的逻辑,改为倒计时结束后统一收集所有参与用户,确保倒计时正常运行
  2. 实时计算剩余时间:通过辅助函数每次循环重新计算并格式化剩余时间,保证嵌入消息显示准确
  3. 延迟收集用户列表:在倒计时结束后再获取反应用户列表,确保所有参与者都被统计
  4. 解决变量名冲突:将存储获奖者的变量改为selected_winners,避免和参数winners重名导致逻辑错误
  5. 简化抽奖逻辑:合并重复的抽奖代码,统一处理参与人数足够、不足和无人参与的情况
  6. 修复交互响应错误:参数验证失败时改用interaction.followup.send,避免已defer后调用response.send_message报错
  7. 优化时间格式化:用辅助函数统一处理时间格式,代码更简洁易维护

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:05:00