From 71076a39a9488e2faf2ee8943b5082e2d429f172 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Fri, 22 Nov 2019 02:07:02 +0100 Subject: [PATCH] Progress is being done --- .gitignore | 1 + pyproject.toml | 2 +- royalnet/backpack/commands/play.py | 4 +- royalnet/backpack/events/play.py | 16 ++++++- royalnet/serf/discord/__init__.py | 2 - royalnet/serf/discord/createrichembed.py | 27 ------------ .../discord/discordbard/createrichembed.py | 4 ++ royalnet/serf/discord/discordbard/dbqueue.py | 8 +++- .../serf/discord/discordbard/discordbard.py | 10 ++--- .../serf/discord/discordbard/ytdldiscord.py | 43 +++++++++++++++---- royalnet/serf/discord/discordserf.py | 2 + royalnet/utils/multilock.py | 2 +- 12 files changed, 72 insertions(+), 49 deletions(-) delete mode 100644 royalnet/serf/discord/createrichembed.py create mode 100644 royalnet/serf/discord/discordbard/createrichembed.py diff --git a/.gitignore b/.gitignore index 84e315a2..c90f79d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.egg-info .idea/misc.xml .idea/royalnet.iml +dist/ diff --git a/pyproject.toml b/pyproject.toml index c27976ef..2b5d4a24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ classifiers = [ "Development Status :: 3 - Alpha", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)" ] diff --git a/royalnet/backpack/commands/play.py b/royalnet/backpack/commands/play.py index ed4866a0..08d04cf7 100644 --- a/royalnet/backpack/commands/play.py +++ b/royalnet/backpack/commands/play.py @@ -25,4 +25,6 @@ class PlayCommand(Command): "guild_id": guild.id, "url": url, }) - await data.reply(f"✅ !") + message = f"▶️ Added to [c]{response['bard']['type']}[/c]:\n" + message += "\n".join([ytd['title'] for ytd in response['added']]) + await data.reply(message) \ No newline at end of file diff --git a/royalnet/backpack/events/play.py b/royalnet/backpack/events/play.py index bc77bae6..0a912ca4 100644 --- a/royalnet/backpack/events/play.py +++ b/royalnet/backpack/events/play.py @@ -3,6 +3,7 @@ from royalnet.commands import * from royalnet.serf.discord import DiscordSerf from royalnet.serf.discord.discordbard import YtdlDiscord, DiscordBard from royalnet.utils import asyncify +import pickle import logging log = logging.getLogger(__name__) @@ -52,4 +53,17 @@ class PlayEvent(Event): await bard.add(ytd) # Run the bard log.debug(f"Running voice for: {guild}") - await self.serf.voice_run(guild) + # FIXME: sure? + self.loop.create_task(self.serf.voice_run(guild)) + # Return the results + log.debug(f"Sending results...") + results = { + "added": [{ + "title": ytd.info.title, + "embed_pickle": pickle.dumps(ytd.embed()) + } for ytd in ytdl], + "bard": { + "type": bard.__class__.__name__, + } + } + return results diff --git a/royalnet/serf/discord/__init__.py b/royalnet/serf/discord/__init__.py index 76963ee3..8e3a8c83 100644 --- a/royalnet/serf/discord/__init__.py +++ b/royalnet/serf/discord/__init__.py @@ -2,13 +2,11 @@ It is pretty unstable, compared to the rest of the bot, but it *should* work.""" -from .createrichembed import create_rich_embed from .escape import escape from .discordserf import DiscordSerf from . import discordbard __all__ = [ - "create_rich_embed", "escape", "DiscordSerf", "discordbard", diff --git a/royalnet/serf/discord/createrichembed.py b/royalnet/serf/discord/createrichembed.py deleted file mode 100644 index 878a14ee..00000000 --- a/royalnet/serf/discord/createrichembed.py +++ /dev/null @@ -1,27 +0,0 @@ -from discord import Embed, Colour -from discord.embeds import EmptyEmbed -from royalnet.bard import YtdlInfo - - -def create_rich_embed(yi: YtdlInfo) -> Embed: - """Return this info as a :py:class:`discord.Embed`.""" - colors = { - "youtube": 0xCC0000, - "soundcloud": 0xFF5400, - "Clyp": 0x3DBEB3, - "Bandcamp": 0x1DA0C3, - } - embed = Embed(title=yi.title, - colour=Colour(colors.get(yi.extractor, 0x4F545C)), - url=yi.webpage_url if (yi.webpage_url and yi.webpage_url.startswith("http")) else EmptyEmbed) - if yi.thumbnail: - embed.set_thumbnail(url=yi.thumbnail) - if yi.uploader: - embed.set_author(name=yi.uploader, - url=yi.uploader_url if yi.uploader_url is not None else EmptyEmbed) - # embed.set_footer(text="Source: youtube-dl", icon_url="https://i.imgur.com/TSvSRYn.png") - if yi.duration: - embed.add_field(name="Duration", value=str(yi.duration), inline=True) - if yi.upload_date: - embed.add_field(name="Published on", value=yi.upload_date.strftime("%d %b %Y"), inline=True) - return embed diff --git a/royalnet/serf/discord/discordbard/createrichembed.py b/royalnet/serf/discord/discordbard/createrichembed.py new file mode 100644 index 00000000..ba56df56 --- /dev/null +++ b/royalnet/serf/discord/discordbard/createrichembed.py @@ -0,0 +1,4 @@ +from discord import Embed, Colour +from discord.embeds import EmptyEmbed +from royalnet.bard import YtdlInfo + diff --git a/royalnet/serf/discord/discordbard/dbqueue.py b/royalnet/serf/discord/discordbard/dbqueue.py index 46cdf8cb..10272d3d 100644 --- a/royalnet/serf/discord/discordbard/dbqueue.py +++ b/royalnet/serf/discord/discordbard/dbqueue.py @@ -25,8 +25,11 @@ class DBQueue(DiscordBard): except IndexError: yield None else: - async with ytd.spawn_audiosource() as fas: - yield fas + try: + async with ytd.spawn_audiosource() as fas: + yield fas + finally: + await ytd.delete_asap() async def add(self, ytd: YtdlDiscord): self.list.append(ytd) @@ -40,3 +43,4 @@ class DBQueue(DiscordBard): async def cleanup(self) -> None: for ytd in self.list: await ytd.delete_asap() + await self.stop() diff --git a/royalnet/serf/discord/discordbard/discordbard.py b/royalnet/serf/discord/discordbard/discordbard.py index 85bf3e94..e9850a56 100644 --- a/royalnet/serf/discord/discordbard/discordbard.py +++ b/royalnet/serf/discord/discordbard/discordbard.py @@ -54,8 +54,10 @@ class DiscordBard: self.now_playing = fas return fas - async def cut(self): - """Immediatly end the playback of the current file""" + async def stop(self): + """Stop the playback of the current song.""" + if self.now_playing is not None: + self.now_playing.stop() async def add(self, ytd: YtdlDiscord) -> None: """Add a new :class:`YtdlDiscord` to the :class:`DiscordBard`, if possible. @@ -93,7 +95,3 @@ class DiscordBard: UnsupportedError: If :meth:`.peek` is unsupported.""" return len(await self.peek()) - async def stop(self): - """Stop the playback of the current song.""" - if self.now_playing is not None: - self.now_playing.stop() diff --git a/royalnet/serf/discord/discordbard/ytdldiscord.py b/royalnet/serf/discord/discordbard/ytdldiscord.py index f0fc1292..f79b3e02 100644 --- a/royalnet/serf/discord/discordbard/ytdldiscord.py +++ b/royalnet/serf/discord/discordbard/ytdldiscord.py @@ -5,23 +5,24 @@ import logging from contextlib import asynccontextmanager from royalnet.utils import asyncify, MultiLock from royalnet.bard import YtdlInfo, YtdlFile - -try: - from .fileaudiosource import FileAudioSource -except ImportError: - FileAudioSource = None +from .fileaudiosource import FileAudioSource try: import ffmpeg except ImportError: ffmpeg = None +try: + import discord +except ImportError: + discord = None log = logging.getLogger(__name__) class YtdlDiscord: """A representation of a YtdlFile conversion to the :mod:`discord` PCM format.""" + def __init__(self, ytdl_file: YtdlFile): self.ytdl_file: YtdlFile = ytdl_file self.pcm_filename: typing.Optional[str] = None @@ -44,9 +45,9 @@ class YtdlDiscord: log.debug(f"Converting to PCM: {self.ytdl_file.filename}") await asyncify( ffmpeg.input(self.ytdl_file.filename) - .output(destination_filename, format="s16le", ac=2, ar="48000") - .overwrite_output() - .run + .output(destination_filename, format="s16le", ac=2, ar="48000") + .overwrite_output() + .run ) self.pcm_filename = destination_filename @@ -84,3 +85,29 @@ class YtdlDiscord: with open(self.pcm_filename, "rb") as stream: fas = FileAudioSource(stream) yield fas + + def embed(self) -> "discord.Embed": + """Return this info as a :py:class:`discord.Embed`.""" + if discord is None: + raise ImportError("'discord' extra is not installed") + colors = { + "youtube": 0xCC0000, + "soundcloud": 0xFF5400, + "Clyp": 0x3DBEB3, + "Bandcamp": 0x1DA0C3, + "PeerTube": 0xF1680D, + } + embed = discord.Embed(title=self.info.title, + colour=discord.Colour(colors.get(self.info.extractor, 0x4F545C)), + url=self.info.webpage_url if (self.info.webpage_url and self.info.webpage_url.startswith("http")) else discord.embeds.EmptyEmbed) + if self.info.thumbnail: + embed.set_thumbnail(url=self.info.thumbnail) + if self.info.uploader: + embed.set_author(name=self.info.uploader, + url=self.info.uploader_url if self.info.uploader_url is not None else discord.embeds.EmptyEmbed) + # embed.set_footer(text="Source: youtube-dl", icon_url="https://i.imgur.com/TSvSRYn.png") + if self.info.duration: + embed.add_field(name="Duration", value=str(self.info.duration), inline=True) + if self.info.upload_date: + embed.add_field(name="Published on", value=self.info.upload_date.strftime("%d %b %Y"), inline=True) + return embed diff --git a/royalnet/serf/discord/discordserf.py b/royalnet/serf/discord/discordserf.py index eaeb1186..01c4fc38 100644 --- a/royalnet/serf/discord/discordserf.py +++ b/royalnet/serf/discord/discordserf.py @@ -263,6 +263,8 @@ class DiscordSerf(Serf): if bard.now_playing is None: fas = await bard.next() + if fas is None: + return # FIXME: possible race condition here, pls check bard = self.bards.get(guild) if bard.voice_client is not None and bard.voice_client.is_connected(): diff --git a/royalnet/utils/multilock.py b/royalnet/utils/multilock.py index 57919864..0861a2fb 100644 --- a/royalnet/utils/multilock.py +++ b/royalnet/utils/multilock.py @@ -55,4 +55,4 @@ class MultiLock: def __repr__(self): return f"" + f"{'_' if self._normal_event.is_set() else 'N'}{'_' if self._exclusive_event.is_set() else 'E'}>"