diff --git a/discord/__init__.py b/discord/__init__.py index e4c0a6748..0bde8628a 100644 --- a/discord/__init__.py +++ b/discord/__init__.py @@ -20,6 +20,7 @@ __build__ = 0x009000 from .client import Client from .user import User +from .game import Game from .channel import Channel, PrivateChannel from .server import Server from .member import Member diff --git a/discord/client.py b/discord/client.py index 8e94971cb..f44ccded0 100644 --- a/discord/client.py +++ b/discord/client.py @@ -37,6 +37,7 @@ from .message import Message from . import utils from .invite import Invite from .object import Object +from .game import Game import traceback import requests @@ -208,12 +209,13 @@ class ConnectionState(object): if member is not None: old_member = copy.copy(member) member.status = data.get('status') - member.game_id = data.get('game_id') + game = data.get('game') + member.game = game and Game(**game) member.name = user.get('username', member.name) member.avatar = user.get('avatar', member.avatar) # call the event now - self.dispatch('status', member, old_member.game_id, old_member.status) + self.dispatch('status', member, old_member.game, old_member.status) self.dispatch('member_update', old_member, member) def handle_user_update(self, data): @@ -1444,27 +1446,25 @@ class Client(object): log.debug(request_logging_format.format(response=response)) utils._verify_successful_response(response) - def change_status(self, game_id=None, idle=False): + def change_status(self, game=None, idle=False): """Changes the client's status. - The game_id parameter is a numeric ID (not a string) that represents - a game being played currently. The list of game_id to actual games changes - constantly and would thus be out of date pretty quickly. An old version of - the game_id database can be seen `here`_ to help you get started. + The game parameter is a Game object that represents a game being played + currently. May be None if no game is being played. The idle parameter is a boolean parameter that indicates whether the client should go idle or not. .. _here: https://gist.github.com/Rapptz/a82b82381b70a60c281b - :param game_id: The numeric game ID being played. None if no game is being played. + :param game: A Game object representing the game being played. None if no game is being played. :param idle: A boolean indicating if the client should go idle.""" idle_since = None if idle == False else int(time.time() * 1000) payload = { 'op': 3, 'd': { - 'game_id': game_id, + 'game': game and {'name': game.name}, 'idle_since': idle_since } } diff --git a/discord/game.py b/discord/game.py new file mode 100644 index 000000000..913867763 --- /dev/null +++ b/discord/game.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +""" +The MIT License (MIT) + +Copyright (c) 2015 Rapptz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +""" + + +class Game(object): + """Represents the game a :class:`Member` is playing + + Instance attributes: + + .. attribute:: name + + The game name + """ + + __slots__ = ['name'] + + def __init__(self, **kwargs): + self.name = kwargs.get('name') + + def __str__(self): + return self.name + + def __eq__(self, other): + return isinstance(other, Game) and other.name == self.name + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.name) diff --git a/discord/member.py b/discord/member.py index 2fadc664d..1bb7b130c 100644 --- a/discord/member.py +++ b/discord/member.py @@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE. from .user import User from .utils import parse_time +from .game import Game class Member(User): """Represents a Discord member to a :class:`Server`. @@ -65,9 +66,9 @@ class Member(User): .. attribute:: status A string that denotes the user's status. Can be 'online', 'offline' or 'idle'. - .. attribute:: game_id + .. attribute:: game - The game ID that the user is currently playing. Could be None if no game is being played. + A dictionary representing the game that the user is currently playing. None if no game is being played. .. attribute:: server The :class:`Server` that the member belongs to. @@ -80,7 +81,8 @@ class Member(User): self.joined_at = parse_time(joined_at) self.roles = roles self.status = 'offline' - self.game_id = kwargs.get('game_id', None) + game = kwargs.get('game', None) + self.game = game and Game(**game) self.server = kwargs.get('server', None) self.update_voice_state(mute=mute, deaf=deaf) diff --git a/discord/server.py b/discord/server.py index 0c2eca5a2..e06e8b4f5 100644 --- a/discord/server.py +++ b/discord/server.py @@ -28,6 +28,7 @@ from . import utils from .role import Role from .member import Member from .channel import Channel +from .game import Game class Server(object): """Represents a Discord server. @@ -119,7 +120,8 @@ class Server(object): member = utils.find(lambda m: m.id == user_id, self.members) if member is not None: member.status = presence['status'] - member.game_id = presence['game_id'] + game = presence['game'] + member.game = game and Game(**game) self.channels = [Channel(server=self, **c) for c in guild['channels']] afk_id = guild.get('afk_channel_id') diff --git a/docs/api.rst b/docs/api.rst index 935f05dc7..c3541f928 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -152,12 +152,12 @@ to handle it, which defaults to print a traceback and ignore the exception. :param before: A :class:`Message` of the previous version of the message. :param after: A :class:`Message` of the current version of the message. -.. function:: on_status(member, old_game_id, old_status) +.. function:: on_status(member, old_game, old_status) Called whenever a :class:`Member` changes their status or game playing status. :param member: The :class:`Member` who has had their status changed. - :param old_game_id: The game ID the member had before it changed. + :param old_game_id: The :class:`Game` the member had before it changed. :param old_status: The status the member had before it changed. .. function:: on_channel_delete(channel)