diff --git a/royalpack/commands/__init__.py b/royalpack/commands/__init__.py index 7f9ff50f..375e2600 100644 --- a/royalpack/commands/__init__.py +++ b/royalpack/commands/__init__.py @@ -32,6 +32,7 @@ from .eval import EvalCommand from .exec import ExecCommand from .trivia import TriviaCommand from .steampowered import SteampoweredCommand +from .steammatch import SteammatchCommand # Enter the commands of your Pack here! available_commands = [ @@ -68,6 +69,7 @@ available_commands = [ FunkwhaleCommand, TriviaCommand, SteampoweredCommand, + SteammatchCommand ] # Don't change this, it should automatically generate __all__ diff --git a/royalpack/commands/steammatch.py b/royalpack/commands/steammatch.py new file mode 100644 index 00000000..32a105d6 --- /dev/null +++ b/royalpack/commands/steammatch.py @@ -0,0 +1,101 @@ +from typing import * +from royalnet.commands import * +from royalnet.utils import * +from ..tables import Alias, Steam +import steam +import requests.exceptions + + +class SteamGame: + def __init__(self, + appid=None, + name=None, + playtime_forever=None, + img_icon_url=None, + img_logo_url=None, + has_community_visible_stats=None, + playtime_windows_forever=None, + playtime_mac_forever=None, + playtime_linux_forever=None, + playtime_2weeks=None): + self.appid = appid + self.name = name + self.playtime_forever = playtime_forever + self.img_icon_url = img_icon_url + self.img_logo_url = img_logo_url + self.has_community_visible_stats = has_community_visible_stats + self.playtime_windows_forever = playtime_windows_forever + self.playtime_mac_forever = playtime_mac_forever + self.playtime_linux_forever = playtime_linux_forever + self.playtime_2weeks = playtime_2weeks + + def __hash__(self): + return self.appid + + def __eq__(self, other): + if isinstance(other, SteamGame): + return self.appid == other.appid + return False + + def __str__(self): + return self.name + + def __repr__(self): + return f"<{self.__class__.__qualname__} {self.appid} ({self.name})>" + + +class SteammatchCommand(Command): + name: str = "steammatch" + + description: str = "Vedi quali giochi hai in comune con uno o più membri!" + + syntax: str = "{royalnet_username}+" + + def __init__(self, interface: CommandInterface): + super().__init__(interface) + if "Steam" not in self.config or "web_api_key" not in self.config["Steam"]: + raise ConfigurationError("[c]Steam.web_api_key[/c] config option is missing!") + self._api = steam.WebAPI(self.config["Steam"]["web_api_key"]) + + async def run(self, args: CommandArgs, data: CommandData) -> None: + users = [] + + author = await data.get_author(error_if_none=True) + users.append(author) + + for arg in args: + user = await asyncify(Alias.find_by_alias, self.alchemy, data.session, arg) + users.append(user) + + if len(users) < 2: + raise InvalidInputError("Devi specificare almeno un altro utente!") + + shared_games: Optional[set] = None + for user in users: + user_games = set() + if len(user.steam) == 0: + raise UserError(f"{user} non ha un account Steam registrato!") + for steam_account in user.steam: + steam_account: Steam + try: + response = await asyncify(self._api.IPlayerService.GetOwnedGames, + steamid=steam_account._steamid, + include_appinfo=True, + include_played_free_games=True, + appids_filter=0) + except requests.exceptions.HTTPError: + raise ExternalError(f"L'account Steam di {user} è privato!") + games = response["response"]["games"] + for game in games: + user_games.add(SteamGame(**game)) + if shared_games is None: + shared_games = user_games + else: + shared_games = shared_games.intersection(user_games) + + message_rows = [f"🎮 Giochi in comune tra {andformat([str(user) for user in users], final=' e ')}:"] + for game in sorted(list(shared_games), key=lambda g: g.name): + message_rows.append(f"- {game}") + + message = "\n".join(message_rows) + await data.reply(message) diff --git a/royalpack/commands/steampowered.py b/royalpack/commands/steampowered.py index 304fd994..cfa5186f 100644 --- a/royalpack/commands/steampowered.py +++ b/royalpack/commands/steampowered.py @@ -11,7 +11,7 @@ class SteampoweredCommand(Command): description: str = "Connetti il tuo account di Steam!" - syntax: str = "{profile}" + syntax: str = "{profile_url}" def __init__(self, interface: CommandInterface): super().__init__(interface) @@ -23,12 +23,16 @@ class SteampoweredCommand(Command): string = f"ℹ️ [b]{account.persona_name}[/b]\n" \ f"{account.profile_url}\n" \ f"\n" \ - f"SteamID: [c]{account.steam_id}[/c]\n" \ - f"Created on: {account.account_creation_date}\n" + f"SteamID: [c]{account.steamid.as_32}[/c]\n" \ + f"SteamID2: [c]{account.steamid.as_steam2}[/c]\n" \ + f"SteamID3: [c]{account.steamid.as_steam3}[/c]\n" \ + f"SteamID64: [c]{account.steamid.as_64}[/c]\n" \ + f"\n" \ + f"Created on: [b]{account.account_creation_date}[/b]\n" return string async def _update(self, account: Steam): - response = await asyncify(self._api.ISteamUser.GetPlayerSummaries_v2, steamids=account.steam_id) + response = await asyncify(self._api.ISteamUser.GetPlayerSummaries_v2, steamids=account._steamid) r = response["response"]["players"][0] account.persona_name = r["personaname"] account.profile_url = r["profileurl"] @@ -39,12 +43,13 @@ class SteampoweredCommand(Command): async def run(self, args: CommandArgs, data: CommandData) -> None: author = await data.get_author() if len(args) > 0: - steamid = args.match("([0-9]+)")[0] - response = await asyncify(self._api.ISteamUser.GetPlayerSummaries_v2, steamids=steamid) + url = args.joined() + steamid64 = await asyncify(steam.steamid.steam64_from_url, url) + response = await asyncify(self._api.ISteamUser.GetPlayerSummaries_v2, steamids=steamid64) r = response["response"]["players"][0] steam_account = self.alchemy.get(Steam)( user=author, - steam_id=int(steamid), + _steamid=int(steamid64), persona_name=r["personaname"], profile_url=r["profileurl"], avatar=r["avatarfull"], diff --git a/royalpack/commands/userinfo.py b/royalpack/commands/userinfo.py index 125ae951..3efa2bfb 100644 --- a/royalpack/commands/userinfo.py +++ b/royalpack/commands/userinfo.py @@ -3,6 +3,7 @@ from royalnet.commands import * from royalnet.utils import * from royalnet.backpack.tables import User from sqlalchemy import func +from ..tables.aliases import Alias class UserinfoCommand(Command): @@ -19,27 +20,18 @@ class UserinfoCommand(Command): if username is None: user: User = await data.get_author(error_if_none=True) else: - found: Optional[User] = await asyncify( - data.session - .query(self.alchemy.get(User)) - .filter(func.lower(self.alchemy.get(User).username) == func.lower(username)) - .one_or_none - ) + found: Optional[User] = await asyncify(Alias.find_by_alias, self.alchemy, data.session, username) if not found: raise InvalidInputError("Utente non trovato.") else: user = found r = [ - f"ℹ️ [b]{user.username}[/b] (ID: {user.uid})", + f"ℹ️ [b]{user.username}[/b]", f"{user.role}", "", ] - if user.fiorygi: - r.append(f"{user.fiorygi}") - r.append("") - # Bios are a bit too long # if user.bio: # r.append(f"{user.bio}") @@ -50,6 +42,9 @@ class UserinfoCommand(Command): for account in user.discord: r.append(f"{account}") + for account in user.steam: + r.append(f"{account}") + for account in user.leagueoflegends: r.append(f"{account}") @@ -61,7 +56,13 @@ class UserinfoCommand(Command): r.append("") if user.trivia_score: - r.append(f"Trivia: [b]{user.trivia_score.correct_answers}[/b] risposte corrette / " - f"{user.trivia_score.total_answers} totali") + r.append(f"Ha [b]{user.trivia_score.score:.0f}[/b] punti trivia, avendo risposto correttamente a" + f" [b]{user.trivia_score.correct_answers}[/b] domande su" + f" [b]{user.trivia_score.total_answers}[/b].") + r.append("") + + if user.fiorygi: + r.append(f"Ha [b]{user.fiorygi}[/b].") + r.append("") await data.reply("\n".join(r)) diff --git a/royalpack/tables/aliases.py b/royalpack/tables/aliases.py index 2a1c99ec..0f4ec1f8 100644 --- a/royalpack/tables/aliases.py +++ b/royalpack/tables/aliases.py @@ -21,6 +21,13 @@ class Alias: def royal(self): return relationship("User", backref="aliases") + @classmethod + def find_by_alias(cls, alchemy, session, alias: str): + result = session.query(alchemy.get(cls)).filter_by(alias=alias.lower()).one_or_none() + if result is not None: + result = result.royal + return result + def __repr__(self): return f"" diff --git a/royalpack/tables/steam.py b/royalpack/tables/steam.py index a1dfddfc..4d165ec7 100644 --- a/royalpack/tables/steam.py +++ b/royalpack/tables/steam.py @@ -1,6 +1,7 @@ from sqlalchemy import * from sqlalchemy.orm import relationship, backref from sqlalchemy.ext.declarative import declared_attr +import steam class Steam: @@ -15,9 +16,13 @@ class Steam: return relationship("User", backref=backref("steam")) @declared_attr - def steam_id(self): + def _steamid(self): return Column(BigInteger, primary_key=True) + @property + def steamid(self): + return steam.SteamID(self._steamid) + @declared_attr def persona_name(self): return Column(String) @@ -39,7 +44,7 @@ class Steam: return Column(DateTime) def __repr__(self): - return f"" + return f"" def __str__(self): - return f"steam:{self.steam_id}" + return f"[c]steam:{self._steamid}[/c]"