def get_matchup(champion_name, enemy_name, patch_version): champion = StaticDataContext.get_object_from_name( Champion, champion_name) enemy = StaticDataContext.get_object_from_name(Champion, enemy_name) versions = StaticDataContext.get_api_version()['versions'][:5] versions = list( map(lambda x: re.sub(xy_version_regex, r"\1", x), versions)) if champion is None or enemy is None: raise errors.BadRequest('Both champions must be provided') with DBManager.create_session_scope(expire_on_commit=False) as session: matchup_avg = session.query(MatchupAverages).filter( (MatchupAverages.champion == champion['id']) & (MatchupAverages.enemy == enemy['id'])) if patch_version is None: matchup_avg = matchup_avg.filter( MatchupAverages.patch_version == versions[0]) else: matchup_avg = matchup_avg.filter( MatchupAverages.patch_version == patch_version) matchup_avg = matchup_avg.first() if matchup_avg is None: raise errors.MatchupNotFound('Matchup not Found') matchup_avg = matchup_avg return dict(MatchContext.process_matchup(matchup_avg), champion=champion, enemy=enemy, versions=versions)
def populate_matchups(cls, limit=50, region='EUNE'): session = DBManager.create_session(expire_on_commit=False) matches = session.query(QueuedMatch).filter_by(region=region).filter( ~exists().where(QueuedMatch.id == CheckedMatch.id))\ .limit(limit).all() for match in matches: payload = { 'api_key': RIOT_API_KEY, 'includeTimeline': 'true', } log.debug('Fetching info for match {0}'.format(match.id)) url = 'https://{0}.api.pvp.net/api/lol/{0}'.format(region.lower()) endpoint = '/{0}/match/{1}'.format(api_versions['match'], match.id) try: result = riot_api.get(url=url, endpoint=endpoint, payload=payload) except ForbiddenException: continue except NotFound: continue cls.populate_single_matchup(result) checked_match = CheckedMatch({ 'id': match.id, 'region': match.region, 'checked_at': datetime.now(), 'match_timestamp': match.match_timestamp }) session.merge(checked_match) session.commit()
def populate_static_table(endpoint='', model=None, payload={}, version=None): entity_name = model.__name__.lower() log.debug('Populating {0} table'.format(model.__tablename__)) try: results = riot_static_api.get(endpoint=endpoint, payload=payload) except ForbiddenException: return results_length = len(results['data'].keys()) log.info('Fetched {0} {1}s'.format(results_length, entity_name)) with DBManager.create_session_scope() as session: status_cnt = 0 for entity_data in results['data'].values(): status_cnt += 1 print('[*] Status {0}/{1}'.format(status_cnt, results_length), end='\r') _process_ctx = getattr(DataProcessContext, 'process_{0}_data'.format(entity_name)) if _process_ctx is None: raise Exception( 'No data process function for model {0} was ' 'defined'.format(entity_name)) _processed_data = _process_ctx(entity_data) session.merge( model(**dict(_processed_data, patch_version=version))) log.debug('Done!')
def populate_players(region='EUNE', league='challenger', player_limit=50): # Get a list with the top 50 challenger players (if any) log.debug('Fetching top {0} players from {1} in region ' '{2}'.format(player_limit, league, region)) payload = {'api_key': RIOT_API_KEY, 'type': 'RANKED_SOLO_5x5'} url = 'https://{0}.api.pvp.net/api/lol/{0}'.format(region.lower()) endpoint = '/{0}/league/{1}'.format(api_versions['league'], league) try: ladder = riot_api.get(url=url, endpoint=endpoint, payload=payload) except ForbiddenException: return if len(ladder.keys()) == 0: return players = [ player for _, player in sorted([(player['leaguePoints'], player) for player in ladder['entries']], reverse=True, key=lambda x: x[0])[:player_limit] ] results_length = len(players) log.debug('[+] Fetched {0} players'.format(results_length)) with DBManager.create_session_scope() as session: for player in players: player_data = { 'id': player.get('playerOrTeamId'), 'region': region.lower(), 'tier': league.lower(), 'name': player.get('playerOrTeamName') } session.merge(ProPlayer(player_data)) log.debug('[+] Done!')
def get_object_from_name(model, name): with DBManager.create_session_scope(expire_on_commit=False) as session: ret = session.query(model).filter_by(name=name).first() if ret is not None: ret = ret.serialize() return ret return None
def get_objects_id_dict(model): with DBManager.create_session_scope(expire_on_commit=False) as session: ret = { str(o.id): o.serialize() for o in session.query(model).all() } return ret return None
def populate_queued_matches(limit=50, region='EUNE'): matches = {} log.debug('Collecting match information for each player. This might ' 'take a while...') with DBManager.create_session_scope(expire_on_commit=False) as session: payload = { 'api_key': RIOT_API_KEY, 'rankedQueues': 'TEAM_BUILDER_DRAFT_RANKED_5x5,RANKED_SOLO_5x5', 'seasons': 'SEASON2016,PRESEASON2016,PRESEASON2017', 'beginIndex': 0, 'endIndex': limit } latest_game = session.query(QueuedMatch).filter_by( region=region).order_by( QueuedMatch.match_timestamp.desc()).first() if latest_game is not None: payload['beginTime'] = latest_game.match_timestamp players = session.query(ProPlayer).all() url = 'https://{0}.api.pvp.net/api/lol/{0}'.format(region.lower()) for player in players: endpoint = '/{0}/matchlist/by-summoner/{1}'\ .format(api_versions['matchlist'], player.id) try: result = riot_api.get(url=url, endpoint=endpoint, payload=payload) except ForbiddenException: continue except NotFound: continue for match in result.get("matches", []): match_data = { 'id': match.get('matchId'), 'region': match.get('region'), 'match_timestamp': match.get('timestamp'), 'added_at': datetime.now() } session.merge(QueuedMatch(match_data)) session.commit()
from onevone.db_manager import DBManager from onevone import log from flask import Flask app = Flask(__name__) app.config.from_object('onevone.configuration.DevelopmentConfig') DBManager.init(app.config['DATABASE_URI']) from onevone import urls
def populate_averages(cls): with DBManager.create_session_scope(expire_on_commit=False) as session: champions = [ c.id for c in session.query(Champion).options(load_only( 'id')).order_by('id').all() ] total_champs = len(champions) versions = StaticDataContext.get_api_version()['versions'][:2] for version in versions: # Keep only the 2 majon numbers of the patch version patch_version = re.sub(r'^((?:\d+\.*){2})((?:\.\d*)*)$', r'\1', version) log.debug('Calculating Averages for patch : {0}'.format( patch_version)) for i in range(0, total_champs): print('Status {0}/{1}'.format(i, total_champs), end='\r') for j in range(0, total_champs): if i == j: continue idA = champions[i] idB = champions[j] matchups = session.query(Matchup, SpellTimeLine, ItemTimeline)\ .join(SpellTimeLine, (Matchup.id == SpellTimeLine.matchup_id)) \ .join(ItemTimeline, (Matchup.id == ItemTimeline.matchup_id)) \ .filter( (Matchup.champion == idA) & (Matchup.enemy == idB) & (Matchup.checked == False) & (Matchup.patch_version == patch_version) ).all() total_games = len(matchups) if total_games == 0: continue matchups, spell_timelines, item_timelines = zip( *matchups) kills = 0 deaths = 0 assists = 0 damage_dealt = 0 wins = 0 creep_score = 0 duration = 0 for matchup in matchups: if matchup.won: wins += 1 kills += matchup.kills deaths += matchup.deaths assists += matchup.assists damage_dealt += matchup.damage_dealt creep_score += matchup.creep_score duration += matchup.duration sts = [st.spell_timeline for st in spell_timelines] avg_spells = cls.timelines_average(data=sts) its = [it.item_timeline for it in item_timelines] avg_items = cls.timelines_average(data=its) mus = [(mu.masteries, mu.runes, mu.summoners) for mu in matchups] masteries, runes, summoners = zip(*mus) avg_masteries = cls.timelines_average(masteries) avg_runes = cls.timelines_average(runes) summoners = [sorted(s.split(',')) for s in summoners] avg_summoners = cls.timelines_average(summoners) matchup_avgs = { 'champion': idA, 'enemy': idB, 'total_games': total_games, 'kills': float(kills / total_games), 'deaths': float(deaths / total_games), 'assists': float(assists / total_games), 'creep_score': float(creep_score / total_games), 'damage_dealt': float(damage_dealt / total_games), 'duration': float(duration / total_games), 'wins': wins, 'item_timeline': avg_items, 'spell_timeline': avg_spells, 'masteries': avg_masteries, 'runes': avg_runes, 'summoners': avg_summoners, 'patch_version': patch_version } try: matchup_avgs = MatchupAverages(matchup_avgs) session.merge(matchup_avgs) session.commit() except IntegrityError: session.rollback() log.warn('Average already {0}vs{1} patch {2}' 'exists. Updating'.format( idA, idB, patch_version)) prev_matchup = session.query( MatchupAverages).filter_by( champion=idA, enemy=idB, patch_version=patch_version).first() session.merge(matchup_avgs) session.commit()
def populate_single_matchup(data): try: frames = data['timeline']['frames'] except KeyError: log.error('No timeline data') return item_timelines = defaultdict(list) spell_timelines = defaultdict(list) for frame in frames: for ev in frame.get('events', []): if ev['eventType'] == 'ITEM_PURCHASED': item_timelines[ev['participantId']].append(ev['itemId']) elif ev['eventType'] == 'SKILL_LEVEL_UP': spell_timelines[ev['participantId']].append( ev['skillSlot']) if data["teams"][0]["winner"] is True: winning_team = data["teams"][0]["teamId"] else: winning_team = data["teams"][1]["teamId"] results = {} # results = { # 'JUNGLE': { # 'vs': [{participant1}, {participant2}]. # 'won': 202 -> champion id # }, # ... # } for participant in data.get('participants', []): lane_role = '{0}:{1}'.format(participant['timeline']['lane'], participant['timeline']['role']) if results.get(lane_role) is None: results[lane_role] = {'vs': [], 'won': None} results[lane_role]['vs'].append(participant) if participant['teamId'] == winning_team: results[lane_role]['won'] = participant['championId'] with DBManager.create_session_scope(expire_on_commit=False) as session: for lane_role, result in results.items(): # Sometimes there are no matchups if len(result['vs']) != 2: continue for idx, participant in enumerate(result['vs']): pid = participant['participantId'] enemy = result['vs'][(idx + 1) % 2] try: masteries = [ '{0}:{1}'.format(m['masteryId'], m['rank']) for m in participant['masteries'] ] runes = [ '{0}:{1}'.format(r['runeId'], r['rank']) for r in participant['runes'] ] summoners = '{0},{1}'.format(participant['spell1Id'], participant['spell2Id']) stats = participant.get('stats') matchup_data = { 'champion': participant['championId'], 'enemy': enemy['championId'], 'won': participant['championId'] == result['won'], 'kills': stats.get('kills'), 'deaths': stats.get('deaths'), 'assists': stats.get('assists'), 'creep_score': stats.get('minionsKilled'), 'damage_dealt': stats.get('totalDamageDealtToChampions'), 'duration': data.get('matchDuration'), 'patch_version': '.'.join(data.get('matchVersion').split('.')[:2]), 'masteries': masteries, 'runes': runes, 'summoners': summoners, } except KeyError: continue matchup = Matchup(matchup_data) session.add(matchup) session.flush() session.refresh(matchup) item_timeline_data = { 'matchup_id': matchup.id, 'item_timeline': item_timelines[pid] } item_timeline = ItemTimeline(item_timeline_data) spell_timeline_data = { 'matchup_id': matchup.id, 'spell_timeline': spell_timelines[pid] } spell_timeline = SpellTimeLine(spell_timeline_data) session.add(item_timeline) session.add(spell_timeline) session.commit()
def generate_static_images(cls): IMAGES_PER_LINE = 10 IMAGE_SIZE = 64 data = {} with DBManager.create_session_scope() as session: version = cls.get_api_version()['versions'][0] ddragon_api = RESTClient(base_url='http://ddragon.' 'leagueoflegends.com/cdn', log=log) from PIL import Image import io models = [SummonerSpell, Champion, Mastery, Item, Rune] for model in models: if model == SummonerSpell: model_name = 'spell' else: model_name = model.__name__.lower() query_set = session.query(model)\ .order_by('id')\ .all() CONCAT_WIDTH = IMAGES_PER_LINE * IMAGE_SIZE CONCAT_HEIGHT = (int(len(query_set) / IMAGES_PER_LINE) + 1) * IMAGE_SIZE sprite_img = Image.new('RGB', (CONCAT_WIDTH, CONCAT_HEIGHT)) data[model_name] = [] i, j = 0, 0 for entry in query_set: data[model_name].append({ 'id': entry.id, 'xoffset_small': -j * 32, 'yoffset_small': -i * 32, 'xoffset_big': -j * 64, 'yoffset_big': -i * 64, }) endpoint = '/{0}/img/{1}/{2}'.format( entry.patch_version, model_name, entry.image_blob) try: image_stream = ddragon_api.get( endpoint=endpoint, response_type='byte-stream') except Exception: continue image = Image.open(image_stream).resize( (IMAGE_SIZE, IMAGE_SIZE)) sprite_img.paste(image, (j * IMAGE_SIZE, i * IMAGE_SIZE)) j += 1 if j == IMAGES_PER_LINE: i += 1 j = 0 splash_blob = getattr(entry, 'splash_blob', None) if splash_blob is not None: endpoint = '/{0}/loading/{1}'.format( model_name, splash_blob) try: image_stream = ddragon_api.get( url='http://ddragon.leagueoflegends.com/cdn/img' .format(model_name, splash_blob), endpoint=endpoint, response_type='byte-stream') except Exception: continue image = Image.open(image_stream) image.save('./onevone/static/images/' + model_name + '-splash/' + splash_blob) sprite_img.save('./onevone/static/images/' + model_name + '_sprite.png') sprite_img_s = sprite_img.copy().resize( (int(CONCAT_WIDTH * 0.5), int(CONCAT_HEIGHT * 0.5))) sprite_img_s.save('./onevone/static/images/' + model_name + '_sprite.small.png') sprite_grey = sprite_img.copy().convert('L') sprite_grey.save('./onevone/static/images/' + model_name + '_sprite_grey.png') from jinja2 import Environment with open('./onevone/static/css/static_data.template.css', 'r') as t,\ open('./onevone/static/css/static_data.css', 'w+') as f: template = t.read() f.write( Environment(trim_blocks=True, lstrip_blocks=True).from_string(template).render( data=data))
def decorator(*args, **kwargs): cache_key = self.key_format.format(*args, **kwargs) ret = cache.get(cache_key) if ret is None: ret = f(*args, **kwargs) if ret is not None: cache.set(cache_key, json.dumps(ret)) if self.timeout > 0: cache.expire(cache_key, self.timeout) return ret return json.loads(ret.decode('utf-8')) return decorator DBManager.init(os.environ['ONEVONE_PRODUCTION_DB']) RIOT_GLOBAL_API = 'https://global.api.pvp.net/api/lol' RIOT_API_KEY = os.environ['RIOT_API_KEY'] api_versions = { 'static': 'v1.2', 'matchlist': 'v2.2', 'league': 'v2.5', 'match': 'v2.2', } xy_version_regex = r'^((?:\d+\.*){2})((?:\.\d*)*)$' xyz_version_regex = r'^((?:\d+\.*){3})((?:\.\d*)*)$' static_url = '{0}/static-data/eune/{1}'.format(RIOT_GLOBAL_API, api_versions['static']) riot_static_api = RESTClient(base_url=static_url, log=log) riot_api = RESTClient(log=log)
from onevone import log __all__ = [ 'ChampionAPI', 'MasteryAPI', 'RunesAPI', 'ItemsAPI', 'MatchupAPI', 'SummonerSpellAPI', 'Index', 'About', 'Contact', 'MatchupView', ] view_session = DBManager.create_session(expire_on_commit=False) def create_error_response(message, error_code): data = json.dumps({'error': True, 'message': message}) response = Response(status=error_code, mimetype='application/json') response.set_data(data) return response def create_success_response(payload): data = json.dumps({ 'data': payload, }) response = Response(status=200, mimetype='application/json') response.set_data(data)