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

discord.py音乐机器人实现歌曲队列、跳过命令及双渠道搜歌方案

完整修改实现代码
  • 队列逻辑直接集成至.play命令:无播放任务时直接播放歌曲,已有播放任务时自动将新歌曲加入队列
  • 新增播放完成自动回调逻辑,当前歌曲播放结束后自动读取队列下一首播放
  • 新增.skip命令,调用后直接跳过当前播放歌曲
  • 自动兼容两种输入方式:输入为http/https开头的链接时直接解析,否则作为 YouTube 搜索关键词检索歌曲
  • 修复原代码每次调用.play都会强行终止当前播放的问题
import discord
from discord.ext import commands
import youtube_dl
import asyncio

class Music(commands.Cog):
    def __init__(self, client):
        self.client = client
        self.music_queue = []
        self.is_playing = False
        self.ffmpeg_options = {
            'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
            'options': '-vn'
        }
        self.ydl_options = {
            'format': 'bestaudio',
            'noplaylist': 'True'
        }

    async def play_next(self, ctx):
        if len(self.music_queue) > 0:
            self.is_playing = True
            song_info = self.music_queue.pop(0)
            url2 = song_info['formats'][0]['url']
            source = await discord.FFmpegOpusAudio.from_probe(url2, **self.ffmpeg_options)
            ctx.voice_client.play(source, after=lambda e: asyncio.run_coroutine_threadsafe(self.play_next(ctx), self.client.loop))
            await ctx.send(f"现在播放:{song_info['title']}")
        else:
            self.is_playing = False
            await ctx.send("队列已空,播放结束")

    @commands.command()
    async def disconnect(self, ctx):
        self.music_queue.clear()
        self.is_playing = False
        await ctx.voice_client.disconnect()

    @commands.command()
    async def play(self, ctx, *, query):
        # 检查用户是否在语音频道
        if ctx.author.voice is None:
            await ctx.send("你当前不在语音频道中!")
            return
        voice_channel = ctx.author.voice.channel
        # 连接语音频道
        if ctx.voice_client is None:
            await voice_channel.connect()
        else:
            await ctx.voice_client.move_to(voice_channel)
        
        # 解析歌曲信息
        with youtube_dl.YoutubeDL(self.ydl_options) as ydl:
            # 判断是链接还是搜索关键词
            if query.startswith("http"):
                info = ydl.extract_info(query, download=False)
            else:
                info = ydl.extract_info(f"ytsearch:{query}", download=False)['entries'][0]
        
        # 判断是否正在播放
        if not self.is_playing:
            self.is_playing = True
            url2 = info['formats'][0]['url']
            source = await discord.FFmpegOpusAudio.from_probe(url2, **self.ffmpeg_options)
            ctx.voice_client.play(source, after=lambda e: asyncio.run_coroutine_threadsafe(self.play_next(ctx), self.client.loop))
            await ctx.send(f"现在播放:{info['title']}")
        else:
            self.music_queue.append(info)
            await ctx.send(f"已加入队列:{info['title']},当前队列长度:{len(self.music_queue)}")

    @commands.command()
    async def skip(self, ctx):
        if ctx.voice_client.is_playing():
            ctx.voice_client.stop()
            await ctx.send("已跳过当前歌曲")
        else:
            await ctx.send("当前没有正在播放的歌曲")

    @commands.command()
    async def pause(self, ctx):
        if ctx.voice_client.is_playing():
            ctx.voice_client.pause()
            embed = discord.Embed(
                title="",
                description="***已暂停播放***",
                color=0x2f3136
            )
            await ctx.send(embed=embed)
        else:
            await ctx.send("当前没有正在播放的歌曲")

    @commands.command()
    async def resume(self, ctx):
        if ctx.voice_client.is_paused():
            ctx.voice_client.resume()
            embed = discord.Embed(
                title="",
                description="***已恢复播放***",
                color=0x2f3136
            )
            await ctx.send(embed=embed)
        else:
            await ctx.send("当前没有暂停的播放任务")

def setup(client):
    client.add_cog(Music(client))

内容的提问来源于stack exchange,提问作者Witalik Zarscikov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 16:30:02