mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-23 19:44:20 +00:00
MOAR MOAR MOAR
This commit is contained in:
parent
bf70ceafe7
commit
2b24d8cd09
8 changed files with 97 additions and 10 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
.idea/misc.xml
|
.idea/misc.xml
|
||||||
.idea/royalnet.iml
|
.idea/royalnet.iml
|
||||||
dist/
|
dist/
|
||||||
|
**/__pycache__/
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/royalnet.iml" filepath="$PROJECT_DIR$/.idea/royalnet.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/royalnet.iml" filepath="$PROJECT_DIR$/.idea/royalnet.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/../royalpack/.idea/royalpack.iml" filepath="$PROJECT_DIR$/../royalpack/.idea/royalpack.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -3,11 +3,13 @@
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/royalnet" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/royalnet" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/dist" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/royalnet.egg-info" />
|
<excludeFolder url="file://$MODULE_DIR$/royalnet.egg-info" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.8 (royalnet-1MWM6-kd-py3.8)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.8 (royalnet-1MWM6-kd-py3.8)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="module" module-name="royalpack" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||||
|
|
|
@ -2,5 +2,7 @@
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/docs_source/royalpack" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/../royalpack" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -1,7 +1,7 @@
|
||||||
from .ytdlinfo import YtdlInfo
|
from .ytdlinfo import YtdlInfo
|
||||||
from .ytdlfile import YtdlFile
|
from .ytdlfile import YtdlFile
|
||||||
from .ytdlmp3 import YtdlMp3
|
from .ytdlmp3 import YtdlMp3
|
||||||
from .errors import *
|
from .ytdldiscord import YtdlDiscord
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .fileaudiosource import FileAudioSource
|
from .fileaudiosource import FileAudioSource
|
||||||
|
@ -13,10 +13,6 @@ __all__ = [
|
||||||
"YtdlInfo",
|
"YtdlInfo",
|
||||||
"YtdlFile",
|
"YtdlFile",
|
||||||
"YtdlMp3",
|
"YtdlMp3",
|
||||||
"BardError",
|
"YtdlDiscord",
|
||||||
"YtdlError",
|
|
||||||
"NotFoundError",
|
|
||||||
"MultipleFilesError",
|
|
||||||
"FileAudioSource",
|
"FileAudioSource",
|
||||||
"UnsupportedError",
|
|
||||||
]
|
]
|
||||||
|
|
38
royalnet/serf/discord/playable.py
Normal file
38
royalnet/serf/discord/playable.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
from typing import Optional, AsyncGenerator, Tuple, Any, Dict
|
||||||
|
try:
|
||||||
|
import discord
|
||||||
|
except ImportError:
|
||||||
|
discord = None
|
||||||
|
|
||||||
|
|
||||||
|
class Playable:
|
||||||
|
"""An abstract class representing something that can be played back in a :class:`VoicePlayer`."""
|
||||||
|
def __init__(self):
|
||||||
|
self.generator: \
|
||||||
|
Optional[AsyncGenerator[Optional["discord.AudioSource"], Tuple[Tuple[Any, ...], Dict[str, Any]]]] = None
|
||||||
|
|
||||||
|
async def next(self, *args, **kwargs) -> Optional["discord.AudioSource"]:
|
||||||
|
"""Get the next :class:`discord.AudioSource` that should be played.
|
||||||
|
|
||||||
|
Called when the :class:`Playable` is first attached to a :class:`VoicePlayer` and when a
|
||||||
|
:class:`discord.AudioSource` stops playing.
|
||||||
|
|
||||||
|
Args and kwargs can be used to pass data to the generator.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:const:`None` if there is nothing available to play, otherwise the :class:`discord.AudioSource` that should
|
||||||
|
be played.
|
||||||
|
"""
|
||||||
|
return await self.generator.asend((args, kwargs,))
|
||||||
|
|
||||||
|
async def _generator(self) \
|
||||||
|
-> AsyncGenerator[Optional["discord.AudioSource"], 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.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
For `weird Python reasons
|
||||||
|
<https://www.python.org/dev/peps/pep-0525/#support-for-asynchronous-iteration-protocol>`, the generator
|
||||||
|
should ``yield`` once before doing anything else."""
|
||||||
|
yield
|
||||||
|
raise NotImplementedError()
|
37
royalnet/serf/discord/playableytdqueue.py
Normal file
37
royalnet/serf/discord/playableytdqueue.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
from typing import Optional, List, AsyncGenerator, Tuple, Any, Dict
|
||||||
|
from royalnet.bard import YtdlDiscord
|
||||||
|
from .playable import Playable
|
||||||
|
try:
|
||||||
|
import discord
|
||||||
|
except ImportError:
|
||||||
|
discord = None
|
||||||
|
|
||||||
|
|
||||||
|
class PlayableYTDQueue(Playable):
|
||||||
|
"""A queue of :class:`YtdlDiscord` to be played in sequence."""
|
||||||
|
def __init__(self, start_with: Optional[List[YtdlDiscord]] = None):
|
||||||
|
super().__init__()
|
||||||
|
self.contents: List[YtdlDiscord] = []
|
||||||
|
if start_with is not None:
|
||||||
|
self.contents = [*self.contents, *start_with]
|
||||||
|
|
||||||
|
async def _generator(self) \
|
||||||
|
-> AsyncGenerator[Optional["discord.AudioSource"], Tuple[Tuple[Any, ...], Dict[str, Any]]]:
|
||||||
|
yield
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# Try to get the first YtdlDiscord of the queue
|
||||||
|
ytd: YtdlDiscord = self.contents.pop(0)
|
||||||
|
except IndexError:
|
||||||
|
# If there isn't anything, yield None
|
||||||
|
yield None
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
# Create a FileAudioSource from the YtdlDiscord
|
||||||
|
# If the file hasn't been fetched / downloaded / converted yet, it will do so before yielding
|
||||||
|
async with ytd.spawn_audiosource() as fas:
|
||||||
|
# Yield the resulting AudioSource
|
||||||
|
yield fas
|
||||||
|
finally:
|
||||||
|
# Delete the YtdlDiscord file
|
||||||
|
await ytd.delete_asap()
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from .errors import *
|
from .errors import *
|
||||||
|
from .playable import Playable
|
||||||
try:
|
try:
|
||||||
import discord
|
import discord
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -10,7 +11,7 @@ except ImportError:
|
||||||
class VoicePlayer:
|
class VoicePlayer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.voice_client: Optional["discord.VoiceClient"] = None
|
self.voice_client: Optional["discord.VoiceClient"] = None
|
||||||
...
|
self.playing: Optional[Playable] = None
|
||||||
|
|
||||||
async def connect(self, channel: "discord.VoiceChannel") -> "discord.VoiceClient":
|
async def connect(self, channel: "discord.VoiceChannel") -> "discord.VoiceClient":
|
||||||
"""Connect the :class:`VoicePlayer` to a :class:`discord.VoiceChannel`, creating a :class:`discord.VoiceClient`
|
"""Connect the :class:`VoicePlayer` to a :class:`discord.VoiceChannel`, creating a :class:`discord.VoiceClient`
|
||||||
|
@ -29,7 +30,7 @@ class VoicePlayer:
|
||||||
GuildAlreadyConnectedError:
|
GuildAlreadyConnectedError:
|
||||||
OpusNotLoadedError:
|
OpusNotLoadedError:
|
||||||
"""
|
"""
|
||||||
if self.voice_client is not None:
|
if self.voice_client is not None and self.voice_client.is_connected():
|
||||||
raise PlayerAlreadyConnectedError()
|
raise PlayerAlreadyConnectedError()
|
||||||
try:
|
try:
|
||||||
self.voice_client = await channel.connect()
|
self.voice_client = await channel.connect()
|
||||||
|
@ -48,7 +49,7 @@ class VoicePlayer:
|
||||||
Raises:
|
Raises:
|
||||||
PlayerNotConnectedError:
|
PlayerNotConnectedError:
|
||||||
"""
|
"""
|
||||||
if self.voice_client is None:
|
if self.voice_client is None or not self.voice_client.is_connected():
|
||||||
raise PlayerNotConnectedError()
|
raise PlayerNotConnectedError()
|
||||||
await self.voice_client.disconnect(force=True)
|
await self.voice_client.disconnect(force=True)
|
||||||
self.voice_client = None
|
self.voice_client = None
|
||||||
|
@ -58,5 +59,14 @@ class VoicePlayer:
|
||||||
|
|
||||||
This requires the :class:`VoicePlayer` to already be connected, and for the passed :class:`discord.VoiceChannel`
|
This requires the :class:`VoicePlayer` to already be connected, and for the passed :class:`discord.VoiceChannel`
|
||||||
to be in the same :class:`discord.Guild` as """
|
to be in the same :class:`discord.Guild` as """
|
||||||
|
if self.voice_client is None or not self.voice_client.is_connected():
|
||||||
|
raise PlayerNotConnectedError()
|
||||||
|
await self.voice_client.move_to(channel)
|
||||||
|
|
||||||
...
|
async def start(self):
|
||||||
|
"""Start playing music on the :class:`discord.VoiceClient`."""
|
||||||
|
if self.voice_client is None or not self.voice_client.is_connected():
|
||||||
|
raise PlayerNotConnectedError()
|
||||||
|
|
||||||
|
def _playback_ended(self, error=None):
|
||||||
|
...
|
||||||
|
|
Loading…
Reference in a new issue