From 7bbf7f334bfb2eec8b1f8b3122e26aeaf30b56e9 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Mon, 18 Nov 2019 19:43:55 +0100 Subject: [PATCH] Commit things --- docs_source/index.rst | 1 + docs_source/randomdiscoveries.rst | 13 ++++++++ royalnet/bard/__init__.py | 12 ++++++++ royalnet/bard/discordbard.py | 17 ++++++++--- royalnet/bard/errors.py | 2 +- royalnet/bard/implementations/__init__.py | 7 +++++ royalnet/bard/implementations/dbqueue.py | 37 +++++++++++++++++++++++ royalnet/bard/implementations/dbstack.py | 37 +++++++++++++++++++++++ royalnet/bard/ytdldiscord.py | 7 ++--- 9 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 docs_source/randomdiscoveries.rst create mode 100644 royalnet/bard/implementations/__init__.py create mode 100644 royalnet/bard/implementations/dbqueue.py create mode 100644 royalnet/bard/implementations/dbstack.py diff --git a/docs_source/index.rst b/docs_source/index.rst index f9861311..e2605ae8 100644 --- a/docs_source/index.rst +++ b/docs_source/index.rst @@ -6,6 +6,7 @@ Welcome to the documentation of Royalnet! .. toctree:: :maxdepth: 5 + randomdiscoveries apireference diff --git a/docs_source/randomdiscoveries.rst b/docs_source/randomdiscoveries.rst new file mode 100644 index 00000000..c73eedc5 --- /dev/null +++ b/docs_source/randomdiscoveries.rst @@ -0,0 +1,13 @@ +Random discoveries +================== + +Here are some things that were found out while developing the bot. + +Discord websocket undocumented error codes +------------------------------------------ + +====== =================== + Code Reason +====== =================== +1006 Heartbeat stopped +====== =================== diff --git a/royalnet/bard/__init__.py b/royalnet/bard/__init__.py index f082d483..ad74da52 100644 --- a/royalnet/bard/__init__.py +++ b/royalnet/bard/__init__.py @@ -1,7 +1,16 @@ from .ytdlinfo import YtdlInfo from .ytdlfile import YtdlFile from .ytdlmp3 import YtdlMp3 +from .ytdldiscord import YtdlDiscord from .errors import * +from .discordbard import DiscordBard +from . import implementations + +try: + from .fileaudiosource import FileAudioSource +except ImportError: + FileAudioSource = None + __all__ = [ "YtdlInfo", @@ -11,4 +20,7 @@ __all__ = [ "YtdlError", "NotFoundError", "MultipleFilesError", + "FileAudioSource", + "implementations", + "DiscordBard", ] diff --git a/royalnet/bard/discordbard.py b/royalnet/bard/discordbard.py index 548f29e0..fb8c9d77 100644 --- a/royalnet/bard/discordbard.py +++ b/royalnet/bard/discordbard.py @@ -18,10 +18,10 @@ class DiscordBard: """The :class:`YtdlDiscord` that's currently being played.""" self.generator: \ - AsyncGenerator[FileAudioSource, Tuple[Tuple[Any, ...], Dict[str, Any]]] = self._generate_generator() + AsyncGenerator[FileAudioSource, Tuple[Tuple[Any, ...], Dict[str, Any]]] = self._generator() """The AsyncGenerator responsible for deciding the next song that should be played.""" - async def _generate_generator(self) -> AsyncGenerator[FileAudioSource, Tuple[Tuple[Any, ...], Dict[str, Any]]]: + async def _generator(self) -> AsyncGenerator[Optional[FileAudioSource], Tuple[Tuple[Any, ...], Dict[str, Any]]]: """Create an async generator that returns the next source to be played; it can take a args+kwargs tuple in input to optionally select a different source. @@ -46,7 +46,7 @@ class DiscordBard: self.now_playing = fas return fas - async def add(self, ytd: YtdlDiscord): + async def add(self, ytd: YtdlDiscord) -> None: """Add a new :class:`YtdlDiscord` to the :class:`DiscordBard`, if possible. Raises: @@ -62,7 +62,7 @@ class DiscordBard: """ raise UnsupportedError() - async def remove(self, ytd: YtdlDiscord): + async def remove(self, ytd: YtdlDiscord) -> None: """Remove a :class:`YtdlDiscord` from the :class:`DiscordBard`, if possible. Raises: @@ -70,7 +70,14 @@ class DiscordBard: """ raise UnsupportedError() - async def cleanup(self): + async def cleanup(self) -> None: """Enqueue the deletion of all :class:`YtdlDiscord` contained in the :class:`DiscordBard`, and return only once all deletions are complete.""" raise NotImplementedError() + + async def length(self) -> int: + """Return the length of the :class:`DiscordBard`. + + Raises: + UnsupportedError: If :meth:`.peek` is unsupported.""" + return len(await self.peek()) diff --git a/royalnet/bard/errors.py b/royalnet/bard/errors.py index 60253203..88b89e72 100644 --- a/royalnet/bard/errors.py +++ b/royalnet/bard/errors.py @@ -15,4 +15,4 @@ class MultipleFilesError(YtdlError): class UnsupportedError(BardError): - """The method you tried to call on a :class:`DiscordBard` is not supported on that particular Bard.""" \ No newline at end of file + """The method you tried to call on a :class:`DiscordBard` is not supported on that particular Bard.""" diff --git a/royalnet/bard/implementations/__init__.py b/royalnet/bard/implementations/__init__.py new file mode 100644 index 00000000..918b26ed --- /dev/null +++ b/royalnet/bard/implementations/__init__.py @@ -0,0 +1,7 @@ +from .dbstack import DBStack +from .dbqueue import DBQueue + +__all__ = [ + "DBStack", + "DBQueue", +] diff --git a/royalnet/bard/implementations/dbqueue.py b/royalnet/bard/implementations/dbqueue.py new file mode 100644 index 00000000..5bd18532 --- /dev/null +++ b/royalnet/bard/implementations/dbqueue.py @@ -0,0 +1,37 @@ +from ..fileaudiosource import FileAudioSource +from ..discordbard import DiscordBard +from ..ytdldiscord import YtdlDiscord +from typing import List, AsyncGenerator, Tuple, Any, Dict, Optional + + +class DBQueue(DiscordBard): + """A First-In-First-Out music queue. + + It is what was once called a ``playlist``.""" + def __init__(self): + super().__init__() + self.list: List[YtdlDiscord] = [] + + async def _generator(self) -> AsyncGenerator[Optional[FileAudioSource], Tuple[Tuple[Any, ...], Dict[str, Any]]]: + yield + while True: + try: + ytd = self.list.pop(0) + except IndexError: + yield None + else: + async with ytd.spawn_audiosource() as fas: + yield fas + + async def add(self, ytd: YtdlDiscord): + self.list.append(ytd) + + async def peek(self) -> List[YtdlDiscord]: + return self.list + + async def remove(self, ytd: YtdlDiscord): + self.list.remove(ytd) + + async def cleanup(self) -> None: + for ytd in self.list: + await ytd.delete_asap() diff --git a/royalnet/bard/implementations/dbstack.py b/royalnet/bard/implementations/dbstack.py new file mode 100644 index 00000000..426c4be1 --- /dev/null +++ b/royalnet/bard/implementations/dbstack.py @@ -0,0 +1,37 @@ +from ..fileaudiosource import FileAudioSource +from ..discordbard import DiscordBard +from ..ytdldiscord import YtdlDiscord +from typing import List, AsyncGenerator, Tuple, Any, Dict, Optional + + +class DBStack(DiscordBard): + """A First-In-Last-Out music queue. + + Not really sure if it is going to be useful...""" + def __init__(self): + super().__init__() + self.list: List[YtdlDiscord] = [] + + async def _generator(self) -> AsyncGenerator[Optional[FileAudioSource], Tuple[Tuple[Any, ...], Dict[str, Any]]]: + yield + while True: + try: + ytd = self.list.pop() + except IndexError: + yield None + else: + async with ytd.spawn_audiosource() as fas: + yield fas + + async def add(self, ytd: YtdlDiscord): + self.list.append(ytd) + + async def peek(self) -> List[YtdlDiscord]: + return self.list + + async def remove(self, ytd: YtdlDiscord): + self.list.remove(ytd) + + async def cleanup(self) -> None: + for ytd in self.list: + await ytd.delete_asap() diff --git a/royalnet/bard/ytdldiscord.py b/royalnet/bard/ytdldiscord.py index 8f3896cf..dc28e02f 100644 --- a/royalnet/bard/ytdldiscord.py +++ b/royalnet/bard/ytdldiscord.py @@ -7,10 +7,9 @@ from .ytdlinfo import YtdlInfo from .ytdlfile import YtdlFile try: - import discord - from royalnet.serf.discord import FileAudioSource + from royalnet.bard.fileaudiosource import FileAudioSource except ImportError: - discord = None + FileAudioSource = None try: import ffmpeg @@ -71,7 +70,7 @@ class YtdlDiscord: @asynccontextmanager async def spawn_audiosource(self): - if discord is None: + if FileAudioSource is None: raise ImportError("'discord' extra is not installed") await self.convert_to_pcm() with open(self.pcm_filename, "rb") as stream: