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

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

重要细节说明

  1. 线程安全处理:after回调是在FFmpeg的子线程中执行的,必须用asyncio.run_coroutine_threadsafe将协程提交到机器人的主事件循环,避免线程冲突。
  2. 任务管理:通过self.idle_tasks字典跟踪任务,确保在开始新播放或手动停止时,能正确取消旧任务,防止重复触发退出逻辑。
  3. 超时自定义:start_idle_timer的timeout参数默认是300秒(5分钟),你可以根据需求修改这个数值。
  4. 边界校验:退出前双重检查is_connected()和is_playing(),避免在播放重新启动或已断开连接的情况下执行无效操作。

这样你的机器人就会在停止播放后,闲置指定时长自动退出语音频道啦!

内容的提问来源于stack exchange,提问作者Sathvik K S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:42:36