Skip to content

Commit f63e985

Browse files
authored
Merge pull request #6 from interactions-py/unstable
Merge unstable to main
2 parents 9d0fc4e + b3a3247 commit f63e985

File tree

7 files changed

+103
-111
lines changed

7 files changed

+103
-111
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,7 @@ dmypy.json
129129
.pyre/
130130

131131
.idea
132+
133+
logs/*
134+
Lavalink.jar
135+

interactions/ext/lavalink/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from interactions.ext.version import Version, VersionAuthor
33

44
__all__ = ["version", "base"]
5-
__version__ = "0.1.0"
5+
__version__ = "0.1.1"
66

77
version = Version(
88
version=__version__, author=VersionAuthor(name="Damego", email="[email protected]")

interactions/ext/lavalink/client.py

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from lavalink import Client as LavalinkClient
55

6-
from interactions import Client, LibraryException, Snowflake
6+
from interactions import Client, Snowflake
77

88
from .models import VoiceState
99
from .player import Player
@@ -16,8 +16,8 @@ class VoiceClient(Client):
1616
def __init__(self, token: str, **kwargs):
1717
super().__init__(token, **kwargs)
1818

19-
self._websocket = VoiceWebSocketClient(token, self._intents)
20-
self.lavalink_client = LavalinkClient(int(self.me.id), player=Player)
19+
self._websocket = VoiceWebSocketClient(self, token, self._intents)
20+
self.lavalink_client: LavalinkClient = None
2121

2222
self._websocket._dispatch.register(
2323
self.__raw_voice_state_update, "on_raw_voice_state_update"
@@ -26,8 +26,13 @@ def __init__(self, token: str, **kwargs):
2626
self.__raw_voice_server_update, "on_raw_voice_server_update"
2727
)
2828

29-
self._websocket._http._bot_var = self
29+
async def _login(self) -> None:
3030
self._http._bot_var = self
31+
self.lavalink_client = LavalinkClient(int(self.me.id), player=Player)
32+
33+
self.__register_lavalink_listeners()
34+
35+
await super()._login()
3136

3237
async def __raw_voice_state_update(self, data: dict):
3338
lavalink_data = {"t": "VOICE_STATE_UPDATE", "d": data}
@@ -47,42 +52,36 @@ async def connect(
4752
"""
4853
Connects to voice channel and creates player.
4954
50-
:param guild_id: The guild id to connect.
51-
:type guild_id: Union[Snowflake, int, str]
52-
:param channel_id: The channel id to connect.
53-
:type channel_id: Union[Snowflake, int, str]
54-
:param self_deaf: Whether bot is self deafened
55-
:type self_deaf: bool
56-
:param self_mute: Whether bot is self muted
57-
:type self_mute: bool
55+
:param Union[Snowflake, int, str] guild_id: The guild id to connect.
56+
:param Union[Snowflake, int, str] channel_id: The channel id to connect.
57+
:param bool self_deaf: Whether bot is self deafened
58+
:param bool self_mute: Whether bot is self muted
5859
:return: Created guild player.
5960
:rtype: Player
6061
"""
61-
# Discord will fire INVALID_SESSION if channel_id is None
6262
if guild_id is None:
63-
raise LibraryException(message="Missed requirement argument: guild_id")
63+
raise TypeError("guild_id cannot be NoneType")
6464
if channel_id is None:
65-
raise LibraryException(message="Missed requirement argument: channel_id")
65+
raise TypeError("channel_id cannot be NoneType for connect method")
6666

67-
await self._websocket.connect_voice_channel(guild_id, channel_id, self_deaf, self_mute)
67+
await self._websocket.update_voice_state(guild_id, channel_id, self_deaf, self_mute)
6868
player = self.lavalink_client.player_manager.get(int(guild_id))
6969
if player is None:
7070
player = self.lavalink_client.player_manager.create(int(guild_id))
7171
return player
7272

7373
async def disconnect(self, guild_id: Union[Snowflake, int]):
7474
if guild_id is None:
75-
raise LibraryException(message="Missed requirement argument: guild_id")
75+
raise TypeError("guild_id cannot be NoneType")
7676

77-
await self._websocket.disconnect_voice_channel(int(guild_id))
77+
await self._websocket.update_voice_state(int(guild_id))
7878
await self.lavalink_client.player_manager.destroy(int(guild_id))
7979

8080
def get_player(self, guild_id: Union[Snowflake, int]) -> Player:
8181
"""
8282
Returns current player in guild.
8383
84-
:param guild_id: The guild id
85-
:type guild_id: Union[Snowflake, int]
84+
:param Union[Snowflake, int] guild_id: The guild id
8685
:return: Guild player
8786
:rtype: Player
8887
"""
@@ -97,8 +96,7 @@ def get_user_voice_state(self, user_id: Union[Snowflake, int]) -> Optional[Voice
9796
"""
9897
Returns user voice state.
9998
100-
:param user_id: The user id
101-
:type user_id: Union[Snowflake, int]
99+
:param Union[Snowflake, int] user_id: The user id
102100
:return: Founded user voice state else nothing
103101
:rtype: Optional[VoiceState]
104102
"""
@@ -110,8 +108,7 @@ def get_guild_voice_states(self, guild_id: Union[Snowflake, int]) -> Optional[Li
110108
"""
111109
Returns guild voice states.
112110
113-
:param guild_id: The channel id
114-
:type guild_id: Union[Snowflake, int]
111+
:param Union[Snowflake, int] guild_id: The channel id
115112
:return: Founded channel voice states else nothing
116113
:rtype: Optional[List[VoiceState]]
117114
"""
@@ -129,8 +126,7 @@ def get_channel_voice_states(
129126
"""
130127
Returns channel voice states.
131128
132-
:param channel_id: The channel id
133-
:type channel_id: Union[Snowflake, int]
129+
:param Union[Snowflake, int] channel_id: The channel id
134130
:return: Founded channel voice states else nothing
135131
:rtype: Optional[List[VoiceState]]
136132
"""
@@ -145,16 +141,14 @@ def get_channel_voice_states(
145141
def __register_lavalink_listeners(self):
146142
for extension in self._extensions.values():
147143
for name, func in getmembers(extension):
148-
if hasattr(func, "__lavalink__"):
149-
name = func.__lavalink__[3:]
150-
event_name = "".join(word.capitalize() for word in name.split("_")) + "Event"
151-
if event_name not in self.lavalink_client._event_hooks:
152-
self.lavalink_client._event_hooks[event_name] = []
153-
self.lavalink_client._event_hooks[event_name].append(func)
154-
155-
async def _ready(self) -> None:
156-
self.__register_lavalink_listeners()
157-
await super()._ready()
144+
if not hasattr(func, "__lavalink__"):
145+
continue
146+
name = func.__lavalink__[3:]
147+
event_name = "".join(word.capitalize() for word in name.split("_")) + "Event"
148+
event_hooks = self.lavalink_client._event_hooks
149+
if event_name not in event_hooks:
150+
event_hooks[event_name] = []
151+
event_hooks[event_name].append(func)
158152

159153

160154
def listener(func=None, *, name: str = None):

interactions/ext/lavalink/models.py

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from datetime import datetime
22
from typing import TYPE_CHECKING, Optional
33

4-
from interactions.api.models.attrs_utils import ClientSerializerMixin, define, field
4+
from interactions.utils.attrs_utils import ClientSerializerMixin, define, field
55

66
from interactions import Channel, Guild, LibraryException, Member, Snowflake
77

@@ -20,37 +20,19 @@ class VoiceState(ClientSerializerMixin):
2020
This class creates an object every time the event ``VOICE_STATE_UPDATE`` is received from the discord API.
2121
It contains information about the user's update voice information.
2222
23-
Attributes:
24-
-----------
25-
_json : dict
26-
All data of the object stored as dictionary
27-
member : Member
28-
The member whose VoiceState was updated
29-
user_id : int
30-
The id of the user whose VoiceState was updated. This is technically the same as the "member id",
31-
but it is called `user_id` because of API terminology.
32-
suppress : bool
33-
Whether the user is muted by the current user(-> bot)
34-
session_id : int
35-
The id of the session
36-
self_video : bool
37-
Whether the user's camera is enabled.
38-
self_mute : bool
39-
Whether the user is muted by themselves
40-
self_deaf : bool
41-
Whether the user is deafened by themselves
42-
self_stream : bool
43-
Whether the user is streaming in the current channel
44-
request_to_speak_timestamp : datetime
45-
Only for stage-channels; when the user requested permissions to speak in the stage channel
46-
mute : bool
47-
Whether the user's microphone is muted by the server
48-
guild_id : int
49-
The id of the guild in what the update took action
50-
deaf : bool
51-
Whether the user is deafened by the guild
52-
channel_id : int
53-
The id of the channel the update took action
23+
:ivar Member member: The member whose VoiceState was updated
24+
:ivar int user_id: The id of the user whose VoiceState was updated.
25+
:ivar bool suppress: Whether the user is muted by the current user(-> bot)
26+
:ivar int session_id: The id of the session
27+
:ivar bool self_video: Whether the user's camera is enabled.
28+
:ivar bool self_mute: Whether the user is muted by themselves
29+
:ivar bool self_deaf: Whether the user is deafened by themselves
30+
:ivar bool self_stream: Whether the user is streaming in the current channel
31+
:ivar datetime request_to_speak_timestamp: Only for stage-channels; when the user requested permissions to speak in the stage channel
32+
:ivar bool mute: Whether the user's microphone is muted by the server
33+
:ivar int guild_id: The id of the guild in what the update took action
34+
:ivar bool deaf: Whether the user is deafened by the guild
35+
:ivar int channel_id: The id of the channel the update took action
5436
"""
5537

5638
guild_id: Optional[Snowflake] = field(converter=Snowflake, default=None)
@@ -78,7 +60,7 @@ def joined(self) -> bool:
7860
"""
7961
return self.channel_id is not None
8062

81-
async def mute_member(self, reason: Optional[str]) -> Member:
63+
async def mute_member(self, reason: Optional[str] = None) -> Member:
8264
"""
8365
Mutes the current member.
8466
@@ -89,7 +71,7 @@ async def mute_member(self, reason: Optional[str]) -> Member:
8971
"""
9072
return await self.member.modify(guild_id=int(self.guild_id), mute=True, reason=reason)
9173

92-
async def deafen_member(self, reason: Optional[str]) -> Member:
74+
async def deafen_member(self, reason: Optional[str] = None) -> Member:
9375
"""
9476
Deafens the current member.
9577
@@ -100,7 +82,7 @@ async def deafen_member(self, reason: Optional[str]) -> Member:
10082
"""
10183
return await self.member.modify(guild_id=int(self.guild_id), deaf=True, reason=reason)
10284

103-
async def move_member(self, channel_id: int, *, reason: Optional[str]) -> Member:
85+
async def move_member(self, channel_id: int, *, reason: Optional[str] = None) -> Member:
10486
"""
10587
Moves the member to another channel.
10688
@@ -141,7 +123,7 @@ async def connect(self, self_deaf: bool = False, self_mute: bool = False) -> "Pl
141123
if not self.channel_id:
142124
raise LibraryException(message="User not connected to the voice channel!")
143125

144-
await self._client._bot_var._websocket.connect_voice_channel(
126+
await self._client._bot_var._websocket.update_voice_state(
145127
self.guild_id, self.channel_id, self_deaf, self_mute
146128
)
147129
player = self._client._bot_var.lavalink_client.player_manager.get(int(self.guild_id))
@@ -154,7 +136,10 @@ async def connect(self, self_deaf: bool = False, self_mute: bool = False) -> "Pl
154136
class VoiceServer(ClientSerializerMixin):
155137
"""
156138
A class object representing the gateway event ``VOICE_SERVER_UPDATE``.
157-
This class creates an object every time the event ``VOICE_SERVER_UPDATE`` is received from the discord API.
139+
140+
:ivar str endpoint: Voice connection token
141+
:ivar Snowflake guild_id: Guild this voice server update is for
142+
:ivar str token: Voice server host
158143
"""
159144

160145
endpoint: str = field()
Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
1-
from interactions import OpCodeType, Storage, WebSocketClient
1+
from typing import TYPE_CHECKING
2+
3+
from interactions import OpCodeType, Storage, WebSocketClient, HTTPClient
24

35
from .models import VoiceServer, VoiceState
46

7+
if TYPE_CHECKING:
8+
from .client import VoiceClient
9+
510
__all__ = ["VoiceWebSocketClient"]
611

712

813
class VoiceWebSocketClient(WebSocketClient):
9-
def __init__(self, *args):
14+
def __init__(self, bot_var: "VoiceClient", *args):
15+
self._bot_var: "VoiceClient" = bot_var
1016
super().__init__(*args)
1117

18+
async def run(self) -> None:
19+
"""
20+
Handles the client's connection with the Gateway.
21+
"""
22+
23+
if isinstance(self._http, str):
24+
self._http = HTTPClient(self._http)
25+
self._http._bot_var = self._bot_var
26+
27+
await super().run()
28+
1229
def _dispatch_event(self, event: str, data: dict) -> None:
30+
"""
31+
Dispatches VOICE_STATE_UPDATE and VOICE_SERVER_UPDATE events from the Gateway.
32+
33+
:param str event: The name of the event.
34+
:param dict data: The data for the event.
35+
"""
1336
if event not in ("VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"):
1437
return super()._dispatch_event(event, data)
1538

1639
self._dispatch.dispatch(f"on_raw_{event.lower()}", data)
1740
_cache: Storage = self._http.cache[VoiceState]
41+
1842
if event == "VOICE_SERVER_UPDATE":
1943
model = VoiceServer(**data, _client=self._http)
2044
self._dispatch.dispatch("on_voice_server_update", model)
@@ -24,44 +48,32 @@ def _dispatch_event(self, event: str, data: dict) -> None:
2448
self._dispatch.dispatch("on_voice_state_update", old, model)
2549
_cache.add(model, model.user_id)
2650

27-
async def connect_voice_channel(
28-
self, guild_id: int, channel_id: int, self_deaf: bool, self_mute: bool
51+
async def update_voice_state(
52+
self,
53+
guild_id: int,
54+
channel_id: int = None,
55+
self_deaf: bool = None,
56+
self_mute: bool = None,
2957
):
3058
"""
31-
Sends packet to websocket for connection to voice channel.
32-
33-
:param guild_id: The guild id to connect.
34-
:type guild_id: int
35-
:param channel_id: The channel id to connect.
36-
:type channel_id: int
37-
:param self_deaf: Whether bot is self deafened
38-
:type self_deaf: bool
39-
:param self_mute: Whether bot is self muted
40-
:type self_mute: bool
59+
Sends VOICE_STATE packet to websocket.
60+
61+
:param int guild_id: The guild id.
62+
:param int channel_id: The channel id.
63+
:param bool self_deaf: Whether bot is self deafened
64+
:param bool self_mute: Whether bot is self muted
4165
"""
66+
4267
payload = {
4368
"op": OpCodeType.VOICE_STATE,
4469
"d": {
45-
"channel_id": str(channel_id),
4670
"guild_id": str(guild_id),
47-
"self_deaf": self_deaf,
48-
"self_mute": self_mute,
71+
"channel_id": str(channel_id) if channel_id is not None else None,
4972
},
5073
}
51-
52-
await self._send_packet(payload)
53-
54-
async def disconnect_voice_channel(self, guild_id: int):
55-
"""
56-
Sends packet to websocket for disconnecting from voice channel.
57-
58-
:param guild_id: The guild id
59-
:type guild_id: int
60-
61-
"""
62-
payload = {
63-
"op": OpCodeType.VOICE_STATE,
64-
"d": {"channel_id": None, "guild_id": str(guild_id)},
65-
}
74+
if self_deaf is not None:
75+
payload["d"]["self_deaf"] = self_deaf
76+
if self_mute is not None:
77+
payload["d"]["self_mute"] = self_mute
6678

6779
await self._send_packet(payload)

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
discord-py-interactions>=4.3.0, <4.3.2
1+
discord-py-interactions>=4.3.2
22
lavalink~=4.0.1

0 commit comments

Comments
 (0)