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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 13:39:40