diff --git a/pomice/events.py b/pomice/events.py index 0dbe0b4..49af9bd 100644 --- a/pomice/events.py +++ b/pomice/events.py @@ -6,10 +6,6 @@ from typing import Optional from typing import Tuple from typing import TYPE_CHECKING -from discord import Client -from discord import Guild -from discord.ext import commands - from .objects import Track from .pool import NodePool @@ -41,9 +37,6 @@ class PomiceEvent(ABC): name = "event" handler_args: Tuple - def dispatch(self, bot: Client) -> None: - bot.dispatch(f"pomice_{self.name}", *self.handler_args) - class TrackStartEvent(PomiceEvent): """Fired when a track has successfully started. @@ -147,7 +140,7 @@ class WebSocketClosedPayload: __slots__ = ("guild", "code", "reason", "by_remote") def __init__(self, data: dict): - self.guild: Optional[Guild] = NodePool.get_node().bot.get_guild(int(data["guildId"])) + self.guild: int = data["guildId"] self.code: int = data["code"] self.reason: str = data["code"] self.by_remote: bool = data["byRemote"] diff --git a/pomice/objects.py b/pomice/objects.py index b251906..e9997e4 100644 --- a/pomice/objects.py +++ b/pomice/objects.py @@ -2,12 +2,6 @@ from __future__ import annotations from typing import List from typing import Optional -from typing import Union - -from discord import ClientUser -from discord import Member -from discord import User -from discord.ext import commands from .enums import PlaylistType from .enums import SearchType @@ -53,12 +47,10 @@ class Track: *, track_id: str, info: dict, - ctx: Optional[commands.Context] = None, track_type: TrackType, search_type: SearchType = SearchType.ytsearch, filters: Optional[List[Filter]] = None, timestamp: Optional[float] = None, - requester: Optional[Union[Member, User, ClientUser]] = None, ): self.track_id: str = track_id self.info: dict = info @@ -89,11 +81,6 @@ class Track: self.is_seekable: bool = info.get("isSeekable", False) self.position: int = info.get("position", 0) - self.ctx: Optional[commands.Context] = ctx - self.requester: Optional[Union[Member, User, ClientUser]] = requester - if not self.requester and self.ctx: - self.requester = self.ctx.author - def __eq__(self, other: object) -> bool: if not isinstance(other, Track): return False diff --git a/pomice/player.py b/pomice/player.py index da01696..3dbc15f 100644 --- a/pomice/player.py +++ b/pomice/player.py @@ -5,15 +5,8 @@ from typing import Any from typing import Dict from typing import List from typing import Optional -from typing import TYPE_CHECKING from typing import Union -from discord import Client -from discord import Guild -from discord import VoiceChannel -from discord import VoiceProtocol -from discord.ext import commands - from . import events from .enums import SearchType from .events import PomiceEvent @@ -32,9 +25,6 @@ from .pool import Node from .pool import NodePool from pomice.utils import LavalinkVersion -if TYPE_CHECKING: - from discord.types.voice import VoiceServerUpdate - from discord.types.voice import GuildVoiceState __all__ = ("Filters", "Player") @@ -129,7 +119,7 @@ class Filters: return self._filters -class Player(VoiceProtocol): +class Player: """The base 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 @@ -156,25 +146,11 @@ class Player(VoiceProtocol): "_player_endpoint_uri", ) - def __call__(self, client: Client, channel: VoiceChannel) -> Player: - self.client = client - self.channel = channel - self._guild = channel.guild - - return self - def __init__( self, - client: Client, - channel: VoiceChannel, *, node: Optional[Node] = None, ) -> None: - self.client: Client = client - self.channel: VoiceChannel = channel - self._guild = channel.guild - - self._bot: Client = client self._node: Node = node if node else NodePool.get_node() self._current: Optional[Track] = None self._filters: Filters = Filters() @@ -260,11 +236,6 @@ class Player(VoiceProtocol): """Property which returns the node the player is connected to""" return self._node - @property - def guild(self) -> Guild: - """Property which returns the guild associated with the player""" - return self._guild - @property def volume(self) -> int: """Property which returns the players current volume""" @@ -276,16 +247,16 @@ class Player(VoiceProtocol): return self._filters @property - def bot(self) -> Client: - """Property which returns the bot associated with this player instance""" - return self._bot + def bot_id(self) -> int: + """Property which returns the bot id associated with this player instance""" + return self._node._bot_id @property def is_dead(self) -> bool: """Returns a bool representing whether the player is dead or not. A player is considered dead if it has been destroyed and removed from stored players. """ - return self.guild.id not in self._node._players + return self not in self._node._players def _adjust_end_time(self) -> Optional[str]: if self._node._version >= LavalinkVersion(3, 7, 5): @@ -321,30 +292,6 @@ class Player(VoiceProtocol): self._log.debug(f"Dispatched voice update to {state['event']['endpoint']} with data {data}") - async def on_voice_server_update(self, data: VoiceServerUpdate) -> None: - self._voice_state.update({"event": data}) - await self._dispatch_voice_update(self._voice_state) - - async def on_voice_state_update(self, data: GuildVoiceState) -> None: - self._voice_state.update({"sessionId": data.get("session_id")}) - - channel_id = data.get("channel_id") - if not channel_id: - await self.disconnect() - self._voice_state.clear() - return - - channel = self.guild.get_channel(int(channel_id)) - if not channel: - await self.disconnect() - self._voice_state.clear() - return - - if not data.get("token"): - return - - await self._dispatch_voice_update({**self._voice_state, "event": data}) - async def _dispatch_event(self, data: dict) -> None: event_type: str = data["type"] event: PomiceEvent = getattr(events, event_type)(data, self) @@ -385,7 +332,6 @@ class Player(VoiceProtocol): self, query: str, *, - ctx: Optional[commands.Context] = None, search_type: SearchType = SearchType.ytsearch, filters: Optional[List[Filter]] = None, ) -> Optional[Union[List[Track], Playlist]]: @@ -401,38 +347,22 @@ class Player(VoiceProtocol): You may also pass in a List of filters to be applied to your track once it plays. """ - return await self._node.get_tracks(query, ctx=ctx, search_type=search_type, filters=filters) + return await self._node.get_tracks(query, search_type=search_type, filters=filters) - async def build_track(self, identifier: str, ctx: Optional[commands.Context] = None) -> Track: + async def build_track(self, identifier: str) -> Track: """ Builds a track using a valid track identifier - - You can also pass in a discord.py Context object to get a - Context object on the track it builds. """ - return await self._node.build_track(identifier, ctx=ctx) + return await self._node.build_track(identifier) - async def get_recommendations( - self, *, track: Track, ctx: Optional[commands.Context] = None - ) -> Optional[Union[List[Track], Playlist]]: + async def get_recommendations(self, *, track: Track) -> Optional[Union[List[Track], Playlist]]: """ Gets recommendations from either YouTube or Spotify. You can pass in a discord.py Context object to get a Context object on all tracks that get recommended. """ - return await self._node.get_recommendations(track=track, ctx=ctx) - - async def connect( - self, *, timeout: float, reconnect: bool, self_deaf: bool = False, self_mute: bool = False - ) -> None: - await self.guild.change_voice_state( - channel=self.channel, - self_deaf=self_deaf, - self_mute=self_mute, - ) - self._node._players[self.guild.id] = self - self._is_connected = True + return await self._node.get_recommendations(track=track) async def stop(self) -> None: """Stops the currently playing track.""" @@ -446,15 +376,6 @@ class Player(VoiceProtocol): self._log.debug(f"Player has been stopped.") - async def disconnect(self, *, force: bool = False) -> None: - """Disconnects the player from voice.""" - try: - await self.guild.change_voice_state(channel=None) - finally: - self.cleanup() - self._is_connected = False - self.channel = None # type: ignore - async def destroy(self) -> None: """Disconnects and destroys the player, and runs internal cleanup.""" try: @@ -486,9 +407,7 @@ class Player(VoiceProtocol): if not track.isrc: # We have to bare raise here because theres no other way to skip this block feasibly raise - search = ( - await self._node.get_tracks(f"{track._search_type}:{track.isrc}", ctx=track.ctx) - )[ + search = (await self._node.get_tracks(f"{track._search_type}:{track.isrc}"))[ 0 ] # type: ignore except Exception: @@ -497,7 +416,6 @@ class Player(VoiceProtocol): search = ( await self._node.get_tracks( f"{track._search_type}:{track.title} - {track.author}", - ctx=track.ctx, ) )[ 0 @@ -612,15 +530,6 @@ class Player(VoiceProtocol): self._log.debug(f"Player volume has been adjusted to {volume}") return self._volume - async def move_to(self, channel: VoiceChannel) -> None: - """Moves the player to a new voice channel.""" - - await self.guild.change_voice_state(channel=channel) - - self.channel = channel - - await self._dispatch_voice_update() - async def add_filter(self, _filter: Filter, fast_apply: bool = False) -> Filters: """Adds a filter to the player. Takes a pomice.Filter object. This will only work if you are using a version of Lavalink that supports filters. diff --git a/pomice/pool.py b/pomice/pool.py index 107c64b..3f63a3f 100644 --- a/pomice/pool.py +++ b/pomice/pool.py @@ -18,9 +18,6 @@ from urllib.parse import quote import aiohttp import orjson as json -from discord import Client -from discord.ext import commands -from discord.utils import MISSING from websockets import client from websockets import exceptions from websockets import typing as wstype @@ -106,7 +103,7 @@ class Node: self, *, pool: Type[NodePool], - bot: commands.Bot, + bot_id: int, host: str, port: int, password: str, @@ -127,7 +124,7 @@ class Node: if not isinstance(port, int): raise TypeError("Port must be an integer") - self._bot: commands.Bot = bot + self._bot_id: int = bot_id self._host: str = host self._port: int = port self._pool: Type[NodePool] = pool @@ -208,9 +205,9 @@ class Node: return self._players @property - def bot(self) -> Client: - """Property which returns the discord.py client linked to this node""" - return self._bot + def bot_id(self) -> int: + """Property which returns the bot id linked to this node""" + return self._bot_id @property def player_count(self) -> int: @@ -535,7 +532,7 @@ class Node: f"Successfully disconnected from node {self._identifier} and closed all sessions. Took {end - start:.3f}s", ) - async def build_track(self, identifier: str, ctx: Optional[commands.Context] = None) -> Track: + async def build_track(self, identifier: str = None) -> Track: """ Builds a track using a valid track identifier @@ -550,7 +547,6 @@ class Node: ) return Track( track_id=identifier, - ctx=ctx, info=data, track_type=TrackType(data["sourceName"]), ) @@ -559,7 +555,6 @@ class Node: self, query: str, *, - ctx: Optional[commands.Context] = None, search_type: SearchType = SearchType.ytsearch, filters: Optional[List[Filter]] = None, ) -> Optional[Union[Playlist, List[Track]]]: @@ -593,7 +588,6 @@ class Node: return [ Track( track_id=apple_music_results.id, - ctx=ctx, track_type=TrackType.APPLE_MUSIC, search_type=search_type, filters=filters, @@ -615,7 +609,6 @@ class Node: tracks = [ Track( track_id=track.id, - ctx=ctx, track_type=TrackType.APPLE_MUSIC, search_type=search_type, filters=filters, @@ -660,7 +653,6 @@ class Node: return [ Track( track_id=spotify_results.id, - ctx=ctx, track_type=TrackType.SPOTIFY, search_type=search_type, filters=filters, @@ -682,7 +674,6 @@ class Node: tracks = [ Track( track_id=track.id, - ctx=ctx, track_type=TrackType.SPOTIFY, search_type=search_type, filters=filters, @@ -734,7 +725,6 @@ class Node: "position": info["position"], "identifier": info["identifier"], }, - ctx=ctx, track_type=TrackType.HTTP, filters=filters, ), @@ -762,7 +752,6 @@ class Node: "position": info["position"], "identifier": info["identifier"], }, - ctx=ctx, track_type=TrackType.LOCAL, filters=filters, ), @@ -804,7 +793,6 @@ class Node: Track( track_id=track["encoded"], info=track["info"], - ctx=ctx, track_type=TrackType(track["info"]["sourceName"]), ) for track in data["tracks"] @@ -822,7 +810,6 @@ class Node: Track( track_id=track["encoded"], info=track["info"], - ctx=ctx, track_type=TrackType(track["info"]["sourceName"]), filters=filters, timestamp=timestamp, @@ -835,9 +822,7 @@ class Node: "There was an error while trying to load this track.", ) - async def get_recommendations( - self, *, track: Track, ctx: Optional[commands.Context] = None - ) -> Optional[Union[List[Track], Playlist]]: + async def get_recommendations(self, *, track: Track) -> Optional[Union[List[Track], Playlist]]: """ Gets recommendations from either YouTube or Spotify. The track that is passed in must be either from @@ -850,7 +835,6 @@ class Node: tracks = [ Track( track_id=track.id, - ctx=ctx, track_type=TrackType.SPOTIFY, info={ "title": track.name, @@ -873,7 +857,6 @@ class Node: elif track.track_type == TrackType.YOUTUBE: return await self.get_tracks( query=f"ytsearch:https://www.youtube.com/watch?v={track.identifier}&list=RD{track.identifier}", - ctx=ctx, ) else: @@ -956,7 +939,7 @@ class NodePool: async def create_node( cls, *, - bot: commands.Bot, + bot_id: int, host: str, port: int, password: str, @@ -984,7 +967,7 @@ class NodePool: node = Node( pool=cls, - bot=bot, + bot_id=bot_id, host=host, port=port, password=password,