如何让discord.py音乐机器人在闲置指定时长后退出语音频道?
实现Discord音乐机器人闲置自动退出语音频道
我来帮你搞定这个闲置自动退出的功能!核心思路是跟踪播放状态,在播放停止后启动一个延迟任务,超时后检查是否仍处于闲置状态,若是则断开语音连接。下面是具体的实现方案和代码示例:
关键思路拆解
- 维护一个字典记录每个语音客户端的闲置延迟任务,避免重复触发退出逻辑
- 在开始播放时,取消当前语音频道的闲置任务(此时机器人处于工作状态,不算闲置)
- 在播放结束(包括主动调用
voice.stop()或歌曲自然播放完毕)时,启动闲置计时器 - 计时器超时后,检查语音客户端是否仍连接且无播放,满足条件则自动退出频道
完整代码示例
首先确保你已导入必要模块:
import discord from discord.ext import commands import asyncio
然后在机器人类中添加核心逻辑:
class MusicBot(commands.Bot): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 存储每个语音客户端对应的闲置任务:{VoiceClient: asyncio.Task} self.idle_tasks = {} async def start_idle_timer(self, voice_client: discord.VoiceClient, timeout: int = 300): """启动闲置计时器,超时后退出语音频道""" await asyncio.sleep(timeout) # 双重检查:确保仍连接且无播放 if voice_client.is_connected() and not voice_client.is_playing(): await voice_client.disconnect() # 清理已完成的任务记录 if voice_client in self.idle_tasks: del self.idle_tasks[voice_client] def cancel_idle_timer(self, voice_client: discord.VoiceClient): """取消当前语音频道的闲置计时器""" if voice_client in self.idle_tasks: self.idle_tasks[voice_client].cancel() del self.idle_tasks[voice_client] # 初始化机器人(记得开启必要的Intents) bot = MusicBot(command_prefix="!", intents=discord.Intents.all()) @bot.command() async def play(ctx, *, url: str): # 省略音频获取逻辑,假设你已处理好audio变量 audio = ... # 替换为你的discord.FFmpegPCMAudio实例 # 获取或连接用户所在语音频道 voice_client = ctx.voice_client if not voice_client: voice_client = await ctx.author.voice.channel.connect() # 开始播放前先取消闲置计时器 bot.cancel_idle_timer(voice_client) # 定义播放结束后的回调函数 def after_playing(error): if error: print(f"播放出错: {error}") # 播放结束后启动闲置计时器(注意线程安全) asyncio.run_coroutine_threadsafe( bot.start_idle_timer(voice_client), bot.loop ) # 启动播放并绑定回调 voice_client.play(discord.FFmpegPCMAudio(audio), after=after_playing) await ctx.send(f"开始播放: {url}") @bot.command() async def stop(ctx): voice_client = ctx.voice_client if voice_client and voice_client.is_playing(): voice_client.stop() # 主动停止播放后重置闲置计时器 bot.cancel_idle_timer(voice_client) await bot.start_idle_timer(voice_client) await ctx.send("已停止播放,将在5分钟后退出频道") # 运行机器人 bot.run("你的机器人Token")
重要细节说明
- 线程安全处理:
after回调是在FFmpeg的子线程中执行的,必须用asyncio.run_coroutine_threadsafe将协程提交到机器人的主事件循环,避免线程冲突。 - 任务管理:通过
self.idle_tasks字典跟踪任务,确保在开始新播放或手动停止时,能正确取消旧任务,防止重复触发退出逻辑。 - 超时自定义:
start_idle_timer的timeout参数默认是300秒(5分钟),你可以根据需求修改这个数值。 - 边界校验:退出前双重检查
is_connected()和is_playing(),避免在播放重新启动或已断开连接的情况下执行无效操作。
这样你的机器人就会在停止播放后,闲置指定时长自动退出语音频道啦!
内容的提问来源于stack exchange,提问作者Sathvik K S
相关产品推荐
相关产品推荐

