From 002111df8ed18d74cbc8876caff4147b37aa3e26 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Sat, 25 Sep 2021 00:42:36 +0200 Subject: [PATCH] Implement queue --- src/bot.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++-------- src/yt.py | 50 ---------------------------------------------- 2 files changed, 50 insertions(+), 58 deletions(-) delete mode 100644 src/yt.py diff --git a/src/bot.py b/src/bot.py index 462cd00..66d9b19 100644 --- a/src/bot.py +++ b/src/bot.py @@ -1,26 +1,70 @@ import os import sys +import asyncio -from discord.ext import commands +import discord +from discord.ext import commands, tasks from dotenv import load_dotenv +import youtube_dl -from yt import YTDLSource from error import ErrorHandler load_dotenv() +# Suppress noise about console usage from errors +youtube_dl.utils.bug_reports_message = lambda: '' + class Music(commands.Cog): def __init__(self, bot): self.bot = bot + self.queue = asyncio.Queue() + self.queue_lock = asyncio.Lock() + self._ytdl_format_options = { + 'format': 'bestaudio/best', + 'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s', + 'restrictfilenames': True, + 'noplaylist': True, + 'nocheckcertificate': True, + 'ignoreerrors': False, + 'logtostderr': False, + 'quiet': True, + 'no_warnings': True, + 'default_search': 'auto', + 'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes + } + self._ffmpeg_options = { + 'options': '-vn' + } + self.ytdl = youtube_dl.YoutubeDL(self._ytdl_format_options) + # pylint: disable=no-member + self.handle_playback.start() + + @tasks.loop() + async def handle_playback(self): + while True: + await self.queue_lock.acquire() + ctx, url, title = await self.queue.get() + audio = discord.FFmpegPCMAudio(url, **self._ffmpeg_options) + + def after(err): + if err: + print(f"Player error: {err}") + self.queue.task_done() + self.queue_lock.release() + ctx.voice_client.play(audio, after=after) + await ctx.send(f"Now playing: {title}") @commands.command() async def play(self, ctx, *, url): async with ctx.typing(): - player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True) - ctx.voice_client.play(player, after=lambda e: print(f"Player error: {e}") if e else None) - - await ctx.send(f"Now playing: {player.title}") + data = self.ytdl.extract_info(url, download=False) + if 'entries' in data: + data = data['entries'][0] + title = data.get('title') + url = data.get('url') + await self.queue.put((ctx, url, title)) + await ctx.send(f"Queued: {title}") @commands.command() async def stop(self, ctx): @@ -33,8 +77,6 @@ class Music(commands.Cog): await ctx.author.voice.channel.connect() else: raise commands.CommandError("Author not connected to a voice channel.") - elif ctx.voice_client.is_playing(): - ctx.voice_client.stop() if __name__ == "__main__": diff --git a/src/yt.py b/src/yt.py deleted file mode 100644 index 8148bba..0000000 --- a/src/yt.py +++ /dev/null @@ -1,50 +0,0 @@ -import asyncio - -import discord -import youtube_dl - -# Suppress noise about console usage from errors -youtube_dl.utils.bug_reports_message = lambda: '' - - -ytdl_format_options = { - 'format': 'bestaudio/best', - 'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s', - 'restrictfilenames': True, - 'noplaylist': True, - 'nocheckcertificate': True, - 'ignoreerrors': False, - 'logtostderr': False, - 'quiet': True, - 'no_warnings': True, - 'default_search': 'auto', - 'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes -} - -ffmpeg_options = { - 'options': '-vn' -} - -ytdl = youtube_dl.YoutubeDL(ytdl_format_options) - - -class YTDLSource(discord.PCMVolumeTransformer): - def __init__(self, source, *, data, volume=0.5): - super().__init__(source, volume) - - self.data = data - - self.title = data.get('title') - self.url = data.get('url') - - @classmethod - async def from_url(cls, url, *, loop=None, stream=False): - loop = loop or asyncio.get_event_loop() - data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=not stream)) - - if 'entries' in data: - # take first item from a playlist - data = data['entries'][0] - - filename = data['url'] if stream else ytdl.prepare_filename(data) - return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)