Update player.py

- This has an implementation of Automatic Node Swtiching
Issues:
     - Takes time in playing after swtiching nodes
     - The Volume becomes low and muffled after the song ends and another song is played.
This commit is contained in:
Crussader 2021-10-26 21:11:37 +04:00 committed by GitHub
parent 4d4587b179
commit 5651ac4fb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 88 additions and 43 deletions

View File

@ -2,7 +2,8 @@ import time
from typing import ( from typing import (
Any, Any,
Dict, Dict,
Optional Optional,
Union
) )
from discord import ( from discord import (
@ -10,7 +11,7 @@ from discord import (
VoiceChannel, VoiceChannel,
VoiceProtocol VoiceProtocol
) )
from discord.ext import commands from discord.ext import commands, tasks
from . import events from . import events
from .enums import SearchType from .enums import SearchType
@ -19,7 +20,7 @@ from .exceptions import TrackInvalidPosition
from .filters import Filter from .filters import Filter
from .objects import Track from .objects import Track
from .pool import Node, NodePool from .pool import Node, NodePool
from .utils import ClientType from .utils import ClientType, if_toggled
class Player(VoiceProtocol): class Player(VoiceProtocol):
@ -29,7 +30,6 @@ class Player(VoiceProtocol):
await ctx.author.voice.channel.connect(cls=pomice.Player) await ctx.author.voice.channel.connect(cls=pomice.Player)
``` ```
""" """
def __call__(self, client: ClientType, channel: VoiceChannel): def __call__(self, client: ClientType, channel: VoiceChannel):
self.client: ClientType = client self.client: ClientType = client
self.channel : VoiceChannel = channel self.channel : VoiceChannel = channel
@ -37,6 +37,8 @@ class Player(VoiceProtocol):
return self return self
def __init__(self, client: ClientType = None, channel: VoiceChannel = None, **kwargs): def __init__(self, client: ClientType = None, channel: VoiceChannel = None, **kwargs):
# super().__init__(client=client, channel=channel)
self.client = client self.client = client
self._bot = client self._bot = client
self.channel = channel self.channel = channel
@ -57,12 +59,35 @@ class Player(VoiceProtocol):
self._voice_state = {} self._voice_state = {}
self._extra = kwargs or {} self._extra = kwargs or {}
def __repr__(self): self.check.start()
def __repr__(self) -> str:
return ( return (
f"<Pomice.player bot={self.bot} guildId={self.guild.id} " f"<Pomice.player bot={self.bot} guildId={self.guild.id} "
f"is_connected={self.is_connected} is_playing={self.is_playing}>" f"is_connected={self.is_connected} is_playing={self.is_playing}>"
) )
def __getitem__(self, key) -> Union[Any, None]:
return self._extra.get(key, None)
def __setitem__(self, key, value) -> None:
self._extra[key] = value
def __delitem__(self, key) -> None:
try:
del self._extra[key]
except KeyError:
pass
def get(self, key) -> Union[Any, None]:
return self.__getitem__(key)
def put(self, key, value) -> None:
self.__setitem__(key, value)
def remove(self, key) -> None:
self.__delitem__(key)
@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"""
@ -150,7 +175,7 @@ class Player(VoiceProtocol):
self._voice_state.update({"sessionId": data.get("session_id")}) self._voice_state.update({"sessionId": data.get("session_id")})
if not (channel_id := data.get("channel_id")): if not (channel_id := data.get("channel_id")):
await self.disconnect() self.channel = None
self._voice_state.clear() self._voice_state.clear()
return return
@ -199,13 +224,10 @@ class Player(VoiceProtocol):
async def disconnect(self, *, force: bool = False): async def disconnect(self, *, force: bool = False):
await self.stop() await self.stop()
try:
await self.guild.change_voice_state(channel=None) await self.guild.change_voice_state(channel=None)
finally:
self._is_connected = False
self.cleanup() self.cleanup()
self.channel = None self.channel = None
self._is_connected = False
del self._node._players[self.guild.id] del self._node._players[self.guild.id]
async def destroy(self): async def destroy(self):
@ -213,14 +235,7 @@ class Player(VoiceProtocol):
await self.disconnect() await self.disconnect()
await self._node.send(op="destroy", guildId=str(self.guild.id)) await self._node.send(op="destroy", guildId=str(self.guild.id))
async def play( async def play(self, track: Track, *, start_position: int = 0) -> Track:
self,
track: Track,
*,
start: int = 0,
end: int = 0,
ignore_if_playing: bool = False
) -> Track:
"""Plays a track. If a Spotify track is passed in, it will be handled accordingly.""" """Plays a track. If a Spotify track is passed in, it will be handled accordingly."""
if track.spotify: if track.spotify:
search: Track = (await self._node.get_tracks( search: Track = (await self._node.get_tracks(
@ -229,27 +244,23 @@ class Player(VoiceProtocol):
))[0] ))[0]
track.original = search track.original = search
data = { await self._node.send(
"op": "play", op="play",
"guildId": str(self.guild.id), guildId=str(self.guild.id),
"track": search.track_id, track=search.track_id,
"startTime": str(start), startTime=start_position,
"noReplace": ignore_if_playing endTime=search.length,
} noReplace=False
)
else: else:
data = { await self._node.send(
"op": "play", op="play",
"guildId": str(self.guild.id), guildId=str(self.guild.id),
"track": track.track_id, track=track.track_id,
"startTime": str(start), startTime=start_position,
"noReplace": ignore_if_playing endTime=track.length,
} noReplace=False
)
if end > 0:
data["endtime"] = str(end)
await self._node.send(**data)
self._current = track self._current = track
return self._current return self._current
@ -284,3 +295,37 @@ class Player(VoiceProtocol):
await self.seek(self.position) await self.seek(self.position)
self._filter = filter self._filter = filter
return filter return filter
@if_toggled('auto_switch_nodes')
async def change_node(self, node: Node = None) -> None:
if node := (node or NodePool.get_node()):
del self._node.players[self.guild.id]
self._node = node
self._node.players[self.guild.id] = self
if self._voice_state:
self._ending_track = self._current
await self._dispatch_voice_update(self._voice_state)
if self._current:
await self._node.send(
op='play',
guildId=str(self.guild.id),
track=self.current.track_id,
startTime=self.position,
endTime=self.current.length,
noReplace = False)
self._current = self.current
self._last_update = time.time() * 1000
if self.is_paused:
await self._node.send(op='pause', guildId=str(self.guild.id), pause=self.is_paused)
await self._node.send(op="volume", guildId = str(self.guild.id), volume=self.volume)
@tasks.loop(seconds=5)
async def check(self):
if not self.node.is_connected:
print(self.node.is_connected)