Как добавить список треков
Делаю музыкального бота, столкнулся с проблемой добавления музыки в список и последующем воспроизведении. Чтобы можно было во время проигрывания видео в боте ещё раз прописать команду play и поставить в очередь видео, которое воспроизведётся после окончания предыдущего. Мой код:
YDL_OPTIONS = {'format': 'worstaudio/best', 'noplaylist': 'False', 'simulate': 'True',
'preferredquality': '192', 'preferredcodec': 'mp3', 'key': 'FFmpegExtractAudio'}
FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
client = commands.Bot( command_prefix ='!', intents = intents)
#Музыка
@client.command()
async def join(ctx):
await ctx.message.author.voice.channel.connect()
@client.command()
async def leave(ctx):
await ctx.guild.voice_client.disconnect()
@client.command()
async def play(ctx, *, arg):
if not ctx.message.author.voice:
await ctx.send('Ты не в голосовом канале')
return
try:
voice = discord.utils.get(client.voice_clients, guild=ctx.guild)
with YoutubeDL(YDL_OPTIONS) as ydl:
if 'https://' in arg:
info = ydl.extract_info(arg, download=False)
else:
info = ydl.extract_info(f"ytsearch:{arg}", download=False)['entries'][0]
url = info['formats'][0]['url']
voice.play(discord.FFmpegPCMAudio(executable ="ffmpeg\\ffmpeg.exe", source=url, **FFMPEG_OPTIONS))
info = str(info)
await ctx.send('https://www.youtube.com/watch?v='+info[8:19])
except:
await ctx.message.author.voice.channel.connect()
voice = discord.utils.get(client.voice_clients, guild=ctx.guild)
with YoutubeDL(YDL_OPTIONS) as ydl:
if 'https://' in arg:
info = ydl.extract_info(arg, download=False)
else:
info = ydl.extract_info(f"ytsearch:{arg}", download=False)['entries'][0]
url = info['formats'][0]['url']
voice.play(discord.FFmpegPCMAudio(executable="ffmpeg\\ffmpeg.exe", source=url, **FFMPEG_OPTIONS))
info = str(info)
await ctx.send('https://www.youtube.com/watch?v=' + info[8:19])
Ответы (1 шт):
Я использовал костыль. Просто цикл while в параллельном потоке, который крутится пока играет музыка, а когда трек заканчивается - заканчивается while и запускается новый трек.
from threading import Thread
class Player(Thread): # Создание потока
def __init__(self, ctx, queue):
super(Player, self).__init__()
self.daemon = True
self.active = True
self.ctx = ctx
self.queue = queue
self.YDL_OPTIONS = {'format': 'worstaudio/best', 'noplaylist': 'False', 'simulate': 'True','preferredquality': '192', 'preferredcodec': 'mp3', 'key': 'FFmpegExtractAudio'}
self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
def run(self):
while self.active and self.queue:
arg = self.queue.pop(0) # Взять элемент из очереди, обработать его и запустить музыку
with YoutubeDL(self.YDL_OPTIONS) as ydl: # Поиск
if 'https://' in arg:
info = ydl.extract_info(arg, download=False)
else:
info = ydl.extract_info(f"ytsearch:{arg}", download=False)['entries'][0]
url = str(info['formats'][0]['url'])
voice = discord.utils.get(client.voice_clients, guild=self.ctx.guild)
voice.play(discord.FFmpegPCMAudio(executable="ffmpeg\\ffmpeg.exe", source=url, **self.FFMPEG_OPTIONS))
while (connection.is_playing() or connection.is_paused()) and connection.is_connected(): # Ждём пока музыка кончится
if not self.active:
return
time.sleep(0.5)
await self.ctx.send('https://www.youtube.com/watch?v=' + info[8:19])
def close(self):
self.active = False
Но этот поток должен быть у каждого сервера свой, так что его нужно записывать
players = {}
И затем им можно управлять
player = players.get(ctx.guild)
if not player or not player.is_alive():
player = Player(ctx, server_queue)
player.start()
players[ctx.guild] = player
else:
await ctx.send("Музыка уже играет!")
player.ctx = ctx
Очередь можно хранить так же в словаре
queue = {}
for guild in self.bot.guilds:
queue[guild] = []
server_queue = queue.get(ctx.guild)
server_queue.append(arg)
Это то, что использовал я. Может есть решение лучше, но я о нём не знаю ¯\_(ツ)_/¯