async def main(argv): global wg, wi, WG_APP_ID # set the directory for the script current_dir = os.getcwd() os.chdir(os.path.dirname(sys.argv[0])) ## Default options: OPT_DB = False OPT_EXTENDED = False OPT_HIST = False OPT_STAT_FUNC = 'player' OPT_WORKERS_N = 10 WG_ACCOUNT = None # format: nick@server, where server is either 'eu', 'ru', 'na', 'asia' or 'china'. # China is not supported since WG API stats are not available there WG_ID = None # WG account_id in integer format. # WG_ACCOUNT will be used to retrieve the account_id, but it can be set directly too # WG_APP_ID = WG_APP_ID WG_RATE_LIMIT = 10 ## WG standard. Do not edit unless you have your ## own server app ID, it will REDUCE the performance ## VERY unlikely you have a DB set up DB_SERVER = 'localhost' DB_PORT = 27017 DB_SSL = False DB_CERT_REQ = ssl.CERT_NONE DB_AUTH = 'admin' DB_NAME = 'BlitzStats' DB_USER = '******' DB_PASSWD = 'PASSWORD' DB_CERT = None DB_CA = None try: ## Read config if os.path.isfile(FILE_CONFIG): config = configparser.ConfigParser() config.read(FILE_CONFIG) try: if 'OPTIONS' in config.sections(): configOptions = config['OPTIONS'] # WG account id of the uploader: # # Find it here: https://developers.wargaming.net/reference/all/wotb/account/list/ OPT_DB = configOptions.getboolean('opt_DB', OPT_DB) OPT_EXTENDED = configOptions.getboolean('opt_analyzer_extended', OPT_EXTENDED) OPT_HIST = configOptions.getboolean('opt_analyzer_hist', OPT_HIST) OPT_STAT_FUNC = configOptions.get('opt_analyzer_stat_func', fallback=OPT_STAT_FUNC) OPT_WORKERS_N = configOptions.getint('opt_analyzer_workers', OPT_WORKERS_N) except (KeyError, configparser.NoSectionError) as err: bu.error(exception=err) try: if 'ANALYZER' in config.sections(): configAnalyzer = config['ANALYZER'] histogram_fields_str = configAnalyzer.get('histogram_buckets', None) if histogram_fields_str != None: set_histogram_buckets(json.loads(histogram_fields_str)) except (KeyError, configparser.NoSectionError) as err: bu.error(exception=err) try: if 'WG' in config.sections(): configWG = config['WG'] WG_ID = configWG.getint('wg_id', WG_ID) WG_ACCOUNT = configWG.get('wg_account', WG_ACCOUNT) WG_APP_ID = configWG.get('wg_app_id', WG_APP_ID) WG_RATE_LIMIT = configWG.getint('wg_rate_limit', WG_RATE_LIMIT) except (KeyError, configparser.NoSectionError) as err: bu.error(exception=err) try: if 'DATABASE' in config.sections(): configDB = config['DATABASE'] DB_SERVER = configDB.get('db_server', DB_SERVER) DB_PORT = configDB.getint('db_port', DB_PORT) DB_SSL = configDB.getboolean('db_ssl', DB_SSL) DB_CERT_REQ = configDB.getint('db_ssl_req', DB_CERT_REQ) DB_AUTH = configDB.get('db_auth', DB_AUTH) DB_NAME = configDB.get('db_name', DB_NAME) DB_USER = configDB.get('db_user', DB_USER) DB_PASSWD = configDB.get('db_password', DB_PASSWD) DB_CERT = configDB.get('db_ssl_cert_file', DB_CERT) DB_CA = configDB.get('db_ssl_ca_file', DB_CA) except (KeyError, configparser.NoSectionError) as err: bu.error(exception=err) parser = ErrorCatchingArgumentParser(description='Analyze Blitz replay JSON files from WoTinspector.com. Use \'upload_wotb_replays.py\' to upload the replay files first.') parser.add_argument('--output', default='plain', choices=['plain', 'db'], help='Select output mode: plain text or database') parser.add_argument('-id', dest='account_id', type=int, default=WG_ID, help='WG account_id to analyze') parser.add_argument('-a', '--account', type=str, default=WG_ACCOUNT, help='WG account nameto analyze. Format: ACCOUNT_NAME@SERVER') parser.add_argument('-x', '--extended', action='store_true', default=OPT_EXTENDED, help='Print Extended stats') parser.add_argument('-X', '--extra_categories', choices=BattleRecordCategory.get_extra_categories(), default=None, nargs='*', help='Print Extended categories') parser.add_argument('--hist', action='store_true', default=OPT_HIST, help='Print player histograms (WR/battles)') parser.add_argument('--stat_func', default=OPT_STAT_FUNC, choices=STAT_FUNC.keys(), help='Select how to calculate for ally/enemy performance: tank-tier stats, global player stats') parser.add_argument('-u', '--url', action='store_true', default=False, help='Print replay URLs') parser.add_argument('--tankfile', type=str, default='tanks.json', help='JSON file to read Tankopedia from. Default is "tanks.json"') parser.add_argument('--mapfile', type=str, default='maps.json', help='JSON file to read Blitz map names from. Default is "maps.json"') parser.add_argument('-o','--outfile', type=str, default='-', metavar="OUTPUT", help='File to write results. Default STDOUT') parser.add_argument('--db', action='store_true', default=OPT_DB, help='Use DB - You are unlikely to have it') parser.add_argument('--filters', type=str, default=None, help='Filters for DB based analyses. MongoDB find() filter JSON format.') parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose mode') parser.add_argument('-s', '--silent', action='store_true', default=False, help='Silent mode') parser.add_argument('files', metavar='FILE1 [FILE2 ...]', type=str, nargs='+', help='Files/dirs to read. Use \'-\' for STDIN, "db:" for database') try: args = parser.parse_args() except Exception as err: raise bu.set_log_level(args.silent, args.verbose, args.debug) bu.set_progress_step(250) # Set the frequency of the progress dots. wg = WG(WG_APP_ID, args.tankfile, args.mapfile, stats_cache=True, rate_limit=WG_RATE_LIMIT) wi = WoTinspector(rate_limit=10) if args.account != None: args.account_id = await wg.get_account_id(args.account) bu.debug('WG account_id: ' + str(args.account_id)) BattleRecord.set_fields(args.extended) #### Connect to MongoDB (TBD) bu.debug('DB_SERVER: ' + DB_SERVER) bu.debug('DB_PORT: ' + str(DB_PORT)) bu.debug('DB_SSL: ' + "True" if DB_SSL else "False") bu.debug('DB_AUTH: ' + DB_AUTH) bu.debug('DB_NAME: ' + DB_NAME) client = None db = None if args.db: try: client = motor.motor_asyncio.AsyncIOMotorClient(DB_SERVER,DB_PORT, authSource=DB_AUTH, username=DB_USER, password=DB_PASSWD, ssl=DB_SSL, ssl_cert_reqs=DB_CERT_REQ, ssl_certfile=DB_CERT, tlsCAFile=DB_CA) db = client[DB_NAME] args.account_id = None bu.debug('Database connection initiated') except Exception as err: bu.error("Could no initiate DB connection: Disabling DB", err) args.db = False pass else: bu.debug('No DB in use') # rebase file arguments due to moving the working directory to the script location args.files = bu.rebase_file_args(current_dir, args.files) try: replayQ = asyncio.Queue(maxsize=1000) reader_tasks = [] # Make replay Queue scanner_task = asyncio.create_task(mk_replayQ(replayQ, args, db)) bu.debug('Replay scanner started') # Start tasks to process the Queue for i in range(OPT_WORKERS_N): reader_tasks.append(asyncio.create_task(replay_reader(replayQ, i, args))) bu.debug('ReplayReader ' + str(i) + ' started') bu.debug('Waiting for the replay scanner to finish') await asyncio.wait([scanner_task]) # bu.debug('Scanner finished. Waiting for replay readers to finish the queue') await replayQ.join() await asyncio.sleep(0.1) bu.debug('Replays read. Cancelling Readers and analyzing results') for task in reader_tasks: task.cancel() await asyncio.sleep(0.1) results = [] players = set() for res in await asyncio.gather(*reader_tasks): results.extend(res[0]) players.update(res[1]) if len(players) == 0: raise Exception("No players found to fetch stats for. No replays found?") (player_stats, stat_id_map) = await process_player_stats(players, OPT_WORKERS_N, args, db) bu.verbose('') bu.debug('Number of player stats: ' + str(len(player_stats))) teamresults = calc_team_stats(results, player_stats, stat_id_map, args) process_battle_results(teamresults, args) if args.hist: print('\nPlayer Histograms______', end='', flush=True) process_player_dist(results, player_stats, stat_id_map) bu.debug('Finished. Cleaning up..................') except Exception as err: bu.error(exception=err) except UserWarning as err: bu.verbose(str(err)) pass except Exception as err: bu.error(exception=err) finally: ## Need to close the aiohttp.session since Python destructors do not support async methods... if wg != None: await wg.close() if wi != None: await wi.close() return None
async def main(argv): global wg, wi TASK_N = 7 parser = argparse.ArgumentParser(description='ANalyze Blitz replay JSONs from WoTinspector.com') parser.add_argument('--output', default='plain', choices=['json', 'plain', 'db'], help='Select output mode: JSON, plain text or database') parser.add_argument('-id', dest='accountID', type=int, default=None, help='WG account_id to analyze') parser.add_argument('-a', '--account', dest='account', type=str, default=None, help='WG account nameto analyze. Format: ACCOUNT_NAME@SERVER') parser.add_argument('-u', '--url', dest= 'url', action='store_true', default=False, help='Print replay URLs') parser.add_argument('--tankfile', type=str, default='tanks.json', help='JSON file to read Tankopedia from. Default is "tanks.json"') parser.add_argument('--mapfile', type=str, default='maps.json', help='JSON file to read Blitz map names from. Default is "maps.json"') parser.add_argument('-o','--outfile', type=str, default='-', metavar="OUTPUT", help='File to write results. Default STDOUT') parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose mode') parser.add_argument('files', metavar='FILE1 [FILE2 ...]', type=str, nargs='+', help='Files to read. Use \'-\' for STDIN"') args = parser.parse_args() bu.setVerbose(args.verbose) bu.setDebug(args.debug) wg = WG(WG_appID, args.tankfile, args.mapfile) wi = WoTinspector() if args.account != None: args.accountID = await wg.getAccountID(args.account) bu.debug('WG account_id: ' + str(args.accountID)) try: replayQ = asyncio.Queue() reader_tasks = [] # Make replay Queue scanner_task = asyncio.create_task(mkReplayQ(replayQ, args.files)) # Start tasks to process the Queue for i in range(TASK_N): reader_tasks.append(asyncio.create_task(replayReader(replayQ, i, args))) bu.debug('Task ' + str(i) + ' started') bu.debug('Waiting for the replay scanner to finish') await asyncio.wait([scanner_task]) bu.debug('Scanner finished. Waiting for replay readers to finish the queue') await replayQ.join() bu.debug('Replays read. Cancelling Readers and analyzing results') for task in reader_tasks: task.cancel() results = [] playerstanks = set() for res in await asyncio.gather(*reader_tasks): results.extend(res[0]) playerstanks.update(res[1]) player_stats = await processTankStats(playerstanks, TASK_N) bu.verbose('') results = calcTeamStats(results, player_stats, args.accountID) processStats(results, args) finally: ## Need to close the aiohttp.session since Python destructors do not support async methods... await wg.close() await wi.close() return None
async def main(argv): global wg, wi parser = argparse.ArgumentParser(description='Post replays(s) to WoTinspector.com and retrieve battle data') parser.add_argument('--output', default='single', choices=['file', 'files', 'db'] , help='Select output mode: single/multiple files or database') parser.add_argument('-id', dest='accountID', type=int, default=WG_ID, help='WG account_id') parser.add_argument('-a', '--account', dest='account', type=str, default=None, help='Uploader\'s WG account name. Format: ACCOUNT_NAME@SERVER') parser.add_argument('-t','--title', type=str, default=None, help='Title for replays. Use NN for continous numbering. Default is filename-based numbering') parser.add_argument('-p', '--private', dest="private", action='store_true', default=False, help='Set replays private on WoTinspector.com') parser.add_argument('--tasks', dest='N_tasks', type=int, default=10, help='Number of worker threads') parser.add_argument('--tankopedia', type=str, default='tanks.json', help='JSON file to read Tankopedia from. Default: "tanks.json"') parser.add_argument('--mapfile', type=str, default='maps.json', help='JSON file to read Blitz map names from. Default: "maps.json"') parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode') parser.add_argument('-v', '--verbose', action='store_true', default=True, help='Verbose mode') parser.add_argument('-s', '--silent', action='store_true', default=False, help='Silent mode') parser.add_argument('files', metavar='FILE1 [FILE2 ...]', type=str, nargs='+', help='Files to read. Use \'-\' for STDIN"') args = parser.parse_args() bu.setVerbose(args.verbose) bu.setDebug(args.debug) if args.silent: bu.setVerbose(False) wg = WG(WG_appID, args.tankopedia, args.mapfile) wi = WoTinspector() if args.account != None: args.accountID = await wg.getAccountID(args.account) bu.debug('WG account_id: ' + str(args.accountID)) if args.accountID == None: args.accountID = 0 try: queue = asyncio.Queue() tasks = [] # Make replay Queue tasks.append(asyncio.create_task(mkReplayQ(queue, args.files, args.title))) # Start tasks to process the Queue for i in range(args.N_tasks): tasks.append(asyncio.create_task(replayWorker(queue, i, args.accountID, args.private))) bu.debug('Task ' + str(i) + ' started') bu.debug('Waiting for the replay scanner to finish') await asyncio.wait([tasks[0]]) bu.debug('Scanner finished. Waiting for workers to finish queue') await queue.join() bu.debug('Cancelling workers') for task in tasks: task.cancel() bu.debug('Waiting for workers to cancel') await asyncio.gather(*tasks, return_exceptions=True) bu.verbose(str(REPLAY_N) + ' replays: ' + str(REPLAY_N - SKIPPED_N) + ' uploaded, ' + str(SKIPPED_N) + ' skipped') except KeyboardInterrupt: print('Ctrl-c pressed ...') sys.exit(1) finally: ## Need to close the aiohttp.session since Python destructors do not support async methods... await wg.session.close() await wi.close() return None
async def main(argv): global wg # set the directory for the script os.chdir(os.path.dirname(sys.argv[0])) ## Read config BLITZAPP_FOLDER = '.' try: if os.path.isfile(FILE_CONFIG): config = configparser.ConfigParser() config.read(FILE_CONFIG) configOptions = config['EXTRACT_TANKOPEDIA'] BLITZAPP_FOLDER = configOptions.get('blitz_app_dir', BLITZAPP_FOLDER) except: pass parser = argparse.ArgumentParser( description='Extract Tankopedia data from Blitz game files') parser.add_argument('blitz_app_base', type=str, nargs='?', metavar="BLITZAPP_FOLDER", default=BLITZAPP_FOLDER, help='Base dir of the Blitz App files') parser.add_argument('tanks', type=str, default='tanks.json', nargs='?', metavar="TANKS_FILE", help='File to write Tankopedia') parser.add_argument('maps', type=str, default='maps.json', nargs='?', metavar='MAPS_FILE', help='File to write map names') arggroup = parser.add_mutually_exclusive_group() arggroup.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode') arggroup.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose mode') arggroup.add_argument('-s', '--silent', action='store_true', default=False, help='Silent mode') args = parser.parse_args() bu.set_log_level(args.silent, args.verbose, args.debug) wg = WG() tasks = [] for nation in wg.NATIONS: tasks.append( asyncio.create_task(extract_tanks(args.blitz_app_base, nation))) tanklist = [] for tanklist_tmp in await asyncio.gather(*tasks): tanklist.extend(tanklist_tmp) tank_strs, map_strs = await read_user_strs(args.blitz_app_base) json_data = None userStrs = {} tanks = {} if os.path.exists(args.tanks): try: async with aiofiles.open(args.tanks) as infile: json_data = json.loads(await infile.read()) userStrs = json_data['userStr'] tanks = json_data['data'] except Exception as err: bu.error('Unexpected error when reading file: ' + args.tanks + ' : ' + str(err)) async with aiofiles.open(args.tanks, 'w', encoding="utf8") as outfile: new_tanks, new_userStrs = await convert_tank_names(tanklist, tank_strs) # merge old and new tankopedia tanks.update(new_tanks) userStrs.update(new_userStrs) tankopedia = collections.OrderedDict() tankopedia['status'] = 'ok' tankopedia['meta'] = {"count": len(tanks)} tankopedia['data'] = tanks tankopedia['userStr'] = userStrs bu.verbose_std('New tankopedia \'' + args.tanks + '\' contains ' + str(len(tanks)) + ' tanks') await outfile.write( json.dumps(tankopedia, ensure_ascii=False, indent=4, sort_keys=False)) if args.maps != None: maps = {} if os.path.exists(args.maps): try: async with aiofiles.open(args.maps) as infile: maps = json.loads(await infile.read()) except Exception as err: bu.error('Unexpected error when reading file: ' + args.maps + ' : ' + str(err)) # merge old and new map data maps.update(map_strs) async with aiofiles.open(args.maps, 'w', encoding="utf8") as outfile: bu.verbose_std('New maps file \'' + args.maps + '\' contains ' + str(len(maps)) + ' maps') await outfile.write( json.dumps(maps, ensure_ascii=False, indent=4, sort_keys=True)) return None
async def main(argv): global wg parser = argparse.ArgumentParser( description='Extract Tankopedia data from Blitz game files') parser.add_argument('blitzAppBase', type=str, metavar="BLITZAPP_FOLDER", default=".", help='Base dir of the Blitz App files') parser.add_argument('tanks', type=str, default='tanks.json', nargs='?', metavar="TANKS_FILE", help='File to write Tankopedia') parser.add_argument('maps', type=str, default='maps.json', nargs='?', metavar='MAPS_FILE', help='File to write map names') parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose mode') args = parser.parse_args() bu.setVerbose(args.verbose) bu.setDebug(args.debug) wg = WG() tasks = [] for nation in wg.nations: tasks.append( asyncio.create_task(extractTanks(args.blitzAppBase, nation))) tanklist = [] for tanklist_tmp in await asyncio.gather(*tasks): tanklist.extend(tanklist_tmp) tank_strs, map_strs = await readUserStrs(args.blitzAppBase) json_data = None userStrs = {} tanks = {} if os.path.exists(args.tanks): try: async with aiofiles.open(args.tanks) as infile: json_data = json.loads(await infile.read()) userStrs = json_data['userStr'] tanks = json_data['data'] except Exception as err: bu.error('Unexpected error when reading file: ' + args.tanks + ' : ' + str(err)) async with aiofiles.open(args.tanks, 'w', encoding="utf8") as outfile: new_tanks, new_userStrs = await convertTankNames(tanklist, tank_strs) # merge old and new tankopedia tanks.update(new_tanks) userStrs.update(new_userStrs) tankopedia = collections.OrderedDict() tankopedia['status'] = 'ok' tankopedia['meta'] = {"count": len(tanks)} tankopedia['data'] = tanks tankopedia['userStr'] = userStrs await outfile.write( json.dumps(tankopedia, ensure_ascii=False, indent=4, sort_keys=False)) if args.maps != None: maps = {} if os.path.exists(args.maps): try: async with aiofiles.open(args.maps) as infile: maps = json.loads(await infile.read()) except Exception as err: bu.error('Unexpected error when reading file: ' + args.maps + ' : ' + str(err)) # merge old and new map data maps.update(map_strs) async with aiofiles.open(args.maps, 'w', encoding="utf8") as outfile: await outfile.write( json.dumps(maps, ensure_ascii=False, indent=4, sort_keys=True)) return None
async def main(argv): global wg, wi # set the directory for the script os.chdir(os.path.dirname(sys.argv[0])) ## Read config config = configparser.ConfigParser() config.read(FILE_CONFIG) configOptions = config['OPTIONS'] OPT_WORKERS_N = configOptions.getint('opt_uploader_workers', 5) configWG = config['WG'] # WG account id of the uploader: # # Find it here: https://developers.wargaming.net/reference/all/wotb/account/list/ WG_ID = configWG.getint('wg_id', None) ## WG API Rules limit 10 request / sec. Higher rate of requests will return errors ==> extra delay WG_RATE_LIMIT = configWG.getint('wg_rate_limit', 10) parser = argparse.ArgumentParser( description= 'Post replays(s) to WoTinspector.com and retrieve battle data') parser.add_argument('-id', dest='accountID', type=int, default=WG_ID, help='WG account_id') parser.add_argument( '-a', '--account', dest='account', type=str, default=None, help='Uploader\'s WG account name. Format: ACCOUNT_NAME@SERVER') parser.add_argument( '-t', '--title', type=str, default=None, help= 'Title for replays. Use NN for continous numbering. Default is filename-based numbering' ) parser.add_argument('-p', '--private', dest="private", action='store_true', default=False, help='Set replays private on WoTinspector.com') parser.add_argument( '--tankopedia', type=str, default='tanks.json', help='JSON file to read Tankopedia from. Default: "tanks.json"') parser.add_argument( '--mapfile', type=str, default='maps.json', help='JSON file to read Blitz map names from. Default: "maps.json"') parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose mode') parser.add_argument('-s', '--silent', action='store_true', default=False, help='Silent mode') parser.add_argument('files', metavar='FILE1 [FILE2 ...]', type=str, nargs='+', help='Files to read. Use \'-\' for STDIN"') args = parser.parse_args() bu.set_verbose(args.verbose) bu.set_log_level(args.silent, args.verbose, args.debug) wg = WG(WG_appID, args.tankopedia, args.mapfile) wi = WoTinspector(rate_limit=WG_RATE_LIMIT) if args.account != None: args.accountID = await wg.get_account_id(args.account) bu.debug('WG account_id: ' + str(args.accountID)) if args.accountID == None: args.accountID = 0 try: queue = asyncio.Queue() tasks = [] # Make replay Queue tasks.append( asyncio.create_task(mkReplayQ(queue, args.files, args.title))) # Start tasks to process the Queue for i in range(OPT_WORKERS_N): tasks.append( asyncio.create_task( replayWorker(queue, i, args.accountID, args.private))) bu.debug('Task ' + str(i) + ' started') bu.debug('Waiting for the replay scanner to finish') await asyncio.wait([tasks[0]]) bu.debug('Scanner finished. Waiting for workers to finish queue') await queue.join() bu.debug('Cancelling workers') for task in tasks: task.cancel() bu.debug('Waiting for workers to cancel') await asyncio.gather(*tasks, return_exceptions=True) bu.verbose( str(REPLAY_N) + ' replays: ' + str(REPLAY_N - SKIPPED_N - ERROR_N) + ' uploaded, ' + str(SKIPPED_N) + ' skipped, ' + str(ERROR_N) + ' errors') except KeyboardInterrupt: print('Ctrl-c pressed ...') sys.exit(1) finally: ## Need to close the aiohttp.session since Python destructors do not support async methods... await wg.session.close() await wi.close() return None
async def main(argv): global wg, wi current_dir = os.getcwd() # set the directory for the script os.chdir(os.path.dirname(sys.argv[0])) # options defaults OPT_WORKERS_N = 5 WG_ID = None WG_ACCOUNT = None # format: nick@server, where server is either 'eu', 'ru', 'na', 'asia' or 'china'. # China is not supported since WG API stats are not available there WG_RATE_LIMIT = 10 try: ## Read config if os.path.isfile(FILE_CONFIG): bu.debug('Reading config file: ' + FILE_CONFIG) config = configparser.ConfigParser() config.read(FILE_CONFIG) try: if 'UPLOADER' in config.sections(): configUploader = config['UPLOADER'] OPT_WORKERS_N = configUploader.getint('opt_workers', OPT_WORKERS_N) except (KeyError, configparser.NoSectionError) as err: bu.error(exception=err) try: if 'WG' in config.sections(): configWG = config['WG'] # WG account id of the uploader: # # Find it here: https://developers.wargaming.net/reference/all/wotb/account/list/ WG_ID = configWG.getint('wg_id', WG_ID) WG_ACCOUNT = configWG.get('wg_account', WG_ACCOUNT) ## WG API Rules limit 10 request / sec. Higher rate of requests will return errors ==> extra delay WG_RATE_LIMIT = configWG.getint('wg_rate_limit', WG_RATE_LIMIT) except (KeyError, configparser.NoSectionError) as err: bu.error(exception=err) except Exception as err: bu.error(exception=err) parser = argparse.ArgumentParser(description='Post replays(s) to WoTinspector.com and retrieve replay data as JSON') parser.add_argument('-id', dest='accountID', type=int, default=WG_ID, help='WG account_id') parser.add_argument('-a', '--account', dest='account', type=str, default=WG_ACCOUNT, help='Uploader\'s WG account name. Format: ACCOUNT_NAME@SERVER') parser.add_argument('-t','--title', type=str, default=None, help='Title for replays. Use "NN" for continous numbering. Default is automatic naming') parser.add_argument('-p', '--private', dest="private", action='store_true', default=False, help='Set replays private on WoTinspector.com') parser.add_argument('--tankopedia', type=str, default='tanks.json', help='JSON file to read Tankopedia from. Default: "tanks.json"') parser.add_argument('--mapfile', type=str, default='maps.json', help='JSON file to read Blitz map names from. Default: "maps.json"') parser.add_argument('-d', '--debug', action='store_true', default=False, help='Debug mode') parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose mode') parser.add_argument('-s', '--silent', action='store_true', default=False, help='Silent mode') parser.add_argument('files', metavar='FILE1 [FILE2 ...]', type=str, nargs='+', help='Files to read. Use \'-\' for STDIN"') args = parser.parse_args() bu.set_verbose(args.verbose) bu.set_log_level(args.silent, args.verbose, args.debug) wg = WG(WG_appID, args.tankopedia, args.mapfile) wi = WoTinspector(rate_limit=WG_RATE_LIMIT) if args.account != None: args.accountID = await wg.get_account_id(args.account) bu.debug('WG account_id: ' + str(args.accountID)) if args.accountID == None: args.accountID = 0 try: queue = asyncio.Queue() # rebase file arguments due to moving the working directory to the script location args.files = bu.rebase_file_args(current_dir, args.files) tasks = [] # Make replay Queue tasks.append(asyncio.create_task(mkReplayQ(queue, args.files, args.title))) # Start tasks to process the Queue for i in range(OPT_WORKERS_N): tasks.append(asyncio.create_task(replayWorker(queue, i, args.accountID, args.private))) bu.debug('Task ' + str(i) + ' started') bu.debug('Waiting for the replay scanner to finish') await asyncio.wait([tasks[0]]) bu.debug('Scanner finished. Waiting for workers to finish queue') await queue.join() bu.debug('Cancelling workers') for task in tasks: task.cancel() bu.debug('Waiting for workers to cancel') await asyncio.gather(*tasks, return_exceptions=True) bu.verbose_std(str(REPLAY_N) + ' replays: ' + str(REPLAY_N - SKIPPED_N - ERROR_N) + ' uploaded, ' + str(SKIPPED_N) + ' skipped, ' + str(ERROR_N) + ' errors') except KeyboardInterrupt: print('Ctrl-c pressed ...') sys.exit(1) finally: ## Need to close the aiohttp.session since Python destructors do not support async methods... await wg.session.close() await wi.close() return None