如何让Python编写的Discord机器人在音乐队列清空后10分钟退出语音频道
实现Discord音乐机器人队列清空后自动断开语音频道的方案
1. 新增定时器属性
首先在类的初始化中添加一个属性,用来存储自动断开的定时器任务,方便后续取消或重置:
def __init__(self, bot): self.bot = bot # All the music related stuff self.is_playing = False self.is_paused = False # Two-dimensional array containing [song, channel] self.music_queue = [] self.YDL_OPTIONS = {'format': 'bestaudio', 'noplaylist': 'True'} self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'} self.vc = None # 新增:存储自动断开的异步任务 self.disconnect_timer = None
2. 编写自动断开的核心逻辑
添加一个异步函数,负责等待10分钟后检查队列状态并执行断开操作:
import asyncio async def auto_disconnect(self, ctx): # 等待10分钟(600秒) await asyncio.sleep(600) # 双重验证:队列空 + 机器人仍在语音频道 if not self.music_queue and self.vc and self.vc.is_connected(): self.is_playing = False self.is_paused = False await self.vc.disconnect() await ctx.send("队列已空,10分钟无操作,自动断开语音频道") # 重置定时器标记 self.disconnect_timer = None
3. 修改播放逻辑关联定时器
在你的play_next函数(播放完当前歌曲后调用的下一首播放逻辑)中,添加队列空时启动定时器、队列非空时取消定时器的逻辑:
async def play_next(self, ctx): if self.music_queue: # 有新歌曲要播放,取消之前的自动断开定时器 if self.disconnect_timer: self.disconnect_timer.cancel() self.disconnect_timer = None self.is_playing = True # 获取并播放下一首歌曲(保留你原有的播放代码) song_url = self.music_queue[0][0] source = await discord.FFmpegOpusAudio.from_probe(song_url, **self.FFMPEG_OPTIONS) # 注意:after回调需要用run_coroutine_threadsafe提交到事件循环 self.vc.play(source, after=lambda e: asyncio.run_coroutine_threadsafe(self.play_next(ctx), self.bot.loop)) self.music_queue.pop(0) else: # 队列为空,启动自动断开定时器(避免重复启动) if not self.disconnect_timer: self.disconnect_timer = asyncio.create_task(self.auto_disconnect(ctx)) self.is_playing = False
4. 在添加歌曲命令中取消定时器
当用户新增歌曲到空队列时,需要取消正在运行的定时器,避免机器人误断开:
@commands.command(name="add", help="添加歌曲到队列") async def add(self, ctx, *args): song_name = " ".join(args) # 保留你原有的歌曲搜索、获取URL的逻辑 # ... self.music_queue.append([song_url, ctx.channel]) if not self.is_playing: # 取消定时器(如果存在)并开始播放 if self.disconnect_timer: self.disconnect_timer.cancel() self.disconnect_timer = None await self.play(ctx) # 调用你初始化语音连接并播放的函数 else: await ctx.send(f"已添加歌曲到队列:{song_name}")
5. 更新leave命令逻辑
在手动断开命令中,也要取消定时器,避免后续出现无效操作:
@commands.command(name="leave", aliases=["disconnect", "l", "d"], help="Kick the bot from VC") async def dc(self, ctx): self.is_playing = False self.is_paused = False # 取消自动断开定时器 if self.disconnect_timer: self.disconnect_timer.cancel() self.disconnect_timer = None await self.vc.disconnect()
注意事项
- 如果你的机器人支持多服务器,当前的全局队列/定时器结构会冲突,需要改成按服务器ID(
guild.id)存储的字典结构,比如self.music_queues = {}、self.disconnect_timers = {}。 - 确保
vc.play的after回调使用asyncio.run_coroutine_threadsafe,因为该回调运行在同步线程中,必须将异步任务提交到机器人的事件循环。
内容的提问来源于stack exchange,提问作者Major Tom
相关产品推荐
相关产品推荐

