Discord.py 临时禁言指令适配无空格时间输入的实现方法
tempmute指令参数兼容优化实现
问题根源
原代码的参数定义为time: int, d,框架做参数解析时,碰到用户输入的10m会直接把整段字符串塞给time参数尝试转换为整数,转换失败就直接抛出BadArgument报错,根本走不到后续的参数解析流程,自然无法识别紧凑的无空格时间输入格式。
优化思路
不再强制把时间数值和时间单位拆成两个独立入参——直接收集成员参数之后、原因参数之前的所有输入内容,在指令内部统一做拆分解析,这样不管用户是把数字和单位连起来输(10m),还是按老习惯用空格分开输(10 m),都能正常解析,也不用强迫老用户改变原有使用习惯。
具体改动点
- 把原来拆分的
time: int, d两个入参换成可变位置参数*time_parts,把所有时间相关的输入片段统一收集 - 新增正则格式校验逻辑,将收集到的片段拼接后,直接匹配「数字+单字符时间单位」的规则
- 用字典存储时间单位和对应秒数的映射,删掉原来重复编写的多分支if判断
- 移除原代码里多余的循环查找Muted角色的逻辑——之前已经通过工具方法获取/创建好该角色,没必要再遍历全服务器的角色列表重复检索
优化后的完整代码
import asyncio import re import discord from discord.ext import commands # 预定义时间单位对应的秒数映射 UNIT_SECONDS_MAP = { "s": 1, "m": 60, "h": 60 * 60, "d": 60 * 60 * 24 } @bot.command() async def tempmute(ctx, member: discord.Member, *time_parts: str, reason: str = None): guild = ctx.guild mutedRole = discord.utils.get(guild.roles, name="Muted") # 不存在Muted角色时自动创建 if not mutedRole: mutedRole = await guild.create_role(name="Muted") # 为所有频道配置禁言角色的权限限制 for channel in guild.channels: await channel.set_permissions(mutedRole, speak=False, send_messages=False) # 解析时间参数:同时兼容 "10m" 和 "10 m" 两种输入格式 raw_time_str = "".join(time_parts).lower().strip() time_match = re.match(r"^(\d+)([smhd])$", raw_time_str) # 格式不合法时直接给用户友好提示 if not time_match: await ctx.send("时间格式不合法,请输入类似 `10s`/`5m`/`2h`/`3d` 的格式,示例:`!tempmute @用户 10m 违规发言`") return time_value = int(time_match.group(1)) time_unit = time_match.group(2) total_sleep_seconds = time_value * UNIT_SECONDS_MAP[time_unit] display_time = f"{time_value}{time_unit}" # 执行禁言操作 await member.add_roles(mutedRole) embed = discord.Embed( title="TempMuted!", description=f"{member.mention} 已被临时禁言", colour=discord.Colour.red() ) embed.add_field(name="禁言原因", value=reason if reason else "未指定原因", inline=False) embed.add_field(name="禁言时长", value=display_time, inline=False) await ctx.send(embed=embed) # 等待禁言时长结束后自动解除 await asyncio.sleep(total_sleep_seconds) await member.remove_roles(mutedRole) unmute_embed = discord.Embed( title="临时禁言到期", description=f"{member.mention} 已自动解除禁言", colour=discord.Colour.light_gray() ) await ctx.send(embed=unmute_embed)
实际兼容效果
改完后两种输入方式都可以正常使用:
- 新支持的紧凑写法:
!tempmute @违规用户 10m 恶意刷屏 - 完全兼容的旧拆分写法:
!tempmute @违规用户 10 m 恶意刷屏
如果用户输入了非法的时间格式(比如10x、abc这类无意义内容),指令会直接返回明确的格式提示,不会把框架的原始报错暴露给用户。
内容的提问来源于stack exchange,提问作者Jack Thorn
相关产品推荐
相关产品推荐

