from typing import List
import aiohttp
from .exceptions import (GuildNotFound, InvalidKeyException,
NoStatusForPlayer, PixelException, PlayerNotFound,
PlayerNotInGuild)
from .gametypes import GameType
from .models import stats
from .models.boosters import Booster
from .models.friends import Friend
from .models.guilds import Guild, GuildMember, GuildTag, GuildRank
from .models.leaderboards import Leaderboard, LeaderboardMember
from .models.players import (PixelAchievements, Player, PlayerAchievements,
PlayerRank)
from .models.sessions import PlayerStatus
from .utils import clean_uuid, get_player_uuid
BASE_API_URL = "https://api.hypixel.net{}"
__all__ = ["PixelClient"]
[docs]class PixelClient:
"""
Asynchronus client for accessing Hypixel's API
"""
def __init__(self, api_key: str):
self._api_key = api_key
self._session = aiohttp.ClientSession()
self._achievements = PixelAchievements()
async def _request(self, route: str, method: str, params: dict=None):
async with self._session.request(method, BASE_API_URL.format(route), params=params) as r:
if not r.status == 200:
raise PixelException(
"An error occurred while making the request.\n"
"Status code: {0.status}.\n"
"Reason: {0.reason}".format(r)
)
data = await r.json()
if not data["success"]:
if data["cause"] == "Invalid API key!":
raise InvalidKeyException(data["cause"])
else:
raise PixelException("Error: {}".format(data["cause"]))
else:
return data
[docs] async def boosters(self) -> List[Booster]:
"""
Get a list of all boosters
Returns
-------
`list` of `Booster`
A list of all boosters in the queue
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
"""
data = await self._request(
"/boosters", "GET", params={"key": self._api_key}
)
raw_boosters = data["boosters"]
boosters = []
for r_b in raw_boosters:
boosters.append(Booster(
r_b["_id"], r_b["purchaserUuid"], r_b["amount"],
r_b["originalLength"], r_b["length"], r_b["gameType"],
r_b["dateActivated"], stacked=r_b.get("stacked", None)
))
return boosters
[docs] async def find_guild_by_name(self, name: str) -> str:
"""
Get the guild id for a guild with the specified name
Parameters
----------
name: str
The guild name
Returns
-------
str
The guild id
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
GuildNotFound
If no guild is found
"""
data = await self._request(
"/findGuild", "GET",
params={"key": self._api_key, "byName": name}
)
if data["guild"] is None:
raise GuildNotFound()
return data["guild"]
[docs] async def find_guild_by_uuid(self, uuid: str) -> str:
"""
Get the guild id for the specified player's guild
Parameters
----------
uuid: str
The player's uuid
Returns
-------
str
The guild id
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
PlayerNotInGuild
If no guild is found
"""
data = await self._request(
"/findGuild", "GET",
params={"key": self._api_key, "byUuid": clean_uuid(uuid)}
)
if data["guild"] is None:
raise PlayerNotInGuild()
return data["guild"]
[docs] async def friends(self, uuid: str) -> List[Friend]:
"""
Get friends of a player
Parameters
----------
uuid: str
The uuid of the player to get friends of
Returns
-------
`list` of `Friend`
A list of objects representing the player's friendships
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or if an error is returned in the response json
"""
data = await self._request(
"/friends", "GET",
params={"key": self._api_key, "uuid": clean_uuid(uuid)}
)
friends_list = []
for raw_friend in data["records"]:
friends_list.append(
Friend(
raw_friend["_id"],
raw_friend["uuidSender"],
raw_friend["uuidReceiver"],
raw_friend["started"]
)
)
return friends_list
[docs] async def guild(self, guild_id: str) -> Guild:
"""
Get a guild
Parameters
----------
guild_id: str
The id of the guild to look up
Returns
-------
Guild
The requested guild
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
GuildNotFound
If no guild is found
"""
data = await self._request(
"/guild", "GET",
params={"key": self._api_key, "id": guild_id}
)
if data["guild"] is None:
raise GuildNotFound()
guild = data["guild"]
members = []
for m in guild["members"]:
members.append(GuildMember(m))
tag = GuildTag(guild.get("tag", None), guild.get("tagColor", None))
guild_joinable = guild.get("joinable", False)
vip_count = guild.get("vipCount", 0)
mvp_count = guild.get("mvpCount", 0)
discord = guild.get("discord", None)
description = guild.get("description", None)
ranks = guild.get("ranks", None)
if ranks:
ranks = [GuildRank(r) for r in ranks]
preferred_games = guild.get("preferredGames", None)
if preferred_games:
preferred_games = [getattr(GameType, game) for game in preferred_games]
# banner = GuildBanner(
# guild["banner"]["Base"], guild["banner"]["Patterns"]
# )
return Guild(
guild["_id"], guild["created"], guild["exp"], discord, guild_joinable,
description, members, guild["name"], tag,
vip_count, mvp_count, ranks, preferred_games, guild.get("chatThrottle", 0),
guild.get("publiclyListed", False), guild.get("chatMute", 0)
)
[docs] async def leaderboards(self) -> List[Leaderboard]:
"""
Get all leaderboards
Returns
-------
`list` of `Leaderboard`
A list of all leaderboards
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
"""
data = await self._request(
"/leaderboards", "GET",
params={"key": self._api_key}
)
raw_leaderboards = data["leaderboards"]
leaderboard_list = []
for game, lbs in raw_leaderboards.items():
game_type = getattr(GameType, game)
for lb in lbs:
leaders = []
for l in lb["leaders"]:
leaders.append(LeaderboardMember(l))
leaderboard_list.append(
Leaderboard(
lb["path"], lb["prefix"], lb["count"],
leaders, lb["title"], game_type
)
)
return leaderboard_list
[docs] async def player_from_name(self, name: str) -> Player:
"""
Gets the player represented by the specified name
Parameters
----------
name: str
The name of the player
Returns
-------
Player
The specified player
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
PlayerNotFound
If the player doesn't exist or has never logged into the server
"""
uuid = await get_player_uuid(name, self._session)
if uuid is None:
raise PlayerNotFound()
return await self.player_from_uuid(uuid)
[docs] async def player_from_uuid(self, uuid: str) -> Player:
"""
Gets the player represented by the specified uuid
Parameters
----------
uuid: str
The uuid of the player
Returns
-------
Player
The specified player
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
PlayerNotFound
If the player doesn't exist or has never logged into the server
"""
data = await self._request(
"/player", "GET",
params={"key": self._api_key, "uuid": uuid}
)
if not bool(data["player"]):
raise PlayerNotFound()
player_data = data["player"]
player_rank = PlayerRank.from_player_data(player_data)
player_achievements = PlayerAchievements(player_data, self._achievements)
most_recent_game_type = getattr(GameType, player_data["mostRecentGameType"])
player_stats = []
for k, v in player_data["stats"].items():
player_stats.append(getattr(stats, k + "Stats")(v))
if "housingMeta" in player_data:
player_stats.append(stats.HousingStats(player_data["housingMeta"]))
return Player(
player_data["_id"], player_data["displayname"], player_data["firstLogin"],
player_data["lastLogin"], player_data["karma"], player_data["networkExp"],
player_rank, player_data["lastLogout"], player_achievements,
player_stats, most_recent_game_type
)
[docs] async def status(self, uuid: str) -> PlayerStatus:
"""
Get a player's current status
Parameters
----------
uuid: str
The player to get the status of
Returns
-------
PlayerStatus
The player's current status
Raises
------
InvalidKeyException
If the client's API key is not valid
PixelException
If an error occurs while making the request or is present in the response json
NoStatusForPlayer
If the specified player is offline or has this endpoint disabled via in-game settings
"""
data = await self._request(
"/status", "GET",
params={"key": self._api_key, "uuid": uuid}
)
if "session" in data and not data["session"]["online"]:
raise NoStatusForPlayer()
else:
return PlayerStatus(data["session"])