def _get_league_stats(category, qualifier, season, league_id, limit): stats = dict() player_pool = qualifier for leader_category, title, heading in LEAGUE_STATS[category]: stats[leader_category] = list() if league_id: league_id_optional = '&leagueId={}'.format(league_id) league_stats = 'leaguestats-{}-{}-{}-{}-{}'.format(category, leader_category, qualifier, season, league_id) else: league_id_optional = '' league_stats = 'leaguestats-{}-{}-{}-{}'.format(category, leader_category, qualifier, season) json_data = request.request_json(LEAGUE_LEADER_TYPES_URL.format(leaderCategories=leader_category, season=season, leagueIdOptional=league_id_optional, statGroup=category, playerPool=player_pool, limit=limit), league_stats, request.CACHE_SHORT) # Fill out/normalize the stats for each leader. This format is common across all the leader stats for league_leaders in json_data['leagueLeaders']: if 'leaders' not in league_leaders: continue for leader_info in league_leaders['leaders']: entry = {'rank': '', 'value': '', 'team': '', 'league': '', 'name': ''} if 'rank' in leader_info: entry['rank'] = leader_info['rank'] if 'value' in leader_info: entry['value'] = leader_info['value'] if 'team' in leader_info: entry['team'] = leader_info['team']['name'] if 'league' in leader_info: entry['league'] = leader_info['league']['name'] if 'person' in leader_info: entry['name'] = leader_info['person']['fullName'] stats[leader_category].append(entry) return stats
def display_division_standings(date_str, args_filter, rank_tag='divisionRank', header_tags=('league', 'division')): standings_type = 'byDivision' display_title = 'Division' if date_str is None: season_str = time.strftime("%Y") url_date_str = '' else: season_str = datetime.strftime(datetime.strptime(date_str, "%Y-%m-%d"), "%Y") url_date_str = '&date=' + date_str url = STANDINGS_URL.format(standings_type=standings_type, league_ids=mlbapidata.get_league_ids(args_filter), season=season_str, date=url_date_str) json_data = request.request_json(url, 'standings-{}-{}'.format(season_str, standings_type), cache_stale=request.CACHE_SHORT) border = displayutil.Border(use_unicode=config.UNICODE) outl = list() if display_title != '': outl.append(_get_title_header(display_title, border)) needs_line_hr = False if args_filter and args_filter in mlbapidata.DIVISION_FILTERS: _get_standings_display_for_record(outl, standings_type, _get_division_record(json_data['records'], args_filter), header_tags, rank_tag, border, needs_line_hr) else: for div in mlbapidata.DIVISION_FILTERS: div_record = _get_division_record(json_data['records'], div) if div_record: _get_standings_display_for_record(outl, standings_type, div_record, header_tags, rank_tag, border, needs_line_hr) print('\n'.join(outl))
def get_boxscore(game_pk): url = '{0}/api/v1/game/{1}/boxscore'.format( config.CONFIG.parser['api_url'], game_pk) json_data = request.request_json(url, 'boxscore-{}'.format(game_pk), cache_stale=request.CACHE_SHORT) return json_data
def _lookup_inning_timestamp_via_airings(game_rec, media_playback_id, inning, inning_half='top', overwrite_json=True): broadcast_start = None url = ( 'https://search-api-mlbtv.mlb.com/svc/search/v2/graphql/persisted/' 'query/core/Airings?variables={{%22partnerProgramIds%22%3A[%22{gamepk}%22]}}' ).format(gamepk=game_rec['game_pk']) json_data = request.request_json(url, 'airings', cache_stale=request.CACHE_SHORT) for airing in json_data['data']['Airings']: # there is a separate BROADCAST_START for each broadcast, so do lookup based on passed-in media id LOG.debug("airing['mediaId']: %s, media_playback_id: %s", str(airing['mediaId']), media_playback_id) if str(airing['mediaId']) != media_playback_id: continue if 'milestones' not in airing: LOG.warn( "_lookup_inning_timestamp_via_airings: no milestone data for airing: %s", str(airing)) continue for milestone in airing['milestones']: if milestone['milestoneType'] == "BROADCAST_START": for milestone_time in milestone['milestoneTime']: if str(milestone_time['type']) == 'absolute': broadcast_start_str = str( milestone_time['startDatetime']) broadcast_start = parser.parse( broadcast_start_str).timestamp() elif milestone['milestoneType'] == "INNING_START": milestone_inning = '1' milestone_inning_half = 'top' for keyword in milestone['keywords']: if str(keyword['type']) == 'inning': milestone_inning = str(keyword['value']) elif str(keyword['type']) == 'top': if str(keyword['value']) != 'true': milestone_inning_half = 'bottom' if milestone_inning == inning and milestone_inning_half == inning_half: # we found it for milestone_time in milestone['milestoneTime']: if str(milestone_time['type']) == 'absolute': inning_start_timestamp_str = milestone_time[ 'startDatetime'] # inning_start_timestamp_str = str(play['about']['startTime']) inning_start_timestamp = parser.parse( inning_start_timestamp_str).timestamp() LOG.info("Found inning start: %s", inning_start_timestamp_str) LOG.debug("Milestone data: %s", str(milestone)) return broadcast_start, inning_start_timestamp, inning_start_timestamp_str LOG.warn("Could not locate '%s %s' inning", inning_half, inning) return broadcast_start, None, None
def _get_person_stats(person_ids, category, roster_type, season): if category == 'all': groups = '[hitting,fielding,pitching]' else: groups = category json_data = request.request_json(MULTI_PERSON_STATS_URL.format(personIds=person_ids, groups=groups, season=season), 'person-stats-{}-{}-{}-{}'.format(groups, roster_type, season, str(person_ids)), request.CACHE_SHORT) return json_data
def _get_roster(team_id, roster_type, season): json_data = request.request_json(ROSTER_URL.format(teamId=team_id, rosterType=roster_type, season=season), 'roster-{}-{}-{}'.format(team_id, roster_type, season), cache_stale=request.CACHE_DAY) roster = dict() for person in json_data['roster']: person_id = str(person['person']['id']) roster[person_id] = dict() roster[person_id]['fullName'] = person['person']['fullName'] roster[person_id]['link'] = person['person']['link'] roster[person_id]['jerseyNumber'] = person['jerseyNumber'] roster[person_id]['position'] = person['position']['abbreviation'] roster[person_id]['status'] = person['status']['code'] return roster
def get_team_dict(season): if not season: season = get_current_season() json_data = request.request_json(TEAMS_URL.format(season=season), 'teams-' + season, cache_stale=request.CACHE_DAY) global TEAM_DICT if season in TEAM_DICT: return TEAM_DICT[season] TEAM_DICT[season] = dict() for team in json_data['teams']: TEAM_DICT[season][team['id']] = { 'name': team['name'], # San Diego Padres 'abbreviation': team['abbreviation'].lower(), # SD 'teamName': team['teamName'], # Padres 'teamCode': team['teamCode'], # sdn 'fileCode': team['fileCode'], # sd 'shortName': team['shortName'], # San Diego 'leagueId': team['league']['id'], 'divisionId': team['division']['id'], } # print(str(TEAM_DICT)) return TEAM_DICT[season]
def _get_games_by_date(self, date_str=None): if date_str is None: date_str = time.strftime("%Y-%m-%d") # https://statsapi.mlb.com/api/v1/schedule?sportId=1&startDate=2018-03-26&endDate=2018-03-26&hydrate=schedule.teams,schedule.linescore,schedule.game.content.media.epg # hydrate = 'hydrate=schedule.teams,schedule.linescore,schedule.game.content.media.epg' hydrate = 'hydrate=broadcasts(all),game(content(all),editorial(preview,recap)),linescore,team,probablePitcher(note)' # hydrate = 'hydrate=linescore,team,game(content(summary,media(epg),editorial(preview,recap),highlights(highlights(items))))' # "&hydrate=linescore,team,game(content(summary,media(epg),editorial(preview,recap),highlights(highlights(items))))" # hydrate = 'hydrate=linescore,team,game(content(summary,media(epg)),tickets)' url = '{0}/api/v1/schedule?sportId=1&startDate={1}&endDate={1}&{2}'.format( config.CONFIG.parser['api_url'], date_str, hydrate) json_data = request.request_json(url, 'gamedata-{}'.format(date_str), cache_stale=request.CACHE_SHORT) game_records = dict() # we return this dictionary if json_data['dates'] is None or len(json_data['dates']) < 1: LOG.debug("_get_games_by_date: no game data for %s", date_str) return None for game in json_data['dates'][0]['games']: # LOG.debug('game: {}'.format(game)) game_pk_str = str(game['gamePk']) game_records[game_pk_str] = dict() game_rec = game_records[game_pk_str] game_rec['game_pk'] = game_pk_str game_rec['abstractGameState'] = str( game['status']['abstractGameState']) # Preview, Live, Final game_rec['codedGameState'] = str( game['status'] ['codedGameState']) # is something like: F, O, C, I # is something like: Scheduled, Live, Final, In Progress, Critical, Postponed: game_rec['detailedState'] = str(game['status']['detailedState']) game_rec['doubleHeader'] = str(game['doubleHeader']) game_rec['gameNumber'] = str(game['gameNumber']) game_rec['mlbdate'] = parser.parse(str(game['gameDate'])) # Issue #23 handle resumed games if 'resumeDate' in game: game_rec['resumeDate'] = parser.parse(str(game['resumeDate'])) if 'resumedFrom' in game: game_rec['resumedFrom'] = parser.parse(str( game['resumedFrom'])) if 'gamesInSeries' in game: game_rec['gamesInSeries'] = str(game['gamesInSeries']) game_rec['seriesGameNumber'] = str(game['seriesGameNumber']) else: game_rec['gamesInSeries'] = "0" game_rec['seriesGameNumber'] = "0" game_rec['linescore'] = dict() if 'linescore' in game: game_rec['linescore']['raw'] = game['linescore'] if 'Delayed' in game_rec['detailedState']: game_rec['linescore']['currentInning'] = str( game_rec['detailedState']) game_rec['linescore'][ 'currentInningOrdinal'] = 'Not Started' game_rec['linescore']['inningState'] = '' elif 'currentInning' in game['linescore']: game_rec['linescore']['currentInning'] = str( game['linescore']['currentInning']) else: game_rec['linescore']['currentInningOrdinal'] = '0' if 'currentInningOrdinal' in game['linescore']: game_rec['linescore']['currentInningOrdinal'] = str( game['linescore']['currentInningOrdinal']) if 'inningState' in game['linescore']: game_rec['linescore']['inningState'] = str( game['linescore']['inningState'])[:3] else: game_rec['linescore']['inningState'] = str( game['linescore']['inningHalf'])[:3] else: game_rec['linescore'][ 'currentInningOrdinal'] = 'Not Started' game_rec['linescore']['inningState'] = '' else: game_rec['linescore']['currentInning'] = 'n/a' game_rec['linescore']['inningState'] = '' game_rec['linescore']['currentInningOrdinal'] = game_rec[ 'detailedState'] for teamtype in ('home', 'away'): # pprint.pprint(game['teams']) game_rec[teamtype] = dict() # seems to be two different formats for away/home team info(!) if 'name' in game['teams'][teamtype][ 'team'] and 'abbrev' in game['teams'][teamtype][ 'team']['name']: game_rec[teamtype] = { 'abbrev': str(game['teams'][teamtype]['team']['name'] ['abbrev']).lower(), 'display': str(game['teams'][teamtype]['team']['name'] ['display']), 'brief': str(game['teams'][teamtype]['team']['name']['brief']), 'full': str(game['teams'][teamtype]['team']['name']['full']), 'league': str(game['teams'][teamtype]['league']), 'division': str(game['teams'][teamtype]['division']), } elif 'abbreviation' in game['teams'][teamtype]['team']: game_rec[teamtype] = { 'abbrev': str(game['teams'][teamtype]['team'] ['abbreviation']).lower(), 'display': str(game['teams'][teamtype]['team']['shortName']), 'brief': str(game['teams'][teamtype]['team']['teamName']), 'full': str(game['teams'][teamtype]['team']['name']), 'league': 'n/a', 'division': 'n/a', } else: LOG.error("Unexpected game['teams'] for teamtype=%s", teamtype) pprint.pprint(game['teams'][teamtype]) game_rec[teamtype] = { 'abbrev': 'n/a', 'display': 'n/a', 'brief': 'n/a', 'full': 'n/a', 'league': 'n/a', 'division': 'n/a', } if 'linescore' in game and teamtype in game['linescore'][ 'teams'] and 'runs' in game['linescore']['teams'][ teamtype]: game_rec['linescore'][teamtype] = { 'runs': str(game['linescore']['teams'][teamtype]['runs']), 'hits': str(game['linescore']['teams'][teamtype]['hits']), 'errors': str(game['linescore']['teams'][teamtype]['errors']), } else: game_rec['linescore'][teamtype] = { 'runs': '0', 'hits': '0', 'errors': '0' } game_rec['favourite'] = gamedata.is_fav(game_rec) game_rec['preview'] = list() try: if 'probablePitcher' in game['teams'][ 'away'] or 'probablePitcher' in game['teams']['home']: game_rec['preview'].append('Probable Pitchers') game_rec['preview'].append('-----------------') for teamtype in ('away', 'home'): if 'probablePitcher' in game['teams'][teamtype]: # if config.CONFIG.parser['info_display_articles'] and 'fullName' in game['teams'][teamtype]['probablePitcher']: if 'fullName' in game['teams'][teamtype][ 'probablePitcher']: pitcher_name = ' '.join( reversed(game['teams'][teamtype] ['probablePitcher'] ['fullName'].split(','))).strip() if config.CONFIG.parser.getboolean( 'info_display_articles' ) and 'note' in game['teams'][teamtype][ 'probablePitcher']: note = game['teams'][teamtype][ 'probablePitcher']['note'] game_rec['preview'].append( '{}: {}: {}'.format( game['teams'][teamtype]['team'] ['teamName'], pitcher_name, note)) else: game_rec['preview'].append('{}: {}'.format( game['teams'][teamtype]['team'] ['teamName'], pitcher_name)) if config.CONFIG.parser.getboolean( 'info_display_articles' ) and teamtype == 'away': game_rec['preview'].append('') except: game_rec['preview'] = None game_rec['summary'] = list() try: if 'headline' in game['content']['editorial']['recap']['mlb']: game_rec['summary'].append('SUMMARY: ' + game['content']['editorial'] ['recap']['mlb']['headline']) if 'subhead' in game['content']['editorial']['recap']['mlb']: game_rec['summary'].append(' ' + game['content']['editorial'] ['recap']['mlb']['subhead']) if config.CONFIG.parser.getboolean('info_display_articles', True): if len(game_rec['summary']) > 0: game_rec['summary'].append('') if 'seoTitle' in game['content']['editorial']['recap'][ 'mlb']: # game_rec['summary'].append('TITLE: ' + game['content']['editorial']['recap']['mlb']['seoTitle']) game_rec['summary'].append( game['content']['editorial']['recap']['mlb'] ['seoTitle']) game_rec['summary'].append( '-' * len(game['content']['editorial']['recap'] ['mlb']['seoTitle'])) if 'body' in game['content']['editorial']['recap']['mlb']: game_rec['summary'].append(game['content']['editorial'] ['recap']['mlb']['body']) except: game_rec['summary'] = None game_rec['feed'] = dict() if game_rec['abstractGameState'] == 'Preview': continue # epg if 'media' in game['content'] and 'epg' in game['content']['media']: for media in game['content']['media']['epg']: if media['title'] == 'MLBTV': for stream in media['items']: if stream[ 'mediaFeedType'] != 'COMPOSITE' and stream[ 'mediaFeedType'] != 'ISO': feedtype = str(stream['mediaFeedType']).lower( ) # home, away, national, french, ... # Fix Issue #23 - resumed games show up on original day media feeds, with multiple entries for home and away # Handle it by naming the feed away-resume, home-resume, etc if 'resumeDate' in game_rec or 'resumedFrom' in game_rec: resume_feedtype = feedtype + '-resume' if resume_feedtype not in game_rec['feed']: feedtype = resume_feedtype else: # Maybe there is other cases where there is multiple home/away feeds? extrafeednum = 2 while feedtype in game_rec['feed']: feedtype += '{}'.format(extrafeednum) game_rec['feed'][feedtype] = dict() if 'mediaId' in stream: game_rec['feed'][feedtype][ 'mediaPlaybackId'] = str( stream['mediaId']) if 'contentId' in stream: game_rec['feed'][feedtype][ 'contentId'] = str( stream['contentId']) game_rec['feed'][feedtype][ 'mediaState'] = str( stream['mediaState']) game_rec['feed'][feedtype][ 'eventId'] = str(stream['id']) game_rec['feed'][feedtype][ 'callLetters'] = str( stream['callLetters']) if 'epgAlternate' in game['content']['media']: for media in game['content']['media']['epgAlternate']: if media['title'] == 'Extended Highlights': feedtype = 'condensed' if len(media['items']) > 0: game_rec['feed'][feedtype] = dict() stream = media['items'][0] game_rec['feed'][feedtype][ 'mediaPlaybackId'] = str( stream['mediaPlaybackId']) for playback_item in stream['playbacks']: if playback_item[ 'name'] == config.CONFIG.parser[ 'playback_scenario']: game_rec['feed'][feedtype][ 'playback_url'] = playback_item[ 'url'] elif media['title'] == 'Daily Recap': feedtype = 'recap' if len(media['items']) > 0: game_rec['feed'][feedtype] = dict() stream = media['items'][0] for playback_item in stream['playbacks']: if playback_item[ 'name'] == config.CONFIG.parser[ 'playback_scenario']: game_rec['feed'][feedtype][ 'playback_url'] = playback_item[ 'url'] if 'mediaPlaybackId' in game_rec['feed'][ feedtype]: game_rec['feed'][feedtype][ 'mediaPlaybackId'] = str( stream['mediaPlaybackId']) else: # For Issue #46 LOG.debug( 'No mediaPlaybackId for %s: %s at %s, game#: %s', game_rec['game_pk'], game_rec['away']['abbrev'], game_rec['home']['abbrev'], game_rec['gameNumber']) # elif media['title'] == 'Audio': # for stream in media['items']: # feedtype = 'audio-' + str(stream['mediaFeedType']).lower() # home, away, national, french, ... # game_rec['feed'][feedtype] = dict() # game_rec['feed'][feedtype]['mediaPlaybackId'] = str(stream['mediaId']) # game_rec['feed'][feedtype]['eventId'] = str(stream['id']) # game_rec['feed'][feedtype]['callLetters'] = str(stream['callLetters']) return game_records