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

如何让Discord机器人mute命令兼容带空格与无空格时间格式?

解决Discord机器人Mute命令支持带空格时间格式的问题

你的问题根源在于Discord.py的参数解析逻辑:timelimit: str只能捕获单个无空格字符串,输入带空格的时间(比如10 minutes)时,10会被赋值给timelimit,minutes会被归入后面的reason参数,导致时间解析失败。下面提供两种可行的解决方法:


方案1:合并参数后手动解析时间

修改命令参数定义,先接收所有后续参数,再从中分离时间部分和理由:

import re
from datetime import timedelta
import discord
from discord.ext import commands
from typing import Union

def parse_time_input(time_input: str) -> tuple[int, str]:
    # 匹配带/不带空格的时间格式,例如"10d"、"10 days"
    match = re.match(r'(\d+)\s*([a-z]+)?', time_input.lower())
    if match:
        time_value = int(match.group(1))
        # 无单位时默认用秒
        time_unit = match.group(2) if match.group(2) else "s"
        return time_value, time_unit
    else:
        return -1, ""

@bot.command(aliases=["shut", "zip"])
async def mute(ctx, member: Union[discord.Member, int], *args):
    # 处理成员对象
    if isinstance(member, int):
        member = await bot.fetch_user(member)
    elif isinstance(member, str):
        member = discord.utils.get(ctx.guild.members, name=member)
    
    # 从参数中分离时间和理由
    time_input = ""
    reason = "No reason provided"
    # 遍历参数,找到第一个能解析的时间输入
    for i, arg in enumerate(args):
        temp_input = " ".join(args[:i+1])
        time_val, _ = parse_time_input(temp_input)
        if time_val != -1:
            time_input = temp_input
            # 剩余参数拼接成理由
            if i+1 < len(args):
                reason = " ".join(args[i+1:])
            break
    # 无有效时间时用默认值28天
    if not time_input:
        time_input = "28d"
    
    time_value, time_unit = parse_time_input(time_input)
    if time_value == -1:
        await ctx.send("<:error:1131175466049470505> | Invalid time format")
        return

    unit_multipliers = {
        's': 1,
        'sec': 1, 'secs': 1, 'second': 1, 'seconds': 1,
        'm': 60,
        'min': 60, 'mins': 60, 'minute': 60, 'minutes': 60,
        'h': 3600,
        'hour': 3600, 'hours': 3600,
        'd': 86400,
        'day': 86400, 'days': 86400,
        'w': 604800,
        'week': 604800, 'weeks': 604800,
    }

    multiplier = unit_multipliers.get(time_unit, 1)
    total_seconds = time_value * multiplier
    mute_time = timedelta(seconds=total_seconds)

    if mute_time.total_seconds() > 2419200:
        await ctx.send("<:error:1131175466049470505> | Timeout limit can't be over 28 days!")
        return

    await member.edit(timed_out_until=discord.utils.utcnow() + mute_time)

    await ctx.send(f"<:check:1132263275770429471> | {member.mention} has been muted for {mute_time} by {ctx.author.mention}\nReason: {reason}")

方案2:使用自定义时间转换器

这种方式更符合Discord.py的命令规范,让框架自动处理带空格的时间输入:

import re
from datetime import timedelta
import discord
from discord.ext import commands
from typing import Union, Optional

class TimeConverter(commands.Converter):
    async def convert(self, ctx, argument):
        # 匹配带/不带空格的时间格式
        match = re.match(r'(\d+)\s*([a-z]+)?', argument.lower())
        if not match:
            raise commands.BadArgument("Invalid time format")
        
        time_value = int(match.group(1))
        time_unit = match.group(2) if match.group(2) else "s"
        
        unit_multipliers = {
            's': 1,
            'sec': 1, 'secs': 1, 'second': 1, 'seconds': 1,
            'm': 60,
            'min': 60, 'mins': 60, 'minute': 60, 'minutes': 60,
            'h': 3600,
            'hour': 3600, 'hours': 3600,
            'd': 86400,
            'day': 86400, 'days': 86400,
            'w': 604800,
            'week': 604800, 'weeks': 604800,
        }
        
        multiplier = unit_multipliers.get(time_unit, 1)
        total_seconds = time_value * multiplier
        if total_seconds > 2419200:
            raise commands.BadArgument("Timeout limit can't be over 28 days!")
        
        return timedelta(seconds=total_seconds)

@bot.command(aliases=["shut", "zip"])
async def mute(ctx, member: Union[discord.Member, int], timelimit: Optional[TimeConverter] = timedelta(days=28), *, reason: str = "No reason provided"):
    # 处理成员对象
    if isinstance(member, int):
        member = await bot.fetch_user(member)
    elif isinstance(member, str):
        member = discord.utils.get(ctx.guild.members, name=member)
    
    await member.edit(timed_out_until=discord.utils.utcnow() + timelimit)

    await ctx.send(f"<:check:1132263275770429471> | {member.mention} has been muted for {timelimit} by {ctx.author.mention}\nReason: {reason}")

方案对比

  • 方案1无需额外定义转换器,适合快速修改现有代码,兼容性强。
  • 方案2代码结构更清晰,出错时自动触发Discord.py的错误处理机制,更符合框架规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:05:57