feat: add Activity presence models (#60)
This commit is contained in:
parent
c47a7e49f8
commit
39162b6543
@ -36,6 +36,7 @@ from .ext import loader as ext_loader
|
|||||||
from .interactions import Interaction, Snowflake
|
from .interactions import Interaction, Snowflake
|
||||||
from .error_handler import setup_global_error_handler
|
from .error_handler import setup_global_error_handler
|
||||||
from .voice_client import VoiceClient
|
from .voice_client import VoiceClient
|
||||||
|
from .models import Activity
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .models import (
|
from .models import (
|
||||||
@ -439,8 +440,7 @@ class Client:
|
|||||||
async def change_presence(
|
async def change_presence(
|
||||||
self,
|
self,
|
||||||
status: str,
|
status: str,
|
||||||
activity_name: Optional[str] = None,
|
activity: Optional[Activity] = None,
|
||||||
activity_type: int = 0,
|
|
||||||
since: int = 0,
|
since: int = 0,
|
||||||
afk: bool = False,
|
afk: bool = False,
|
||||||
):
|
):
|
||||||
@ -449,8 +449,7 @@ class Client:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
status (str): The new status for the client (e.g., "online", "idle", "dnd", "invisible").
|
status (str): The new status for the client (e.g., "online", "idle", "dnd", "invisible").
|
||||||
activity_name (Optional[str]): The name of the activity.
|
activity (Optional[Activity]): Activity instance describing what the bot is doing.
|
||||||
activity_type (int): The type of the activity.
|
|
||||||
since (int): The timestamp (in milliseconds) of when the client went idle.
|
since (int): The timestamp (in milliseconds) of when the client went idle.
|
||||||
afk (bool): Whether the client is AFK.
|
afk (bool): Whether the client is AFK.
|
||||||
"""
|
"""
|
||||||
@ -460,8 +459,7 @@ class Client:
|
|||||||
if self._gateway:
|
if self._gateway:
|
||||||
await self._gateway.update_presence(
|
await self._gateway.update_presence(
|
||||||
status=status,
|
status=status,
|
||||||
activity_name=activity_name,
|
activity=activity,
|
||||||
activity_type=activity_type,
|
|
||||||
since=since,
|
since=since,
|
||||||
afk=afk,
|
afk=afk,
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,8 @@ import time
|
|||||||
import random
|
import random
|
||||||
from typing import Optional, TYPE_CHECKING, Any, Dict
|
from typing import Optional, TYPE_CHECKING, Any, Dict
|
||||||
|
|
||||||
|
from .models import Activity
|
||||||
|
|
||||||
from .enums import GatewayOpcode, GatewayIntent
|
from .enums import GatewayOpcode, GatewayIntent
|
||||||
from .errors import GatewayException, DisagreementException, AuthenticationError
|
from .errors import GatewayException, DisagreementException, AuthenticationError
|
||||||
from .interactions import Interaction
|
from .interactions import Interaction
|
||||||
@ -213,26 +215,17 @@ class GatewayClient:
|
|||||||
async def update_presence(
|
async def update_presence(
|
||||||
self,
|
self,
|
||||||
status: str,
|
status: str,
|
||||||
activity_name: Optional[str] = None,
|
activity: Optional[Activity] = None,
|
||||||
activity_type: int = 0,
|
*,
|
||||||
since: int = 0,
|
since: int = 0,
|
||||||
afk: bool = False,
|
afk: bool = False,
|
||||||
):
|
) -> None:
|
||||||
"""Sends the presence update payload to the Gateway."""
|
"""Sends the presence update payload to the Gateway."""
|
||||||
payload = {
|
payload = {
|
||||||
"op": GatewayOpcode.PRESENCE_UPDATE,
|
"op": GatewayOpcode.PRESENCE_UPDATE,
|
||||||
"d": {
|
"d": {
|
||||||
"since": since,
|
"since": since,
|
||||||
"activities": (
|
"activities": [activity.to_dict()] if activity else [],
|
||||||
[
|
|
||||||
{
|
|
||||||
"name": activity_name,
|
|
||||||
"type": activity_type,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
if activity_name
|
|
||||||
else []
|
|
||||||
),
|
|
||||||
"status": status,
|
"status": status,
|
||||||
"afk": afk,
|
"afk": afk,
|
||||||
},
|
},
|
||||||
@ -353,7 +346,10 @@ class GatewayClient:
|
|||||||
future._members.extend(raw_event_d_payload.get("members", [])) # type: ignore
|
future._members.extend(raw_event_d_payload.get("members", [])) # type: ignore
|
||||||
|
|
||||||
# If this is the last chunk, resolve the future
|
# If this is the last chunk, resolve the future
|
||||||
if raw_event_d_payload.get("chunk_index") == raw_event_d_payload.get("chunk_count", 1) - 1:
|
if (
|
||||||
|
raw_event_d_payload.get("chunk_index")
|
||||||
|
== raw_event_d_payload.get("chunk_count", 1) - 1
|
||||||
|
):
|
||||||
future.set_result(future._members) # type: ignore
|
future.set_result(future._members) # type: ignore
|
||||||
del self._member_chunk_requests[nonce]
|
del self._member_chunk_requests[nonce]
|
||||||
|
|
||||||
|
@ -2361,6 +2361,37 @@ class ThreadMember:
|
|||||||
return f"<ThreadMember user_id='{self.user_id}' thread_id='{self.id}'>"
|
return f"<ThreadMember user_id='{self.user_id}' thread_id='{self.id}'>"
|
||||||
|
|
||||||
|
|
||||||
|
class Activity:
|
||||||
|
"""Represents a user's presence activity."""
|
||||||
|
|
||||||
|
def __init__(self, name: str, type: int) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.type = type
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
return {"name": self.name, "type": self.type}
|
||||||
|
|
||||||
|
|
||||||
|
class Game(Activity):
|
||||||
|
"""Represents a playing activity."""
|
||||||
|
|
||||||
|
def __init__(self, name: str) -> None:
|
||||||
|
super().__init__(name, 0)
|
||||||
|
|
||||||
|
|
||||||
|
class Streaming(Activity):
|
||||||
|
"""Represents a streaming activity."""
|
||||||
|
|
||||||
|
def __init__(self, name: str, url: str) -> None:
|
||||||
|
super().__init__(name, 1)
|
||||||
|
self.url = url
|
||||||
|
|
||||||
|
def to_dict(self) -> Dict[str, Any]:
|
||||||
|
payload = super().to_dict()
|
||||||
|
payload["url"] = self.url
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
class PresenceUpdate:
|
class PresenceUpdate:
|
||||||
"""Represents a PRESENCE_UPDATE event."""
|
"""Represents a PRESENCE_UPDATE event."""
|
||||||
|
|
||||||
@ -2371,7 +2402,17 @@ class PresenceUpdate:
|
|||||||
self.user = User(data["user"])
|
self.user = User(data["user"])
|
||||||
self.guild_id: Optional[str] = data.get("guild_id")
|
self.guild_id: Optional[str] = data.get("guild_id")
|
||||||
self.status: Optional[str] = data.get("status")
|
self.status: Optional[str] = data.get("status")
|
||||||
self.activities: List[Dict[str, Any]] = data.get("activities", [])
|
self.activities: List[Activity] = []
|
||||||
|
for activity in data.get("activities", []):
|
||||||
|
act_type = activity.get("type", 0)
|
||||||
|
name = activity.get("name", "")
|
||||||
|
if act_type == 0:
|
||||||
|
obj = Game(name)
|
||||||
|
elif act_type == 1:
|
||||||
|
obj = Streaming(name, activity.get("url", ""))
|
||||||
|
else:
|
||||||
|
obj = Activity(name, act_type)
|
||||||
|
self.activities.append(obj)
|
||||||
self.client_status: Dict[str, Any] = data.get("client_status", {})
|
self.client_status: Dict[str, Any] = data.get("client_status", {})
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Updating Presence
|
# Updating Presence
|
||||||
|
|
||||||
The `Client.change_presence` method allows you to update the bot's status and displayed activity.
|
The `Client.change_presence` method allows you to update the bot's status and displayed activity.
|
||||||
|
Pass an :class:`~disagreement.models.Activity` (such as :class:`~disagreement.models.Game` or :class:`~disagreement.models.Streaming`) to describe what your bot is doing.
|
||||||
|
|
||||||
## Status Strings
|
## Status Strings
|
||||||
|
|
||||||
@ -22,8 +23,18 @@ An activity dictionary must include a `name` and a `type` field. The type value
|
|||||||
| `4` | Custom |
|
| `4` | Custom |
|
||||||
| `5` | Competing |
|
| `5` | Competing |
|
||||||
|
|
||||||
Example:
|
Example using the provided activity classes:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
await client.change_presence(status="idle", activity={"name": "with Discord", "type": 0})
|
from disagreement.models import Game
|
||||||
|
|
||||||
|
await client.change_presence(status="idle", activity=Game("with Discord"))
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also specify a streaming URL:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from disagreement.models import Streaming
|
||||||
|
|
||||||
|
await client.change_presence(status="online", activity=Streaming("My Stream", "https://twitch.tv/someone"))
|
||||||
```
|
```
|
||||||
|
@ -2,6 +2,7 @@ import pytest
|
|||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from disagreement.client import Client
|
from disagreement.client import Client
|
||||||
|
from disagreement.models import Game
|
||||||
from disagreement.errors import DisagreementException
|
from disagreement.errors import DisagreementException
|
||||||
|
|
||||||
|
|
||||||
@ -18,11 +19,11 @@ class DummyGateway(MagicMock):
|
|||||||
async def test_change_presence_passes_arguments():
|
async def test_change_presence_passes_arguments():
|
||||||
client = Client(token="t")
|
client = Client(token="t")
|
||||||
client._gateway = DummyGateway()
|
client._gateway = DummyGateway()
|
||||||
|
game = Game("hi")
|
||||||
await client.change_presence(status="idle", activity_name="hi", activity_type=0)
|
await client.change_presence(status="idle", activity=game)
|
||||||
|
|
||||||
client._gateway.update_presence.assert_awaited_once_with(
|
client._gateway.update_presence.assert_awaited_once_with(
|
||||||
status="idle", activity_name="hi", activity_type=0, since=0, afk=False
|
status="idle", activity=game, since=0, afk=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user