python - 如何在我的 Discord Music Bot 中实现队列系统?
问题描述
@client.command()
async def play(ctx, *, url = None):
if ctx.author.voice is None:
msg = await ctx.send("You are not in a voice channel.")
await msg.delete(delay = 3)
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)
search_keyword = url
if not ("youtube.com/watch?" in search_keyword):
search_keyword = search_keyword.replace(" ", "+")
html = urllib.request.urlopen(f"https://www.youtube.com/results?search_query={search_keyword}")
video_ids = re.findall(r"watch\?v=(\S{11})", html.read().decode())
url = str(f"https://www.youtube.com/watch?v={video_ids[0]}")
ctx.voice_client.stop()
FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
YDL_OPTIONS = {'format': 'bestaudio', 'noplaylist':'True'}
vc = ctx.voice_client
with youtube_dl.YoutubeDL(YDL_OPTIONS) as ydl:
info = ydl.extract_info(url, download=False)
title = info.get('title', None)
length = info['duration']
url2 = info["formats"][0]["url"]
source = await discord. FFmpegOpusAudio.from_probe(url2, **FFMPEG_OPTIONS)
vc.play(source)
embed = discord.Embed(title = "Currently Playing", colour = discord.Colour.blue())
embed.add_field(name = "Song", value = title, inline = False)
embed.add_field(name = "Length", value = str(datetime.timedelta(seconds = length)), inline = False)
embed.add_field(name = "Link", value = url, inline = False)
msg = await ctx.send(embed=embed)
await msg.add_reaction("\u23F8")
await msg.add_reaction("\u25B6")
await msg.add_reaction("\u23F9")
while True:
try:
reaction, user = await client.wait_for("reaction_add", check=lambda reaction, user: user.id == ctx.author.id and reaction.message.id == msg.id and reaction.emoji in ["\u23F8", "\u25B6", "\u23F9"], timeout = length)
except asyncio.TimeoutError:
return await msg.clear_reactions()
async def process():
if reaction.emoji == "\u23F8":
await msg.remove_reaction(reaction.emoji, ctx.author)
ctx.voice_client.pause()
elif reaction.emoji == "\u25B6":
await msg.remove_reaction(reaction.emoji, ctx.author)
ctx.voice_client.resume()
elif reaction.emoji == "\u23F9":
await msg.remove_reaction(reaction.emoji, ctx.author)
ctx.voice_client.stop()
asyncio.create_task(process())
这是我的播放命令的代码。现在,如果在播放歌曲时调用该命令,则该歌曲停止并开始新请求 ctx.voice_client.stop()
的歌曲,这是因为在下载歌曲之前。但是,我正在尝试实现一个队列系统,如果在播放另一首歌曲时调用该命令,它将被添加到队列中,并且队列中的歌曲将在当前歌曲结束后立即播放。目前我对如何做到这一点的想法是替换ctx.voice_client.stop()
使用 if 语句检查机器人的状态,如果它当前正在播放,或者将其附加到包含当前队列的全局列表变量或播放歌曲。但是我对如何让它一个接一个地播放队列并实现一个跳过命令一无所知。另一个复杂的部分是将跳过命令实现为类似于我如何实现暂停和播放命令的反应。我现在不知道我的想法是否可行,因此感谢您的任何意见。
解决方案
首先你需要在你的命令之外创建一个空队列
queues = {}
以及检查队列中是否有一首歌的功能,它将播放该歌曲
#check queue
queues = {}
def check_queue(ctx, id):
if queues[id] !={}:
voice = ctx.guild.voice_client
source = queues[id].pop(0)
voice.play(source, after=lambda x=0: check_queue(ctx, ctx.message.guild.id))
并在播放命令中创建一个函数以将下一首歌曲添加到队列中,如果一首歌曲已经在播放,并添加检查队列函数
if voice.is_playing():
guild_id = ctx.message.guild.id
if guild_id in queues:
queues[guild_id].append(source)
else:
queues[guild_id] = [source]
else:
vc.play(source, after=lambda x=0: check_queue(ctx, ctx.message.guild.id))
如果您需要更多帮助,可以在此处查看我的代码需要帮助 Discord 机器人队列
推荐阅读
- python - 在另一个脚本中使用 argparse 运行 python 脚本
- swift - 基于 JSExport 的类未在 JSContext 中发布
- android - Android 的 Firebase Firestore 和 Places Api 之间的冲突
- c# - TFS 构建代理上出现错误 CS0579,但在本地运行构建时成功
- jsf - 通过对每一行的删除按钮删除 P:DATATABLE 行
- python - 减去数据框中的两个值
- wordpress - 多种帖子类型,但仅为一种设置偏移量
- sql-server - 使用警卫停止递归 CTE
- sql - JPA - 在没有 IN 参数的情况下调用 Oracle 函数
- excel - 从文件夹中获取文件名从第二个文件开始,而不是从第一个文件开始