import argparse import datetime import logging import os, os.path import sys import jinja2 import smashgg import version # ============================================================================= def main(): # ------------------------------------------------------------------------- parser = argparse.ArgumentParser() subparsers = parser.add_subparsers( dest = "command", help = "commands", ) parser.add_argument( "--proxy", "-p", default = None, help = "the proxy to use" ) parser.add_argument( "--token", "-t", default = None, help = "the authentication token to use" ) # ------------------------------------------------------------------------- top8_parser = subparsers.add_parser( "top8", ) top8_parser.add_argument( "tournament", default = None, help = "The tournament slug or id", ) top8_parser.add_argument( "--resourcesdir", "-RD", default = "res", help = "The directories containing images and templates resources", ) top8_parser.add_argument( "--templatesdir", "-TD", default = "templates", help = "The local result templates directory", ) top8_parser.add_argument( "--template", "-T", default = "rebootlyon", help = "The local result template to use", ) top8_parser.add_argument( "--lkrz-file", "-f", default = None, help = "The lkrz file in which the results are stored ; if it " \ "does not exist, one will be created from the smashgg data", ) top8_parser.add_argument( "--outfile", "-o", default = None, help = "The SVG local result file to output to ; defaults to " \ "./tournament-slug.svg", ) # ------------------------------------------------------------------------- parser.add_argument( "--verbose", "-v", default = 0, action = "count", help = "increase verbosity" ) parser.add_argument( "--version", "-V", default = False, action = "store_true", help = "show version number" ) # ------------------------------------------------------------------------- args = parser.parse_args() # Set log level # ------------------------------------------------------------------------- log = logging.getLogger(version.NAME) log.setLevel(logging.DEBUG) log_handler_console = logging.StreamHandler() log_handler_console.setLevel(logging.WARNING) if(args.verbose >= 2): log_handler_console.setLevel(logging.DEBUG) elif(args.verbose >=1): log_handler_console.setLevel(logging.INFO) else: log_handler_console.setLevel(logging.WARNING) log_formatter_console = logging.Formatter("%(name)s:%(levelname)s: %(message)s") log_handler_console.setFormatter(log_formatter_console) log.addHandler(log_handler_console) # Print version if required # ------------------------------------------------------------------------- if args.version: print(version.VERSION_NAME) sys.exit(0) # ------------------------------------------------------------------------- if args.command not in [ "top8" ]: parser.print_help() sys.exit(1) # ------------------------------------------------------------------------- if args.command == "top8": try: with open(args.lkrz_file, "r") as f: # TODO parse config file to fill tournament & top_players log.error("config file loading is not implemened yet") raise NotImplementedError except: # Get infos from smash.gg and write the config file tournament, top_players = getTournamentTop( id_or_slug = args.tournament, top = 8, token = args.token, proxy = args.proxy, log = log, ) if tournament is None or top_players is None: log.error("Could not load data from smash.gg") sys.exit(1) lkrz_data = "\n".join( [ tournament.conf() ] \ + list(map( lambda p:p.conf(), top_players.values(), )) ) if args.lkrz_file is None: args.lkrz_file = "{}.lkrz".format(tournament.slug) with open(args.lkrz_file, "w", encoding="utf8") as f: f.write(lkrz_data) # Template rendering log.info("Génération du SVG en utilisant le template") jj2_env = jinja2.Environment( loader = jinja2.FileSystemLoader( os.path.join( args.resourcesdir, args.templatesdir, ) ) ) jj2_tpl = jj2_env.get_template( os.path.join( args.template, "template.svg.j2", ) ) context = { "tournament": tournament, "players" : sorted( top_players.values(), key = lambda p: p.placement, ), "imgdir_ssbu_chars": os.path.join( args.resourcesdir, "ssbu", "Super Smash Bros Ultimate", "Fighter Portraits", ), } if args.outfile is None: args.outfile = "{}.svg".format(tournament.slug) jj2_tpl.stream(context).dump( args.outfile ) # ----------------------------------------------------------------------------- def getTournamentTop( id_or_slug, top=8, token = "", proxy = None, log=None): """Returns a tuple : the smashgg.Tournament object and a list of the top smashgg.Player in that tournament.""" # ------------------------------------------------------------------------- # Select the right event (the one with the most entrants or the most sets) def selectBiggestEvent(data, log=None): try: event = data["events"][0] except: log.error("No event found in data") log.debug(data) return None try: numEntrants = event["numEntrants"] except KeyError: numEntrants = event["standings"]["pageInfo"]["total"] for e in data["events"]: try: ne = e["numEntrants"] except KeyError: ne = e["standings"]["pageInfo"]["total"] if ne > numEntrants: event = e numEntrants = ne log.info("Selected Event '{}' with {} entrants" \ .format( event["name"], numEntrants, )) return event # ------------------------------------------------------------------------- data = None try: data = smashgg.run_query( query_name = "getTournamentTopById", variables = { "id" : int(id_or_slug), # If this fails, it's a slug "top": top, }, token = token, proxy = proxy, log = log, ) except ValueError: data = smashgg.run_query( query_name = "getTournamentTopBySlug", variables = { "slug" : id_or_slug, "top": top, }, token = token, proxy = proxy, log = log, ) try: tournament_data = data["tournament"] except: log.error("Failed to load Tournaments") return None,None if tournament_data is None: log.error("Failed to load Tournament") return None,None event = selectBiggestEvent(tournament_data, log) if event is None : return None,None # Get the tournament tournament = smashgg.Tournament( id = tournament_data["id"], slug = tournament_data["slug"], name = tournament_data["name"], startAt = \ datetime.datetime. \ fromtimestamp(tournament_data["startAt"]), numEntrants = event["standings"]["pageInfo"]["total"], venueAddress = tournament_data["venueAddress"], venueName = tournament_data["venueName"], city = tournament_data["city"], countryCode = tournament_data["countryCode"], hashtag = tournament_data["hashtag"], ) # Get the top players top_players = {} standings = event["standings"]["nodes"] for standing in standings : seeding = None for seed in standing["entrant"]["seeds"]: # Take the seeding from the phase with *all* Event entrants if seed["phase"]["numSeeds"] == tournament.numEntrants: seeding = seed["groupSeedNum"] participant_data = standing["entrant"]["participants"][0] try: twitterHandle = participant_data \ ["player"] \ ["user"] \ ["authorizations"] \ [0] \ ["externalUsername"] except TypeError: twitterHandle = None player = smashgg.Player( id = standing["entrant"]["id"], prefix = participant_data["prefix"], gamerTag = participant_data["gamerTag"], placement = standing["placement"], seeding = seeding, twitterHandle = twitterHandle, ) top_players[player.id] = player # ------------------------------------------------------------------------- # Now, we need to find which characters those top players chose data = None data = smashgg.run_query( query_name = "getCharsByTournamentIdAndEntrantIds", variables = { "tournamentId" : int(tournament.id), "entrantIds": [ id for id in top_players.keys() ], }, token = token, proxy = proxy, log = log, ) try: tournament_data = data["tournament"] except: log.error("Failed to load Tournament") return None,None if tournament_data is None: log.error("Failed to load Tournament") return None,None event = selectBiggestEvent(tournament_data, log) if event is None : return None,None # TODO check that sets number is < to hardcoded 100 max value (cf query) sets = event["sets"]["nodes"] for s in sets: try: for g in s["games"]: winnerId = g["winnerId"] for slct in g["selections"]: if slct["selectionType"] == "CHARACTER": eid = slct["entrant"]["id"] try: top_players[eid].add_character_selection( character = slct["selectionValue"], win = (winnerId == eid), ) except KeyError: pass except TypeError: # If some games or selections are null, this can happen continue # Return the data return tournament, top_players # ============================================================================= if __name__ == '__main__': main()