from datetime import datetime from binascii import hexlify from gevent.event import Event from steam.steamid import SteamID from steam.enums import EFriendRelationship, EPersonaState, EChatEntryType from steam.enums.emsg import EMsg from steam.core.msg import MsgProto class SteamUser(object): """ A data model for a Steam user. Holds user persona state, and related actions .. note:: This is an internal object that can be obtained by :meth:`SteamClient.get_user` """ _pstate = None _pstate_requested = False steam_id = SteamID() #: steam id relationship = EFriendRelationship.NONE #: friendship status def __init__(self, steam_id, steam): self._pstate_ready = Event() self._steam = steam self.steam_id = SteamID(steam_id) def __repr__(self): return "<%s(%s, %s, %s)>" % ( self.__class__.__name__, str(self.steam_id), self.relationship, self.state, ) def refresh(self, wait=True): if self._pstate_requested and self._pstate_ready.is_set(): self._pstate_requested = False if not self._pstate_requested: self._steam.request_persona_state([self.steam_id]) self._pstate_ready.clear() self._pstate_requested = True if wait: self._pstate_ready.wait(timeout=5) self._pstate_requested = False def get_ps(self, field_name, wait_pstate=True): """Get property from PersonaState `See full list of available fields_names `_ """ if not self._pstate_ready.is_set() and wait_pstate: self.refresh() if self._pstate is not None: return getattr(self._pstate, field_name) else: return None @property def last_logon(self): """:rtype: :class:`datetime`, :class:`None`""" ts = self.get_ps('last_logon') return datetime.utcfromtimestamp(ts) if ts else None @property def last_logoff(self): """:rtype: :class:`datetime`, :class:`None`""" ts = self.get_ps('last_logoff') return datetime.utcfromtimestamp(ts) if ts else None @property def name(self): """Name of the steam user, or ``None`` if it's not available :rtype: :class:`str`, :class:`None` """ return self.get_ps('player_name') @property def state(self): """Personsa state (e.g. Online, Offline, Away, Busy, etc) :rtype: :class:`.EPersonaState` """ state = self.get_ps('persona_state', False) return EPersonaState(state) if state else EPersonaState.Offline @property def rich_presence(self): """Contains Rich Presence key-values :rtype: dict """ kvs = self.get_ps('rich_presence') data = {} if kvs: for kv in kvs: data[kv.key] = kv.value return data def get_avatar_url(self, size=2): """Get URL to avatar picture :param size: possible values are ``0``, ``1``, or ``2`` corresponding to small, medium, large :type size: :class:`int` :return: url to avatar :rtype: :class:`str` """ hashbytes = self.get_ps('avatar_hash') if hashbytes != "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000": ahash = hexlify(hashbytes).decode('ascii') else: ahash = 'fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb' sizes = { 0: '', 1: '_medium', 2: '_full', } url = "http://cdn.akamai.steamstatic.com/steamcommunity/public/images/avatars/%s/%s%s.jpg" return url % (ahash[:2], ahash, sizes[size]) def send_message(self, message): """Send chat message to this steam user :param message: message to send :type message: str """ # new chat if self._steam.chat_mode == 2: self._steam.send_um("FriendMessages.SendMessage#1", { 'steamid': self.steam_id, 'message': message, 'chat_entry_type': EChatEntryType.ChatMsg, }) # old chat else: self._steam.send(MsgProto(EMsg.ClientFriendMsg), { 'steamid': self.steam_id, 'chat_entry_type': EChatEntryType.ChatMsg, 'message': message.encode('utf8'), }) def block(self): """Block user""" self._steam.friends.block(self) def unblock(self): """Unblock user""" self._steam.friends.unblock(self)