Browse Source

Add support for "Do Not Disturb" and "Invisible" statuses.

This deprecates Client.change_status in favour of the newer and more
correct Client.change_presence.
pull/349/head
Rapptz 9 years ago
parent
commit
7272190e2d
  1. 42
      discord/client.py
  2. 3
      discord/enums.py
  3. 22
      discord/gateway.py
  4. 16
      discord/utils.py
  5. 11
      docs/api.rst

42
discord/client.py

@ -37,7 +37,7 @@ from .errors import *
from .state import ConnectionState
from .permissions import Permissions, PermissionOverwrite
from . import utils, compat
from .enums import ChannelType, ServerRegion, VerificationLevel
from .enums import ChannelType, ServerRegion, VerificationLevel, Status
from .voice_client import VoiceClient
from .iterators import LogsFromIterator
from .gateway import *
@ -1526,6 +1526,7 @@ class Client:
self._update_cache(self.email, password)
@asyncio.coroutine
@utils.deprecated('change_presence')
def change_status(self, game=None, idle=False):
"""|coro|
@ -1537,7 +1538,8 @@ class Client:
The idle parameter is a boolean parameter that indicates whether the
client should go idle or not.
.. _game_list: https://gist.github.com/Rapptz/a82b82381b70a60c281b
.. deprecated:: v0.13.0
Use :meth:`change_status` instead.
Parameters
----------
@ -1553,6 +1555,42 @@ class Client:
"""
yield from self.ws.change_presence(game=game, idle=idle)
@asyncio.coroutine
def change_presence(self, *, game=None, status=None, afk=False):
"""|coro|
Changes the client's presence.
The game parameter is a Game object (not a string) that represents
a game being played currently.
Parameters
----------
game: Optional[:class:`Game`]
The game being played. None if no game is being played.
status: Optional[:class:`Status`]
Indicates what status to change to. If None, then
:attr:`Status.online` is used.
afk: bool
Indicates if you are going AFK. This allows the discord
client to know how to handle push notifications better
for you in case you are actually idle and not lying.
Raises
------
InvalidArgument
If the ``game`` parameter is not :class:`Game` or None.
"""
if status is None:
status = 'online'
elif status is Status.offline:
status = 'invisible'
else:
status = str(status)
yield from self.ws.change_presence(game=game, status=status, afk=afk)
@asyncio.coroutine
def change_nickname(self, member, nickname):
"""|coro|

3
discord/enums.py

@ -78,6 +78,9 @@ class Status(Enum):
online = 'online'
offline = 'offline'
idle = 'idle'
dnd = 'dnd'
do_not_disturb = 'dnd'
invisible = 'invisible'
def __str__(self):
return self.value

22
discord/gateway.py

@ -29,7 +29,7 @@ import websockets
import asyncio
import aiohttp
from . import utils, compat
from .enums import Status
from .enums import Status, try_enum
from .game import Game
from .errors import GatewayNotFound, ConnectionClosed, InvalidArgument
import logging
@ -406,18 +406,25 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol):
raise ConnectionClosed(e) from e
@asyncio.coroutine
def change_presence(self, *, game=None, idle=None):
def change_presence(self, *, game=None, status=None, afk=False, since=0.0, idle=None):
if game is not None and not isinstance(game, Game):
raise InvalidArgument('game must be of Game or None')
idle_since = None if idle == False else int(time.time() * 1000)
if idle:
status = 'idle'
if status == 'idle':
since = int(time.time() * 1000)
sent_game = dict(game) if game else None
payload = {
'op': self.PRESENCE,
'd': {
'game': sent_game,
'idle_since': idle_since
'afk': afk,
'since': since,
'status': status
}
}
@ -425,14 +432,17 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol):
log.debug('Sending "{}" to change status'.format(sent))
yield from self.send(sent)
status_enum = try_enum(Status, status)
if status_enum is Status.invisible:
status_enum = Status.offline
for server in self._connection.servers:
me = server.me
if me is None:
continue
me.game = game
status = Status.idle if idle_since else Status.online
me.status = status
me.status = status_enum
@asyncio.coroutine
def request_sync(self, guild_ids):

16
discord/utils.py

@ -30,6 +30,7 @@ import datetime
from base64 import b64encode
import asyncio
import json
import warnings, functools
DISCORD_EPOCH = 1420070400000
@ -74,6 +75,21 @@ def parse_time(timestamp):
return datetime.datetime(*map(int, re_split(r'[^\d]', timestamp.replace('+00:00', ''))))
return None
def deprecated(instead=None):
def actual_decorator(func):
@functools.wraps(func)
def decorated(*args, **kwargs):
warnings.simplefilter('always', DeprecationWarning) # turn off filter
if instead:
fmt = "{0.__name__} is deprecated, use {1} instead."
else:
fmt = '{0.__name__} is deprecated.'
warnings.warn(fmt.format(func, instead), stacklevel=3, category=DeprecationWarning)
warnings.simplefilter('default', DeprecationWarning) # reset filter
return func(*args, **kwargs)
return decorated
return actual_decorator
def oauth_url(client_id, permissions=None, server=None, redirect_uri=None):
"""A helper function that returns the OAuth2 URL for inviting the bot

11
docs/api.rst

@ -549,6 +549,17 @@ All enumerations are subclasses of `enum`_.
.. attribute:: idle
The member is idle.
.. attribute:: dnd
The member is "Do Not Disturb".
.. attribute:: do_not_disturb
An alias for :attr:`dnd`.
.. attribute:: invisible
The member is "invisible". In reality, this is only used in sending
a presence a la :meth:`Client.change_presence`. When you receive a
user's presence this will be :attr:`offline` instead.
.. _discord_api_data:

Loading…
Cancel
Save