132 lines
5.6 KiB
Python
132 lines
5.6 KiB
Python
from typing import Any, Dict, List, Set, Tuple
|
|
|
|
from bemani.api.exceptions import APIException
|
|
from bemani.api.objects.base import BaseObject
|
|
from bemani.common import ValidatedDict, GameConstants, APIConstants
|
|
from bemani.data import UserID
|
|
|
|
|
|
class ProfileObject(BaseObject):
|
|
|
|
def __format_ddr_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
return {
|
|
'area': profile.get_int('area', -1) if exact else -1,
|
|
}
|
|
|
|
def __format_iidx_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
qpro = profile.get_dict('qpro')
|
|
|
|
return {
|
|
'area': profile.get_int('pid', -1),
|
|
'qpro': {
|
|
'head': qpro.get_int('head', -1) if exact else -1,
|
|
'hair': qpro.get_int('hair', -1) if exact else -1,
|
|
'face': qpro.get_int('face', -1) if exact else -1,
|
|
'body': qpro.get_int('body', -1) if exact else -1,
|
|
'hand': qpro.get_int('hand', -1) if exact else -1,
|
|
}
|
|
}
|
|
|
|
def __format_jubeat_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
return {}
|
|
|
|
def __format_museca_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
return {}
|
|
|
|
def __format_popn_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
return {
|
|
'character': profile.get_int('chara', -1) if exact else -1,
|
|
}
|
|
|
|
def __format_reflec_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
return {
|
|
'icon': profile.get_dict('config').get_int('icon_id', -1) if exact else -1,
|
|
}
|
|
|
|
def __format_sdvx_profile(self, profile: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
return {}
|
|
|
|
def __format_profile(self, cardids: List[str], profile: ValidatedDict, settings: ValidatedDict, exact: bool) -> Dict[str, Any]:
|
|
base = {
|
|
'name': profile.get_str('name'),
|
|
'cards': cardids,
|
|
'registered': settings.get_int('first_play_timestamp', -1),
|
|
'updated': settings.get_int('last_play_timestamp', -1),
|
|
'plays': settings.get_int('total_plays', -1),
|
|
'match': 'exact' if exact else 'partial',
|
|
}
|
|
|
|
if self.game == GameConstants.DDR:
|
|
base.update(self.__format_ddr_profile(profile, exact))
|
|
if self.game == GameConstants.IIDX:
|
|
base.update(self.__format_iidx_profile(profile, exact))
|
|
if self.game == GameConstants.JUBEAT:
|
|
base.update(self.__format_jubeat_profile(profile, exact))
|
|
if self.game == GameConstants.MUSECA:
|
|
base.update(self.__format_museca_profile(profile, exact))
|
|
if self.game == GameConstants.POPN_MUSIC:
|
|
base.update(self.__format_popn_profile(profile, exact))
|
|
if self.game == GameConstants.REFLEC_BEAT:
|
|
base.update(self.__format_reflec_profile(profile, exact))
|
|
if self.game == GameConstants.SDVX:
|
|
base.update(self.__format_sdvx_profile(profile, exact))
|
|
|
|
return base
|
|
|
|
def fetch_v1(self, idtype: str, ids: List[str], params: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
# Fetch the profiles
|
|
profiles: List[Tuple[UserID, ValidatedDict]] = []
|
|
if idtype == APIConstants.ID_TYPE_SERVER:
|
|
profiles.extend(self.data.local.user.get_all_profiles(self.game, self.version))
|
|
elif idtype == APIConstants.ID_TYPE_SONG:
|
|
raise APIException(
|
|
'Unsupported ID for lookup!',
|
|
405,
|
|
)
|
|
elif idtype == APIConstants.ID_TYPE_INSTANCE:
|
|
raise APIException(
|
|
'Unsupported ID for lookup!',
|
|
405,
|
|
)
|
|
elif idtype == APIConstants.ID_TYPE_CARD:
|
|
users: Set[UserID] = set()
|
|
for cardid in ids:
|
|
userid = self.data.local.user.from_cardid(cardid)
|
|
if userid is not None:
|
|
# Don't duplicate loads for users with multiple card IDs if multiples
|
|
# of those IDs are requested.
|
|
if userid in users:
|
|
continue
|
|
users.add(userid)
|
|
|
|
# We can possibly find another profile for this user. This is important
|
|
# in the case that we returned scores for a user that doesn't have a
|
|
# profile on a particular version. We allow that on this network, so in
|
|
# order to not break remote networks, try our best to return any profile.
|
|
profile = self.data.local.user.get_any_profile(self.game, self.version, userid)
|
|
if profile is not None:
|
|
profiles.append((userid, profile))
|
|
else:
|
|
raise APIException('Invalid ID type!')
|
|
|
|
# Now, fetch the users, and filter out profiles belonging to orphaned users
|
|
retval: List[Dict[str, Any]] = []
|
|
id_to_cards: Dict[UserID, List[str]] = {}
|
|
for (userid, profile) in profiles:
|
|
if userid not in id_to_cards:
|
|
cards = self.data.local.user.get_cards(userid)
|
|
if len(cards) == 0:
|
|
# Can't add this user, skip the profile
|
|
continue
|
|
|
|
id_to_cards[userid] = cards
|
|
|
|
# Format the profile and add it
|
|
settings = self.data.local.game.get_settings(self.game, userid)
|
|
if settings is None:
|
|
settings = ValidatedDict({})
|
|
|
|
retval.append(self.__format_profile(id_to_cards[userid], profile, settings, profile['version'] == self.version))
|
|
|
|
return retval
|