# {{{ Imports import discord, requests, json, time, os, hypixel_bot_tools.errors, tempfile from discord.ext import commands from hypixel_bot_tools import * #the modular aspect of HypiBot from cairosvg import svg2png hypierror = hypixel_bot_tools.errors # }}} # {{{ Get token try: from Token import HYPIXEL_API_KEY, DISCORD_API_KEY, PREFIX except ImportError: print("\tFATAL!\tCould not load Token.py file. Please change the Token.example.py to your liking and make sure that it is valid Python syntax") raise # }}} # {{{ Setup bot bot = commands.Bot(command_prefix=PREFIX) @bot.event async def on_ready(): print("Ready for action Rider sir!") print("PAW PATROL! PAW PATROL! WE'LL BE THERE ON THE DOUBLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE") #sorry # }}} # {{{ pre-gettext wrapper def _(string): return string #so that we don't have to do a major refac when (if) we add gettext # }}} # {{{ Command @bot.command(name="uuid") async def uuid(ctx, username): """ Gets the UUID of a player. based on their username. """ status = await ctx.send(_("Loading from API...")) req = getuuid(username) await status.edit(content=_("Player UUID: %s") % req) @bot.command() async def ping(ctx): '''I'm a good person! TOTALLY not stolen from https://www.programcreek.com/python/?code=Der-Eddy%2Fdiscord_bot%2Fdiscord_bot-master%2Fcogs%2Futility.py''' ping = ctx.message pong = await ctx.send('**:ping_pong:** Pong!') delta = pong.created_at - ping.created_at delta = int(delta.total_seconds() * 1000) hi1 = time.time() await pong.edit(content=f':ping_pong: Pong! ({delta} ms)\n*Finding Discord message edit latency...*') hi2 = time.time() await pong.edit(content=f':ping_pong: Pong! ({delta} ms)\n*Discord message edit latency: {hi2 - hi1}*') @bot.command(name="hypixel",aliases=("h","stats")) async def hypixel(ctx,player,ConvertToUUID=True, v2=True): """ Checks overall stats Change ConvertToUUID to False if you want to pass in the UUID, example: `$h False` instead of `$h `. """ if checkapi(HYPIXEL_API_KEY) is False: await ctx.send(_(":warning: Ran out of API queries per minute. Please wait a little while before continuing...")) return False thing = await ctx.send(_("Fetching player data... If this message doesn't go away, the bot is _definitely_ not broken. :soundsrightbud:")) try: contents = overall(HYPIXEL_API_KEY,player,ConvertToUUID) except hypierror.InvalidPlayer: await thing.edit(content=_(":warning: Invalid player!"));raise lenfriends = countfriends(friends(HYPIXEL_API_KEY,player,ConvertToUUID)) try: statusAPI = contents['settings']['apiSession'] except KeyError: statusAPI = True if not statusAPI: statusAPI_Message = _("API access disabled") currentStatus_Message = _("Unavailable - API access disabled") else: item = status(HYPIXEL_API_KEY,player,ConvertToUUID)['session'] statusAPI_Message = item['online'] #todo: i'm a bit dubious about this code {{{ try: for i in ("gameType","mode","map"): try: item[i] except KeyError: if i == "gameType": raise #set current status message to offline item[i] = "N/A" currentStatus_Message = f"{item['gameType']} ({_('mode')} {item['mode']}); {_('on map')} {item['map']}" onlinecolour = "green" except KeyError: currentStatus_Message = _("Offline") onlinecolour = "#454545" # }}} endtodo for i in ("karma",): #these are fields that might not exist try: contents[i] except KeyError: contents[i] = 0 continue #todo: move this to an if not v2 em = discord.Embed( title=f"{contents['displayname']}'{_('s Hypixel Stats')}", footer=_("Thanks for using Hypibot!")) val = f"{round(RawXPToLevel(contents['networkExp']),2)} ({_('raw')} {int(contents['networkExp'])})" em.add_field(name=_("UUID"),value=getuuid(player),inline=True) em.add_field(name=_("Rank"), value=contents['rank'],inline=True) em.add_field(name=_("Network Level"),value=val,inline=True) em.add_field(name=_("Karma"),value=contents['karma'],inline=True) em.add_field(name=_("Friends"),value=lenfriends,inline=True) em.add_field(name="\u200b",value="\u200b",inline=True)#newline; \u200b is a zero width space that is allowed by dcord em.add_field(name=_("Online?"),value=statusAPI_Message,inline=True) em.add_field(name=_("Current Game"), value=currentStatus_Message,inline=True) with open("AnyConv.com__minecraft-2053886_960_7200.svg") as file: svg = file.read().format(uuid=getuuid(player), userhtml="""{rank} {displayname}""".format(rank=contents['rank'], displayname=contents['displayname']), exp=round(RawXPToLevel(contents['networkExp']),2), karma=contents['karma'], friends=lenfriends, onlinehtml=f'{currentStatus_Message}') #inject details with tempfile.TemporaryDirectory() as tmp: print(tmp) if v2: path = os.path.join(tmp, 'png.pngpng.png') #https://stackoverflow.com/a/45803022/9654083 svg2png(bytestring=svg, write_to=path) #https://stackoverflow.com/questions/6589358/convert-svg-to-png-in-python with open(path, "rb") as file: #https://stackoverflow.com/questions/60913131/how-to-send-a-image-with-discord-py file = discord.File(file, filename=path) await ctx.send("Player data down below.", file=file) await thing.delete() if v2 is False: #todo: move em's declaration to here, also use return up above instead of this await thing.edit(embed=em, content="Player data down below.") @bot.command() async def bedwars(ctx, player, ConvertToUUID=True): if checkapi(HYPIXEL_API_KEY) is False: #todo; use exceptions instead await ctx.send(_(":warning: Ran out of API queries per minute. Please wait a little while before continuing...")) return False try: contents = overall(HYPIXEL_API_KEY, player, ConvertToUUID=ConvertToUUID) except KeyError: raise InvalidPlayer data = contents['stats']['Bedwars'] em = discord.Embed( title=_("%s's Bedwars Stats" % contents['displayname']), footer=_("Thanks for using Hypibot!") ) em.add_field(name=_("Experience"), value=data['Experience'],inline=True) em.add_field(name=_("Coins"),value=data['coins'],inline=True) await ctx.send(embed=em) for i in ("eight_one","eight_two","three_three","two_four","four_four"): await ctx.send(bedwarsToHuman(i)) # }}} # Error handling {{{ @bot.event async def on_command_error(ctx, error): """ Does some stuff in case of cooldown error. Stolen from brewbot. _please don't kill me trm..._ (I am the one who added this code btw so it doesn't matter) """ if hasattr(ctx.command, 'on_error'): #https://gist.github.com/EvieePy/7822af90858ef65012ea500bcecf1612 return error = getattr(error, 'original', error) if isinstance(error, commands.CommandOnCooldown): potentialMessages = [f'This command is on cooldown, please wait {int(error.retry_after)}s.'] message = (random.choice(potentialMessages)) print('\nSomeone tried to do a command that was on cooldown') elif isinstance(error, commands.MissingRequiredArgument): strerror = str(error).split(' ')[0] message = _("You seem to be missing a required argument \"{strerror}\". Run `{PREFIX}help [command]` for more information.").format(PREFIX=PREFIX, strerror=strerror) elif isinstance(error, hypierror.HypixelApiDown): message = _("We couldn't contact the hypixel API. Is the service down?") elif isinstance(error, hypierror.InvalidPlayer): message = _("This seems to be an invalid player - it doesn't have an entry on Mojang's API.\nTry running {PREFIX}[command] {uuid} False to search by UUID instead. Run {PREFIX}help bedwars for more info.").format(PREFIX=PREFIX, uuid=error) elif isinstance(error, commands.errors.CommandNotFound): message = _("command not found. Try {PREFIX}help for a list!").format(PREFIX=PREFIX) else: message = "Unknown error !" em = discord.Embed(title=_("⚠️ Oops! ⚠️"), description=message) em.set_footer(text=error) await ctx.send(embed=em) raise(error) # }}} # {{{ Run bot if __name__ == "__main__": bot.run(DISCORD_API_KEY) # }}}