updated player.py

add the `__call__` to the `Player` class itself, I had to change the `_dispatch_event` you can change it personally after merging it if you want, but trust me, all those if statements, 😥
This commit is contained in:
Crussader 2021-10-20 21:47:32 +04:00 committed by GitHub
parent 91e8922435
commit 9c241f76a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 102 additions and 113 deletions

View File

@ -1,7 +1,6 @@
import time import time
from typing import Any, Dict, Optional, Type, Union from typing import Any, Dict, Optional, Type
import discord
from discord import Client, Guild, VoiceChannel, VoiceProtocol from discord import Client, Guild, VoiceChannel, VoiceProtocol
from discord.ext import commands from discord.ext import commands
@ -12,23 +11,25 @@ from .exceptions import TrackInvalidPosition
from .filters import Filter from .filters import Filter
from .pool import Node, NodePool from .pool import Node, NodePool
from .objects import Track from .objects import Track
from .utils import MISSING from .utils import ClientType, MISSING
class BasePlayer(VoiceProtocol): class Player(VoiceProtocol):
"""Base Player Class For Pomice This Class Has to Be Inherited if your are Building """The Default Basic Player class for Pomice.
your own Player Class, Unless you know what you are doing. In order to initiate a player, you must pass it in as a cls when you connect to a channel.
i.e: ```py
await ctx.author.voice.channel.connect(cls=pomice.Player)
```
""" """
def __call__(self, client: discord.Client, channel: VoiceChannel): def __call__(self, client: ClientType, channel: VoiceChannel):
self.client: discord.Client = client self.client: ClientType = client
self.channel : VoiceChannel = channel self.channel : VoiceChannel = channel
return self return self
def __init__(self, client : ClientType = MISSING, channel : VoiceChannel = MISSING, **kwargs):
def __init__(self, client : Type[Client] = MISSING, channel: VoiceChannel = MISSING): # self.client
self.client = client
self._bot = client self._bot = client
self.channel = channel self.channel = channel
self._guild : Guild = channel.guild self._guild : Guild = channel.guild
@ -43,9 +44,17 @@ class BasePlayer(VoiceProtocol):
self._last_update = 0 self._last_update = 0
self._voice_state = {} self._voice_state = {}
self._extra = kwargs or {} # all custom attributes you want to store
def __repr__(self) -> str: self._current: Track = None
return f"<{self.__class__.__name__}(bot={self._bot}, guildId={self._guild.id})>" self._filter: Filter = None
def __repr__(self):
return (
f"<Pomice.player bot={self.bot} guildId={self.guild.id} "
f"is_connected={self.is_connected} is_playing={self.is_playing}>"
)
@property @property
def is_connected(self) -> bool: def is_connected(self) -> bool:
@ -77,104 +86,6 @@ class BasePlayer(VoiceProtocol):
"""Property which returns the bot associated with this player instance""" """Property which returns the bot associated with this player instance"""
return self._bot return self._bot
async def _update_state(self, data: dict):
state: dict = data.get("state")
self._last_update = time.time() * 1000
self._is_connected = state.get("connected")
self._last_position = state.get("position")
async def _dispatch_voice_update(self, voice_data: Dict[str, Any]):
if {"sessionId", "event"} != self._voice_state.keys():
return
await self._node.send(
op="voiceUpdate",
guildId=str(self.guild.id),
**voice_data
)
async def on_voice_server_update(self, data: dict):
self._voice_state.update({"event": data})
await self._dispatch_voice_update(self._voice_state)
async def on_voice_state_update(self, data: dict):
self._voice_state.update({"sessionId": data.get("session_id")})
if not (channel_id := data.get("channel_id")):
self.channel = None
self._voice_state.clear()
return
self.channel = self.guild.get_channel(int(channel_id))
if not data.get('token'):
return
await self._dispatch_voice_update({**self._voice_state, "event": data})
async def _dispatch_event(self, data: dict):
event_type = data.get("type")
if _track := data.get("track", None):
track = await self._node.build_track(_track)
_events = {
"TrackStartEvent" : (self, track),
"TrackEndEvent" : (self, track, data.get("reason", None)),
"TrackExceptionEvent" : (self, track, data.get("error", None)),
"TrackStuckEvent" : (self, track, data.get("thresholdMs", None)),
"WebSocketOpenEvent": (data.get("target", None), data.get("ssrc", None)),
"WebSocketClosedEvent" : (self._guild, data.get("reason", None), data.get("code", None))
}
if (event := getattr(events, event_type, None)) and (args := _events.get(event_type, None)):
self.bot.dispatch(f"pomice_{event.name}", event, *args)
async def connect(self, *, timeout: float, reconnect: bool):
await self.guild.change_voice_state(channel=self.channel)
self._node._players[self.guild.id] = self
self._is_connected = True
async def stop(self):
"""Stops a currently playing track."""
self._current = None
await self._node.send(op="stop", guildId=str(self.guild.id))
async def disconnect(self, *, force: bool = False):
await self.stop()
await self.guild.change_voice_state(channel=None)
self.cleanup()
self.channel = None
self._is_connected = False
del self._node._players[self.guild.id]
async def destroy(self):
"""Disconnects a player and destroys the player instance."""
await self.disconnect()
await self._node.send(op="destroy", guildId=str(self.guild.id))
class Player(BasePlayer):
"""The Default Basic Player class for Pomice.
In order to initiate a player, you must pass it in as a cls when you connect to a channel.
i.e: ```py
await ctx.author.voice.channel.connect(cls=pomice.Player)
```
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._current: Track = None
self._filter: Filter = None
def __repr__(self):
return (
f"<Pomice.player bot={self.bot} guildId={self.guild.id} "
f"is_connected={self.is_connected} is_playing={self.is_playing}>"
)
@property @property
def position(self) -> float: def position(self) -> float:
"""Property which returns the player's position in a track in milliseconds""" """Property which returns the player's position in a track in milliseconds"""
@ -256,6 +167,29 @@ class Player(BasePlayer):
self._current = track self._current = track
return self._current return self._current
async def connect(self, *, timeout: float, reconnect: bool):
await self.guild.change_voice_state(channel=self.channel)
self._node._players[self.guild.id] = self
self._is_connected = True
async def stop(self):
"""Stops a currently playing track."""
self._current = None
await self._node.send(op="stop", guildId=str(self.guild.id))
async def disconnect(self, *, force: bool = False):
await self.stop()
await self.guild.change_voice_state(channel=None)
self.cleanup()
self.channel = None
self._is_connected = False
del self._node._players[self.guild.id]
async def destroy(self):
"""Disconnects a player and destroys the player instance."""
await self.disconnect()
await self._node.send(op="destroy", guildId=str(self.guild.id))
async def seek(self, position: float) -> float: async def seek(self, position: float) -> float:
"""Seeks to a position in the currently playing track milliseconds""" """Seeks to a position in the currently playing track milliseconds"""
@ -287,3 +221,58 @@ class Player(BasePlayer):
await self.seek(self.position) await self.seek(self.position)
self._filter = filter self._filter = filter
return filter return filter
async def _update_state(self, data: dict):
state: dict = data.get("state")
self._last_update = time.time() * 1000
self._is_connected = state.get("connected")
self._last_position = state.get("position")
async def _dispatch_voice_update(self, voice_data: Dict[str, Any]):
if {"sessionId", "event"} != self._voice_state.keys():
return
await self._node.send(
op="voiceUpdate",
guildId=str(self.guild.id),
**voice_data
)
async def on_voice_server_update(self, data: dict):
self._voice_state.update({"event": data})
await self._dispatch_voice_update(self._voice_state)
async def on_voice_state_update(self, data: dict):
self._voice_state.update({"sessionId": data.get("session_id")})
if not (channel_id := data.get("channel_id")):
self.channel = None
self._voice_state.clear()
return
self.channel = self.guild.get_channel(int(channel_id))
if not data.get('token'):
return
await self._dispatch_voice_update({**self._voice_state, "event": data})
async def _dispatch_event(self, data: dict):
# this feels far more cleaner and does the same thing
# pls, seeing all that if statements makes my eyes bleed
event_type = data.get("type")
if _track := data.get("track", None):
track = await self._node.build_track(_track)
_events = {
"TrackStartEvent" : (self, track),
"TrackEndEvent" : (self, track, data.get("reason", None)),
"TrackExceptionEvent" : (self, track, data.get("error", None)),
"TrackStuckEvent" : (self, track, data.get("thresholdMs", None)),
"WebSocketOpenEvent": (data.get("target", None), data.get("ssrc", None)),
"WebSocketClosedEvent" : (self._guild, data.get("reason", None), data.get("code", None))
}
if (event := getattr(events, event_type, None)) and (args := _events.get(event_type, None)):
self.bot.dispatch(f"pomice_{event.name}", event, *args)