2019-12-05 09:47:32 +00:00

4050 lines
174 KiB
Python

# MLBScores
###
# Copyright (c) 2018, cottongin
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions, and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions, and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author of this software nor the name of
# contributors to this software may be used to endorse or promote products
# derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###
import supybot.utils as utils
from supybot.commands import *
import supybot.plugins as plugins
import supybot.ircutils as ircutils
import supybot.callbacks as callbacks
import supybot.ircmsgs as ircmsgs
import supybot.schedule as schedule
try:
from supybot.i18n import PluginInternationalization
_ = PluginInternationalization('MLBScores')
except ImportError:
# Placeholder that allows to run the plugin on a bot
# without the i18n module
_ = lambda x: x
import requests
import httplib2
import pendulum
import re
import datetime
import pytz
import time
import dateutil.parser
import urllib
import collections
import jellyfish
from operator import itemgetter
from . import inputParser
# from pprint import pprint
# from pybaseball import playerid_lookup
# from pybaseball import pitching_stats_bref
# from pybaseball import batting_stats_bref
class MLBScores(callbacks.Plugin):
"""Plugin to fetch MLB scores from the MLB.com API"""
threaded = True
def dprint(self, thing, override=False):
"""debug print"""
if self._DEBUG == True or override:
print(thing)
return
def __init__(self, irc):
self.__parent = super(MLBScores, self)
self.__parent.__init__(irc)
self._DEBUG = False
try:
self.GOOG = irc.getCallback('Google')
except:
self.GOOG = None
self._HTTP = httplib2.Http('.cache')
self._SCOREBOARD_ENDPOINT = ('https://statsapi.mlb.com/api/v1/schedule'
'?sportId=1,51&date={}'
'&hydrate=team(leaders(showOnPreview('
'leaderCategories=[homeRuns,runsBattedIn,'
'battingAverage],statGroup=[pitching,'
'hitting]))),linescore(matchup,runners),'
'flags,liveLookin,review,broadcasts(all),'
'decisions,person,probablePitcher,stats,'
'homeRuns,previousPlay,game(content('
'media(featured,epg),summary),tickets),'
'seriesStatus(useOverride=true)')
self._FUZZY_DAYS = ['yesterday', 'tonight', 'today', 'tomorrow',
'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
#pendulum.set_formatter('alternative')
self._TEAM_BY_TRI, self._TEAM_BY_ID = self._getTeams()
self._51_BY_TRI, self._51_BY_ID = self._get51Teams()
self._STATUSES = self._getStatuses()
#self._ACTIVE_PLAYERS = self._fetchActivePlayers()
self._TEAM_BY_NICK = {'fish': 'MIA', 'poop': 'NYY', 'goat': 'BOS',
'best': 'BOS', 'worst': 'NYY', '💩': 'NYY'}
self._player_aliases = {'buttholz': 'Clay Buchholz',
'sucker punch': 'Gary Sanchez',
'sucker puncher': 'Gary Sanchez',
'big sexy': 'Bartolo Colon',
'sexx dragon': 'Joe Mauer',
'big papi': 'David Ortiz',
'dp': 'dustin pedroia',
'lil dp': 'dustin pedroia',
'panda': 'pablo sandoval',
'gap tooth': 'aaron judge',
'jv': 'justin verlander',
'comebacker': 'justin verlander',
'justdongs': 'jd martinez',
'justdongers': 'jd martinez',
'erod': 'eduardo rodriguez',
'jdmart': 'jd martinez',
'starlord': 'alex wilson',
'machado': 'dixon machado',
'douchebag': 'manny machado',
'strikeouts mcgee': 'giancarlo stanton',
'k machine': 'giancarlo stanton',
'swings and misses': 'giancarlo stanton',
'calendario': 'candelario',
'scrabble': 'marc rzepczynski',
'mr_pink': 'Enyel De Los Santos',
'jbj': 'jackie bradley jr.',
'mvp': 'mookie betts',
'tyler austin\'s daddy': 'joe kelly',
'tyler austins daddy': 'joe kelly',
'joe kelly\'s son': 'tyler austin',
'joe kellys son': 'tyler austin',
'joe kelly\'s daughter': 'tyler austin',
'joe kellys daughter': 'tyler austin',
}
def periodicCheckGames():
#print('MLBScores: Periodic check')
self.MLB_GAMES = self._fetchGames(None, None)
#print(self.CFB_GAMES)
def periodicCheckPlayers():
self._PLAYERS = {}
self._PLAYERS['active'] = self._fetchPlayers()
self._PLAYERS['allTime'] = self._fetchPlayers('allTime')
periodicCheckGames()
periodicCheckPlayers()
try: # check scores.
schedule.addPeriodicEvent(periodicCheckGames, 20, now=False, name='fetchMLBscores')
except AssertionError:
try:
schedule.removeEvent('fetchMLBscores')
except KeyError:
pass
schedule.addPeriodicEvent(periodicCheckGames, 20, now=False, name='fetchMLBscores')
try: # check active rosters.
schedule.addPeriodicEvent(periodicCheckPlayers, 3600, now=False, name='fetchMLBplayers')
except AssertionError:
try:
schedule.removeEvent('fetchMLBplayers')
except KeyError:
pass
schedule.addPeriodicEvent(periodicCheckPlayers, 3600, now=False, name='fetchMLBplayers')
try:
schedule.removeEvent('fetchALLMLBplayers')
except KeyError:
pass
def _shortenUrl(self, url):
"""Shortens a long URL into a short one."""
# Get a API key from bit.ly
api_key = self.registryValue('bitlyAPIKey')
url_enc = urllib.parse.quote_plus(url)
api_url = 'https://api-ssl.bitly.com/v3/shorten?access_token={}&longUrl={}&format=txt'
try:
url = requests.get(api_url.format(api_key, url_enc))
return url.text.strip()
except:
return url
def _getTeams(self, league=None):
"""fetches teams and tricodes"""
if not league:
url = 'https://statsapi.mlb.com/api/v1/teams?sportId=1'
else:
url = 'https://statsapi.mlb.com/api/v1/teams?sportIds={}&leagueId={}'.format(league[0], league[1])
data = requests.get(url).json()
tmp1 = {}
tmp2 = {}
for team in data['teams']:
tmp1[team['abbreviation']] = team['id']
tmp2[str(team['id'])] = team['abbreviation']
return tmp1, tmp2
def _get51Teams(self):
"""fetches teams and tricodes"""
url = 'https://statsapi.mlb.com/api/v1/teams?sportId=51'
data = requests.get(url).json()
tmp1 = {}
tmp2 = {}
for team in data['teams']:
tmp1[team['abbreviation']] = team['id']
tmp2[str(team['id'])] = team['abbreviation']
return tmp1, tmp2
def _getStatuses(self):
url = 'http://statsapi.mlb.com/api/v1/gameStatus'
data = requests.get(url).json()
tmp = {}
for status in data:
tmp[status['statusCode']] = status['detailedState']
return tmp
@wrap(['text'])
def recap(self, irc, msg, args, irc_args):
"""<team> [<date>]
Returns MLB Recap Videos
"""
team, date, tz = self._parseInput(irc_args)
date = pendulum.parse(date)
if date is None:
date = datetime.datetime.now().strftime("%y-%m-%d")
hdate = datetime.datetime.now().strftime("%m/%d/%y")
else:
# team, date, tz = self._parseInput(irc_args)
# for form in ["%d%b", "%d %b", "%b%d", "%b %d", "%d%B", "%d %B", "%b%B", "%b %B", "%B %d", "%B%d", "%Y%m%d", "%Y-%m-%d", "%m%d"]:
# result = self.api_get_date(date, form)
# if result is not None:
# break
# if result is None:
# return("Use the following format: Apr10 or 10Apr or YYYYMMDD")
day = str(date.day)
month = str(date.month)
year = date.year
if year == 1900:
year = 2019
if (year < 2016):
irc.reply("Sorry, the API only back dates until 2016")
return
if len(day) == 1:
day = "0{}".format(day)
if len(month) == 1:
month = "0{}".format(month)
date = "{}-{}-{}".format(year, month, day)
hdate = "{}/{}/{}".format(month, day, str(year)[2:])
#team = self.MLBFindTeam(team.upper(), 0)
# if len(team) > 3:
# irc.reply(team)
# return
#print(team)
url = "https://statsapi.mlb.com/api/v1/schedule?sportId=1&date={}&hydrate=linescore(matchup,runners),game(content(media(featured,epg),summary),tickets)&teamId={}".format(date, team)
content = requests.get(url).json()
recap = False
try:
for each in content['dates'][0]['games']:
home = int(each['teams']['home']['team']['id'])
away = int(each['teams']['away']['team']['id'])
#print(team, home, away)
if int(team) == home or int(team) == away:
newurl = "https://statsapi.mlb.com/api/v1/game/{}/content".format(each['gamePk'])
newcontent = requests.get(newurl).json()
url = newcontent['media']['epgAlternate'][4]['items'][0]['playbacks'][3]['url']
duration = newcontent['media']['epgAlternate'][4]['items'][0]['duration']
duration = datetime.datetime.strptime(duration, "%H:%M:%S").strftime("%Mm%Ss").lstrip("0").lstrip("m")
away_s = each['teams']['away']['score']
home_s = each['teams']['home']['score']
headline = "{} {} @ {} {}".format(self._TEAM_BY_ID[str(away)], away_s, self._TEAM_BY_ID[str(home)], home_s)
blurb = newcontent['media']['epgAlternate'][4]['items'][0]['blurb']
date, info = blurb.split(":")
url = self._shortenUrl(url)
irc.reply("\x02Recap: {}\x02 |{}".format(headline, info))
recap = True
for items in newcontent['media']['epgAlternate'][4]['items'][0]['playbacks']:
if items['name'] == 'FLASH_2500K_1280X720':
mp4 = self._shortenUrl(items['url'])
if items['name'] == 'HTTP_CLOUD_WIRED_WEB':
hls = self._shortenUrl(items['url'])
irc.reply("\x02MP4\x02: {} | \x02HLS\x02: {} | \x02{}\x02".format(mp4, hls, duration))
except Exception as e:
#print(e)
irc.reply("\x02{}\x02: No recap video available for {}".format(hdate, self._TEAM_BY_ID[team]))
@wrap
def mlbwildcard(self, irc, msg, args):
"""Fetches wildcard standings for MLB"""
url = 'https://statsapi.mlb.com/api/v1/standings?leagueId=103,104&season={season}&standingsTypes=wildCard&hydrate=division,conference,sport,league,team(nextSchedule(team,gameType=[R,F,D,L,W,C],inclusive=false),previousSchedule(team,gameType=[R,F,D,L,W,C],inclusive=true))'
season = pendulum.now().year
url = url.format(season=season)
try:
data = requests.get(url)
data = data.json()
except:
irc.reply('Error fetching standings')
return
al_data = data['records'][0]
nl_data = data['records'][1]
alwc = []
nlwc = []
al = self._blue(self._bold(al_data['league']['abbreviation'] + 'WC'))
nl = self._red(self._bold(nl_data['league']['abbreviation'] + 'WC'))
# BOS +2.5 (W-L) W2 | NYY - (W-L) W2 |
for team in al_data['teamRecords']:
string = '{} {} {} {}{}'
string = string.format(
self._bold('{:3}'.format(team['team']['abbreviation'])),
'-' + team['wildCardGamesBack'] if ('-' not in team['wildCardGamesBack'] and '+' not in team['wildCardGamesBack']) else team['wildCardGamesBack'],
'({}-{})'.format(team['wins'], team['losses']),
self._green(team['streak']['streakCode']) if 'W' in team['streak']['streakCode'] else self._red(team['streak']['streakCode']),
' E#{}'.format(team['wildCardEliminationNumber']) if '-' not in team['wildCardEliminationNumber'] else ''
)
if team['wildCardEliminationNumber'] != 'E':
alwc.append(string)
for team in nl_data['teamRecords']:
string = '{} {} {} {}{}'
string = string.format(
self._bold('{:3}'.format(team['team']['abbreviation'])),
'-' + team['wildCardGamesBack'] if ('-' not in team['wildCardGamesBack'] and '+' not in team['wildCardGamesBack']) else team['wildCardGamesBack'],
'({}-{})'.format(team['wins'], team['losses']),
self._green(team['streak']['streakCode']) if 'W' in team['streak']['streakCode'] else self._red(team['streak']['streakCode']),
' E#{}'.format(team['wildCardEliminationNumber']) if '-' not in team['wildCardEliminationNumber'] else ''
)
if team['wildCardEliminationNumber'] != 'E':
nlwc.append(string)
al_string = '{}: {}'.format(al, ' | '.join(string for string in alwc))
nl_string = '{}: {}'.format(nl, ' | '.join(string for string in nlwc))
irc.reply(al_string)
irc.reply(nl_string)
@wrap([optional('text')])
def mlbstandings(self, irc, msg, args, irc_args=None):
"""[<division>]
Fetches standings for given division, defaults to all divisions if not provided
"""
valid_leagues = ['ALE', 'ALW', 'ALC',
'NLE', 'NLW', 'NLC']
table = False
if irc_args:
if '--table' in irc_args:
table = True
irc_args = irc_args.replace('--table', '')
irc_args = irc_args.strip()
if irc_args.upper() not in valid_leagues:
irc.reply('Error: invalid league')
return
now = pendulum.now().year
url = ('https://statsapi.mlb.com/api/v1/standings?leagueId=103,104'
'&season={season}&standingsTypes=regularSeason'
'&hydrate=division,conference,sport,league,team'
'(nextSchedule(team,gameType=[R,F,D,L,W,C],inclusive=false),'
'previousSchedule(team,gameType=[R,F,D,L,W,C],inclusive=true))')
url = url.format(season=now)
try:
data = requests.get(url)
data = data.json()
except:
irc.reply('Error fetching standings')
return
#print(data['records'][0])
data = data['records']
# ALE: BOS - (103-50) L2 | NYY -10 (94-50) W2 |
standings = collections.OrderedDict()
divisions = {}
for league in data:
abbrv = league['division']['abbreviation']
short_name = league['division']['nameShort']
divisions[abbrv] = short_name
standings[abbrv] = []
for team in league['teamRecords']:
tmp = collections.OrderedDict()
tmp['team_abbrv'] = team['team']['abbreviation']
tmp['games_back'] = team['divisionGamesBack']
tmp['record'] = '({}-{})'.format(team['wins'], team['losses'])
tmp['wins'] = team['wins']
tmp['losses'] = team['losses']
tmp['streak'] = team['streak']['streakCode']
tmp['clinched'] = team['clinchIndicator'] if team['clinched'] else ''
tmp['pct'] = team['leagueRecord']['pct']
tmp['enum'] = team['eliminationNumber']
tmp['wcgb'] = team['wildCardGamesBack']
for split in team['records']['splitRecords']:
if 'lastTen' in split['type']:
tmp['last10'] = '{}-{}'.format(split['wins'], split['losses'])
tmp['rs'] = team['runsScored']
tmp['ra'] = team['runsAllowed']
tmp['diff'] = team['runDifferential']
tmp['xwl'] = '{}-{}'.format(team['records']['expectedRecords'][0]['wins'], team['records']['expectedRecords'][0]['losses'])
tmp['home'] = '{}-{}'.format(team['records']['splitRecords'][0]['wins'], team['records']['splitRecords'][0]['losses'])
tmp['away'] = '{}-{}'.format(team['records']['splitRecords'][1]['wins'], team['records']['splitRecords'][1]['losses'])
tmp['.500'] = '{}-{}'.format(team['records']['splitRecords'][7]['wins'], team['records']['splitRecords'][7]['losses'])
try:
if team['team']['abbreviation'] == team['team']['nextGameSchedule']['dates'][0]['games'][0]['teams']['away']['team']['abbreviation']:
nextStr = 'at {}'.format(team['team']['nextGameSchedule']['dates'][0]['games'][0]['teams']['home']['team']['abbreviation'])
else:
nextStr = 'vs {}'.format(team['team']['nextGameSchedule']['dates'][0]['games'][0]['teams']['away']['team']['abbreviation'])
tmp['next'] = '{} {}'.format(
pendulum.parse(team['team']['nextGameSchedule']['dates'][0]['date']).format('MMM D'),
nextStr
)
except:
tmp['next'] = '-'
tmp['team'] = team['team']['shortName']
standings[abbrv].append(tmp)
#print(standings['ALE'][0])
#print(divisions)
#irc.reply(standings['ALE']
for league in standings:
if not irc_args or (irc_args and not table):
reply_string = '{}: '.format(self._bold(self._blue(league)) if 'A' in league else self._bold(self._red(league)))
tmp_strings = []
for idx, team in enumerate(standings[league]):
tmp_string = '{} {} {} {}'.format(
self._bold('{:3}'.format(team['team_abbrv'])),
'-' + '{:4}'.format(team['games_back']) if '-' not in team['games_back'] else team['games_back'],
team['record'],
self._green(team['streak']) if 'W' in team['streak'] else self._red(team['streak']))
tmp_strings.append(tmp_string)
reply_string += ' | '.join(string for string in tmp_strings)
if irc_args:
if irc_args.upper() == league:
irc.reply(reply_string)
return
else:
irc.reply(reply_string)
else:
if irc_args.upper() == league:
max_width = 0
for team in standings[league]:
if max_width < len(team['clinched'] + team['team']):
max_width = len(team['clinched'] + team['team'])
league_width = max_width - len(divisions[irc_args.upper()]) + 2
header = '{}{:{width}} W L PCT GB E# WCGB L10 STRK RS RA DIFF X-W/L Home Away >.500 Next Game'
header = header.format(divisions[irc_args.upper()], ' ', width=league_width)
irc.reply(header)
for team in standings[league]:
reply_string = '{:{width}} {:3} {:3} {} {:^4} {} {:^4} {} {} {} {} {:^4} {:7} {} {} {} {}'
reply_string = reply_string.format(
team['clinched'] + team['team'],
team['wins'], team['losses'],
team['pct'],
team['games_back'],
team['enum'],
team['wcgb'],
team['last10'],
team['streak'],
team['rs'],
team['ra'],
team['diff'],
team['xwl'],
team['home'],
team['away'],
team['.500'],
team['next'],
width=max_width
)
irc.reply(reply_string)
@wrap([optional('text')])
def offseason(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, '119,131,132,133,135,162,516,595'])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, '119,131,132,133,135,162,516,595'])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def cs(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 162])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 162])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def abl(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 595])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 595])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def winl(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 516])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 516])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def vwl(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 135])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 135])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def pwl(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 133])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 133])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def lmp(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 132])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 132])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def dwl(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 131])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 131])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def azfl(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams(league=[17, 119])
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
GAMES = self._fetchGames(team, date, league=[17, 119])
if not GAMES:
irc.reply('No games found')
return
games = self._parseGames(GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap([optional('text')])
def mlb(self, irc, msg, args, irc_args=None):
"""[<team tri code>] [<date>]
Fetches scores for given team and/or date. Defaults to today and all
teams if no input provided"""
tv = False
if irc_args:
if '--tv' in irc_args:
tv = True
irc_args = irc_args.replace('--tv','')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
team_codes, _ = self._getTeams()
#print(team_codes)
try:
team, date, tz = inputParser.parseInput(irc_args, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
if not self.MLB_GAMES or date:
#print('MLBScores: No cached scores, pulling fresh')
self.MLB_GAMES = self._fetchGames(team, date)
if not self.MLB_GAMES:
irc.reply('No games found')
return
games = self._parseGames(self.MLB_GAMES, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
reply_string = self._replyAsString(team, games, tz, tv)
# what = type(reply_string)
# print(what)
# print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
if date:
self.MLB_GAMES = self._fetchGames(team)
@wrap(['text'])
def currentab(self, irc, msg, args, irc_args):
"""[<team tri code>]
Fetches details for current at bat for the given team."""
if irc_args:
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
try:
team, date, tz = inputParser.parseInput(irc_args, self._TEAM_BY_TRI, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
games = self._fetchGames(team, date)
if not games:
irc.reply('No games found')
return
games = self._parseGames(games, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
for game in games:
at_bat = game['atBat']
if not at_bat:
irc.reply('ERROR: No current at bat found, game active?')
return
irc.reply(at_bat)
@wrap(['positiveInt','text'])
def findab(self, irc, msg, args, ab_index, irc_args):
"""<ab #> <team tri code>
Fetches details for current at bat for the given team."""
if irc_args:
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
try:
team, date, tz = inputParser.parseInput(irc_args, self._TEAM_BY_TRI, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
games = self._fetchGames(team, date)
if not games:
irc.reply('No games found')
return
games = self._parseGames(games, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
ab_index = str(ab_index-1)
for game in games:
at_bat = game['atBats'].get(ab_index)
if not at_bat:
irc.reply('ERROR: No at bat found, game active?')
return
at_bat = at_bat[0]
irc.reply(at_bat)
@wrap(['text'])
def atbats(self, irc, msg, args, irc_args):
"""<ab #> <team tri code>
Fetches details for current at bat for the given team."""
if irc_args:
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
try:
team, date, tz = inputParser.parseInput(irc_args, self._TEAM_BY_TRI, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
games = self._fetchGames(team, date)
if not games:
irc.reply('No games found')
return
games = self._parseGames(games, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
#ab_index = str(ab_index-1)
at_bats = []
for game in games:
for k,v in game['atBats'].items():
#print(k)
at_bats.append([v[1], v[2]])
if not at_bats:
irc.reply('ERROR: No at bats found, game active?')
return
at_bats = sorted(at_bats, key=lambda k: k[0], reverse=True)
irc.reply(', '.join(str(a[0]) + '-' + a[1] for a in at_bats))
@wrap(['text'])
def lastatbat(self, irc, msg, args, irc_args):
"""<team> <player>
Fetches details for last at bat for the given team and player."""
if irc_args:
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
player = irc_args.split()[1:]
player = ' '.join(n for n in player).strip()
irc_args = irc_args.split()[0]
try:
team, date, tz = inputParser.parseInput(irc_args, self._TEAM_BY_TRI, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(irc_args)
print('internal parser worked')
#print(team)
#print(date)
games = self._fetchGames(team, date)
if not games:
irc.reply('No games found')
return
games = self._parseGames(games, date, team)
if not games:
irc.reply('No games found')
return
games = self._sortGames(games)
#ab_index = str(ab_index-1)
at_bats = []
for game in games:
for k,v in game['atBats'].items():
#print(k)
at_bats.append([v[1], v[2]])
if not at_bats:
irc.reply('ERROR: No at bats found, game active?')
return
at_bats = sorted(at_bats, key=lambda k: k[0], reverse=True)
for at_bat in at_bats:
#print(player.lower(), at_bat[1].lower())
if player.lower() == at_bat[1].lower():
print('hi')
idx = str(at_bat[0]-1)
for game in games:
print(game['atBats'].get(idx), idx)
ab = game['atBats'].get(idx)
if ab:
ab = ab[0]
break
irc.reply(ab)
def _sanitizeName(self, name):
""" Sanitize name. """
name = name.lower() # lower.
#name = name.strip('.') # remove periods.
name = name.strip('-') # remove dashes.
name = name.strip("'") # remove apostrophies.
# possibly strip jr/sr/III suffixes in here?
return name
def _pf(self, db, pname):
"""<e|r|s> <player>
Find a player's page via google ajax. Specify DB based on site.
"""
# check for aliases first
if pname.lower() in self._player_aliases:
pname = self._player_aliases[pname.lower()]
# sanitize.
pname = self._sanitizeName(pname)
# db.
if db == "e": # espn.
#splitsfix = '-site:espn.go.com/mlb/player/splits/'
burl = "site:espn.go.com/mlb/player/ {0}".format(pname)
elif db == "r": # rworld.
burl = "site:www.rotoworld.com/player/mlb/ %s" % pname
elif db == "s": # st.
burl = "site:www.spotrac.com/mlb/ %s" % pname
elif db == "br": # br.
burl = "site:www.baseball-reference.com/ %s" % pname
# now actually search
try:
#goog = self.GOOG
if self.GOOG:
try:
search = self.GOOG.search('{0}'.format(burl),'#reddit-baseball',{'smallsearch': True})
search = self.GOOG.decode(search)
if search:
url = search[0]['url']
# title = search[0]['title']
# title = title.replace('<b>', '')
# title = title.replace('</b>', '')
# title = title.strip()
# if pname.title() in title:
# title = title.split(pname.title())[0]
# title += pname.title()
# else:
# title = title.split('-')[0]
# title = title.strip()
title = url.split('/')[-1]
title = title.replace('-', ' ')
print(title)
return title
except:
self.log.exception("ERROR :: _pf :: failed to get link for {0}".format(burl))
return None
except Exception as e:
self.log.info("ERROR :: _pf :: {0}".format(e))
return None
def _similarPlayers(self, optname):
"""Return a dict containing the five most similar players based on optname."""
activeplayers = self._PLAYERS['active']
# test length as sanity check.
if len(activeplayers) == 0:
self.log.info("ERROR: _similarPlayers :: length 0. Could not find any players in players source")
return None
# ok, finally, lets go.
optname = str(self._sanitizeName(optname)) # sanitizename.
jaro, damerau = [], [] # empty lists to put our results in.
# now we create the container to iterate over.
names = [{'fullname': str(self._sanitizeName(k)), 'id':v['id']} for k,v in activeplayers.items()] # full_name # last_name # first_name
#print(type(optname))
# iterate over the entries.
for row in names: # list of dicts.
jaroscore = jellyfish.jaro_distance(optname, row['fullname']) # jaro.
damerauscore = jellyfish.damerau_levenshtein_distance(optname, row['fullname']) # dld
jaro.append({'jaro': jaroscore, 'fullname': row['fullname'], 'id': row['id']}) # add dict to list.
damerau.append({'damerau': damerauscore, 'fullname': row['fullname'], 'id': row['id']}) # ibid.
# now, we do two "sorts" to find the "top5" matches. reverse is opposite on each.
jarolist = sorted(jaro, key=itemgetter('jaro'), reverse=True)[0:5] # bot five.
dameraulist = sorted(damerau, key=itemgetter('damerau'), reverse=False)[0:5] # top five.
# we now have two lists, top5 sorted, and need to do some further things.
# now, lets iterate through both lists. match if both are in it. (better matches)
matching = [k for k in jarolist if k['id'] in [f['id'] for f in dameraulist]]
# now, test if we have anything. better matches will have more.
if len(matching) == 0: # we have NO matches. grab the top two from jaro/damerau (for error str)
matching = [jarolist[0], dameraulist[0], jarolist[1], dameraulist[1]]
self.log.info("_similarPlayers :: NO MATCHES for {0} :: {1}".format(optname, matching))
match = False
else:
match = True
# return matching now.
return matching, match
# def _fetchActivePlayers(self):
# api_base = 'http://statsapi.mlb.com'
# roster_url = '/api/v1/teams/{team}/roster/active'
# players = {}
# for team in self._TEAM_BY_ID:
# url = api_base + roster_url.format(team=team)
# #print(url)
# tmp = requests.get(url).json()
# for player in tmp['roster']:
# if 'Pitcher' in player['position']['type']:
# stat_type = 'pitching'
# else:
# stat_type = 'hitting'
# players[player['person']['fullName']] = {'id': player['person']['id'],
# 'url': player['person']['link'],
# 'team': player['parentTeamId'],
# 'stat': stat_type}
# self._ACTIVE_PLAYERS = players
# return players
def _fetchPlayers(self, search_type=None):
# default to active rosters only
if not search_type:
search_type = 'active'
api_base = 'http://statsapi.mlb.com'
roster_url = '/api/v1/teams/{team}/roster/{search_type}'
# build db
players = {}
for team in self._TEAM_BY_ID:
url = api_base + roster_url.format(team=team, search_type=search_type)
tmp = requests.get(url).json()
for player in tmp['roster']:
# assign stat category to fetch
if 'Pitcher' in player['position']['type']:
stat_type = 'pitching'
else:
stat_type = 'hitting'
# active players will have a team, inactive will not
try:
team = player['parentTeamId']
except:
team = None
# finally assign the player and info
players[player['person']['fullName'].lower()] = {'id': player['person']['id'],
'url': player['person']['link'],
'team': team,
'stat': stat_type,
'disp_name': player['person']['fullName'],
}
return players
def _playerSearch(self, optplayer, search_type):
similar_players = None
match = False
if not self._PLAYERS[search_type]:
players = self._fetchPlayers(search_type)
else:
players = self._PLAYERS[search_type]
if optplayer.lower() not in players:
test = self._pf('e', optplayer)
if test:
optplayer = test
if optplayer.lower() not in players:
similar_players, match = self._similarPlayers(optplayer.lower())
#print(similar_players)
if match:
for item in similar_players:
if item['fullname'].title() in players:
optplayer = item['fullname']
break
if optplayer.lower() not in players:
#irc.reply('ERROR: {} not found on any active roster, check spelling/input'.format(optplayer.title()))
return None, similar_players
#print(optplayer)
if optplayer.lower() not in players:
#irc.reply('ERROR: {} not found on any active roster, check spelling/input'.format(optplayer.title()))
return None, similar_players
player = players[optplayer.lower()]
player['name'] = player['disp_name']
return player, similar_players
@wrap([getopts({'career': '', 'season': 'somethingWithoutSpaces',
'postseason': '', 'stattype': 'somethingWithoutSpaces'}), 'text'])
def mlbstats(self, irc, msg, args, options, optplayer):
"""<player name>
Fetches stats for given player. Options: --season <year>, --career, --postseason"""
api_base = 'http://statsapi.mlb.com'
roster_url = '/api/v1/teams/{team}/roster/allTime'
stats_url = ('/api/v1/people?'
'personIds={personId}'
'&season={year}'
'&hydrate=stats(group={group},season={year},type={statType},gameType={reg_or_post})')
options = dict(options)
# defaults
statType = 'season'
year = pendulum.now().year
reg_or_post = 'R'
blurb = '{} Season Stats'.format(year)
if not options:
statType = 'season'
year = pendulum.now().year
reg_or_post = 'R'
blurb = '{} Season Stats'.format(year)
# parse our options
else:
if 'career' in options and 'postseason' in options:
# we want career postseason stats
reg_or_post = 'P'
statType = 'career'
year = pendulum.now().year
blurb = '{} Postseason Stats'.format(statType.title())
elif 'career' in options and 'postseason' not in options:
# we want career regular season stats
reg_or_post = 'R'
statType = 'career'
year = pendulum.now().year
blurb = '{} Stats'.format(statType.title())
elif 'postseason' in options and 'career' not in options and 'season' not in options:
# we want current season postseason stats
statType = 'season'
year = pendulum.now().year
reg_or_post = 'P'
blurb = '{} Postseason Stats'.format(year, statType.title())
elif 'season' in options and 'postseason' in options:
# we want custom season postseason stats
if not options['season'].isdigit():
year = pendulum.now().year
optplayer = '{} {}'.format(options['season'], optplayer)
else:
year = options['season']
statType = 'season'
reg_or_post = 'P'
blurb = '{} Postseason Stats'.format(year, statType.title())
elif 'season' in options and 'postseason' not in options:
# we want custom season regular season stats
if not options['season'].isdigit():
# this is a workaround for the @aka/alias functionality
year = pendulum.now().year
optplayer = '{} {}'.format(options['season'], optplayer)
else:
year = options['season']
statType = 'season'
reg_or_post = 'R'
blurb = '{} {} Stats'.format(year, statType.title())
print(options)
# now let's try to find our player
player, possibles = self._playerSearch(optplayer, 'allTime')
if not player and possibles:
irc.reply("I couldn't find stats for {}".format(optplayer))
irc.reply("Possible suggestions: {0}".format(" | ".join([i['fullname'].title() for i in possibles])))
return
optplayer = player['name']
group = options.get('stattype') or player['stat']
print(group)
tmp = requests.get('{}{}'.format(api_base, stats_url.format(personId=player['id'],
year=year,
statType=statType,
group=group,
reg_or_post=reg_or_post)))
print(tmp.url)
tmp = tmp.json()
if 'stats' not in tmp['people'][0]:
irc.reply('ERROR: No stats found for {}'.format(optplayer.title()))
return
stats = tmp['people'][0]['stats']
try:
plyr_info = ' (#{} {})'.format(tmp['people'][0]['primaryNumber'],
tmp['people'][0]['primaryPosition']['abbreviation'])
except:
plyr_info = ''
try:
if not tmp['people'][0].get('active'):
years = ' ({}-{})'.format(tmp['people'][0]['mlbDebutDate'].split('-')[0],
tmp['people'][0]['lastPlayedDate'].split('-')[0])
else:
years = ' ({}-)'.format(tmp['people'][0]['mlbDebutDate'].split('-')[0]) #,
#tmp['people'][0]['lastPlayedDate'].split('-')[0])
except:
years = ''
blurb += years
hitting_stat_headers, pitching_stat_headers, _ = self._generateStatHeaders('mlbstats')
out_stats = []
stats = stats[0]['splits']
for thing in stats:
#print(thing)
stat_line = collections.OrderedDict({})
if 'numTeams' not in thing:
try:
team = '{}'.format(self._TEAM_BY_ID[str(thing['team']['id'])])
except:
team = ''
else:
team = 'Total'
if team:
team = '{} :: '.format(self._bu(team))
if not thing['stat']:
stat_line['ERROR'] = 'No stats available for {}'.format(optplayer.title())
break
if group == 'hitting':
for s in hitting_stat_headers:
#print(s)
if s in thing['stat']:
try:
stat_line[hitting_stat_headers[s]] = thing['stat'][s]
except:
stat_line[hitting_stat_headers[s]] = None
elif group == 'pitching':
for s in pitching_stat_headers:
#print(s)
if s in thing['stat']:
try:
stat_line[pitching_stat_headers[s]] = thing['stat'][s]
except:
stat_line[pitching_stat_headers[s]] = None
stat_string = ' '.join('{}: {}'.format(self._bold(k),v) for k,v in stat_line.items())
out_stats.append('{}{}'.format(team, stat_string))
irc.reply('{}{} :: {}'.format(self._bold(self._blue(optplayer)), plyr_info, blurb))
for line in out_stats:
irc.reply('{}'.format(line))
return
@wrap(['text'])
def fstats(self, irc, msg, args, optplayer):
"""<player name>
Fetches current/previous game fielding stats for given player"""
api_base = 'http://statsapi.mlb.com'
roster_url = '/api/v1/teams/{team}/roster/active'
stats_url_current = '/api/v1/people/{personId}/stats/game/current'
stats_url_game = '/api/v1/people/{personId}/stats/game/{gamePk}'
sched_url = ('/api/v1/teams/{teamId}?hydrate=previousSchedule('
'gameType=[E,S,R,A,F,D,L,W]),nextSchedule(gameType=[E,S,R,A,F,D,L,W])')
player, possibles = self._playerSearch(optplayer, 'active')
if not player and possibles:
irc.reply("I couldn't find stats for {}".format(optplayer))
irc.reply("Possible suggestions: {0}".format(" | ".join([i['fullname'].title() for i in possibles])))
return
optplayer = player['name']
current = False
tmp = requests.get('{}{}'.format(api_base, stats_url_current.format(personId=player['id'])))
tmp = tmp.json()
if not tmp['stats']:
# no current game
tmp = requests.get('{}{}'.format(api_base, sched_url.format(teamId=player['team']))).json()
try:
if tmp['teams'][0]['nextGameSchedule']['dates'][0]['games'][0]['status']['abstractGameState'] == 'Final':
gamePk = tmp['teams'][0]['nextGameSchedule']['dates'][0]['games'][0]['gamePk']
gameDate = pendulum.parse(tmp['teams'][0]['nextGameSchedule']['dates'][0]['games'][0]['gameDate'],
strict=False).in_tz('US/Eastern').format('MMM Do')
else:
gamePk = tmp['teams'][0]['previousGameSchedule']['dates'][0]['games'][0]['gamePk']
gameDate = pendulum.parse(tmp['teams'][0]['previousGameSchedule']['dates'][0]['games'][0]['gameDate'],
strict=False).in_tz('US/Eastern').format('MMM Do')
url = api_base + stats_url_game.format(personId=player['id'], gamePk=gamePk)
tmp = requests.get(url).json()
except:
irc.reply('ERROR: No current/previous game fielding stats found for {}'.format(optplayer.title()))
return
else:
current = True
#TBD
if not tmp['stats']:
irc.reply('ERROR: No current/previous game fielding stats found for {}'.format(optplayer.title()))
return
stats = []
for thing in tmp['stats']:
if 'type' not in thing:
stats = thing
break
if not stats:
irc.reply('ERROR: No current/previous game fielding stats found for {}'.format(optplayer.title()))
return
_, _, fielding_stat_headers = self._generateStatHeaders('fstats')
stat_line = collections.OrderedDict({})
for thing in stats['splits']:
if thing['group'] == 'fielding':
if not thing['stat']:
stat_line['ERROR'] = 'No fielding stats available for {} in current or previous game'.format(optplayer.title())
break
for s in fielding_stat_headers:
if s in thing['stat']:
try:
stat_line[fielding_stat_headers[s]] = thing['stat'][s]
except:
stat_line[fielding_stat_headers[s]] = None
try:
pct = (stat_line['Put Outs'] + stat_line['Assists']) / stat_line['Chances']
stat_line['Fielding'] = '{:.3f}'.format(pct)
except ZeroDivisionError:
pass
stat_string = ' '.join('{}: {}'.format(self._bold(k),v) for k,v in stat_line.items())
irc.reply('{} ({}) {}'.format(self._bold(self._blue(optplayer.title())), gameDate, stat_string))
return
@wrap(['text'])
def mlbgamestats(self, irc, msg, args, optplayer):
"""<player name>
Fetches current/previous game stats for given player"""
api_base = 'http://statsapi.mlb.com'
roster_url = '/api/v1/teams/{team}/roster/active'
stats_url_current = '/api/v1/people/{personId}/stats/game/current'
stats_url_game = '/api/v1/people/{personId}/stats/game/{gamePk}'
sched_url = ('/api/v1/teams/{teamId}?hydrate=previousSchedule('
'gameType=[E,S,R,A,F,D,L,W]),nextSchedule(gameType=[E,S,R,A,F,D,L,W])')
player, possibles = self._playerSearch(optplayer, 'active')
if not player and possibles:
irc.reply("I couldn't find stats for {}".format(optplayer))
irc.reply("Possible suggestions: {0}".format(" | ".join([i['fullname'].title() for i in possibles])))
return
optplayer = player['name']
current = False
tmp = requests.get('{}{}'.format(api_base, stats_url_current.format(personId=player['id'])))
print(tmp.url)
tmp = tmp.json()
if not tmp['stats']:
# no current game
tmp = requests.get('{}{}'.format(api_base, sched_url.format(teamId=player['team'])))
print(tmp.url)
tmp = tmp.json()
statuses = ['Final', 'Live']
if tmp['teams'][0]['nextGameSchedule']['dates'][0]['games'][0]['status']['abstractGameState'] in statuses:
gamePk = tmp['teams'][0]['nextGameSchedule']['dates'][0]['games'][0]['gamePk']
gameDate = pendulum.parse(tmp['teams'][0]['nextGameSchedule']['dates'][0]['games'][0]['gameDate'],
strict=False).in_tz('US/Eastern').format('MMM Do')
else:
gamePk = tmp['teams'][0]['previousGameSchedule']['dates'][0]['games'][0]['gamePk']
gameDate = pendulum.parse(tmp['teams'][0]['previousGameSchedule']['dates'][0]['games'][0]['gameDate'],
strict=False).in_tz('US/Eastern').format('MMM Do')
url = api_base + stats_url_game.format(personId=player['id'], gamePk=gamePk)
#irc.reply(url)
print(url)
tmp = requests.get(url).json()
else:
current = True
#TBD
gameDate = pendulum.now().in_tz('US/Eastern').format('MMM Do')
#print(gamePk)
if not tmp['stats']:
irc.reply('ERROR: No current/previous game stats found for {}'.format(optplayer.title()))
return
stats = []
for thing in tmp['stats']:
if 'type' not in thing:
stats = thing
break
#print(stats)
if not stats:
irc.reply('ERROR: No current/previous game stats found for {}'.format(optplayer.title()))
return
hitting_stat_headers, pitching_stat_headers, _ = self._generateStatHeaders('mlbgamestats')
stat_line = collections.OrderedDict({})
for thing in stats['splits']:
#print(thing)
if player['stat'] == thing['group']:
if not thing['stat']:
stat_line['ERROR'] = 'No stats available for {} on {}'.format(optplayer.title(), gameDate)
break
if player['stat'] == 'hitting':
for s in hitting_stat_headers:
#print(s)
if s in thing['stat']:
try:
stat_line[hitting_stat_headers[s]] = thing['stat'][s]
except:
stat_line[hitting_stat_headers[s]] = None
try:
avg = stat_line['H'] / stat_line['AB']
avg = '{:.3f}'.format(avg)
except ZeroDivisionError:
avg = ''
stat_line['AVG'] = avg
elif player['stat'] == 'pitching':
for s in pitching_stat_headers:
#print(s)
if s in thing['stat']:
try:
if s == 'balls' or s == 'strikes':
stat_line['B-S'] = '{}-{}'.format(thing['stat']['balls'], thing['stat']['strikes'])
else:
stat_line[pitching_stat_headers[s]] = thing['stat'][s]
except:
stat_line[pitching_stat_headers[s]] = None
try:
era = '{:.2f}'.format((stat_line['ER']/float(stat_line['IP']))*9)
except:
if float(stat_line['IP']) == 0.0 and stat_line['ER'] > 0:
era = ''
else:
era = '0.00'
stat_line['gERA'] = era
stat_string = ' '.join('{}: {}'.format(self._bold(k),v) for k,v in stat_line.items())
irc.reply('{} ({}) {}'.format(self._bold(self._blue(optplayer.title())), gameDate, stat_string))
return
def _generateStatHeaders(self, called_by):
if called_by == 'mlbstats':
hitting_stat_headers = collections.OrderedDict()
hitting_stat_headers['gamesPlayed'] = 'GP'
hitting_stat_headers['atBats'] = 'AB'
hitting_stat_headers['plateAppearances'] = 'PA'
hitting_stat_headers['hits'] = 'H'
hitting_stat_headers['runs'] = 'R'
hitting_stat_headers['doubles'] = '2B'
hitting_stat_headers['triples'] = '3B'
hitting_stat_headers['homeRuns'] = 'HR'
hitting_stat_headers['baseOnBalls'] = 'BB'
hitting_stat_headers['intentionalWalks'] = 'IBB'
hitting_stat_headers['hitByPitch'] = 'HBP'
hitting_stat_headers['strikeOuts'] = 'SO'
hitting_stat_headers['groundOuts'] = 'GO'
hitting_stat_headers['groundIntoDoublePlay'] = 'GIDP'
hitting_stat_headers['stolenBases'] = 'SB'
hitting_stat_headers['caughtStealing'] = 'CS'
hitting_stat_headers['stolenBasePercentage'] = 'SB%'
hitting_stat_headers['totalBases'] = 'TB'
hitting_stat_headers['leftOnBase'] = 'LOB'
hitting_stat_headers['sacBunts'] = 'sacB'
hitting_stat_headers['sacFlies'] = 'sacF'
hitting_stat_headers['babip'] = 'BABIP'
hitting_stat_headers['rbi'] = 'RBI'
hitting_stat_headers['avg'] = 'AVG'
hitting_stat_headers['obp'] = 'OBP'
hitting_stat_headers['slg'] = 'SLG'
hitting_stat_headers['ops'] = 'OPS'
pitching_stat_headers = collections.OrderedDict()
pitching_stat_headers['gamesPlayed'] = 'GP'
pitching_stat_headers['gamesStarted'] = 'GS'
pitching_stat_headers['completeGames'] = 'CG'
pitching_stat_headers['shutouts'] = 'SHO'
pitching_stat_headers['inningsPitched'] = 'IP'
pitching_stat_headers['pitchesPerInning'] = 'PitPI'
pitching_stat_headers['battersFaced'] = 'BF'
pitching_stat_headers['hits'] = 'H'
pitching_stat_headers['baseOnBalls'] = 'BB'
pitching_stat_headers['intentionalWalks'] = 'IBB'
pitching_stat_headers['hitBatsmen'] = 'HBP'
pitching_stat_headers['balks'] = 'BLK'
pitching_stat_headers['wildPitches'] = 'WP'
pitching_stat_headers['caughtStealing'] = 'CS'
pitching_stat_headers['strikeOuts'] = 'K'
pitching_stat_headers['groundOuts'] = 'GO'
pitching_stat_headers['earnedRuns'] = 'ER'
pitching_stat_headers['runs'] = 'R'
pitching_stat_headers['homeRuns'] = 'HR'
pitching_stat_headers['flyOuts'] = 'FO'
pitching_stat_headers['groundOuts'] = 'GO'
pitching_stat_headers['era'] = 'ERA'
pitching_stat_headers['whip'] = 'WHIP'
pitching_stat_headers['avg'] = 'AVG'
pitching_stat_headers['obp'] = 'OBP'
pitching_stat_headers['slg'] = 'SLG'
pitching_stat_headers['ops'] = 'OPS'
pitching_stat_headers['strikeoutWalkRatio'] = 'K/W'
pitching_stat_headers['strikeoutsPer9Inn'] = 'K/9'
pitching_stat_headers['walksPer9Inn'] = 'W/9'
pitching_stat_headers['hitsPer9Inn'] = 'H/9'
pitching_stat_headers['wins'] = 'W'
pitching_stat_headers['losses'] = 'L'
pitching_stat_headers['winPercentage'] = 'W%'
pitching_stat_headers['saves'] = 'SV'
pitching_stat_headers['saveOpportunities'] = 'SVO'
pitching_stat_headers['holds'] = 'HLD'
fielding_stat_headers = None
return hitting_stat_headers, pitching_stat_headers, fielding_stat_headers
elif called_by == 'fstats':
fielding_stat_headers = collections.OrderedDict()
fielding_stat_headers['chances'] = 'Chances'
fielding_stat_headers['errors'] = 'Errors'
fielding_stat_headers['putOuts'] = 'Put Outs'
fielding_stat_headers['assists'] = 'Assists'
fielding_stat_headers['passedBall'] = 'Passed Balls'
fielding_stat_headers['fielding'] = 'Fielding'
hitting_stat_headers = None
pitching_stat_headers = None
return hitting_stat_headers, pitching_stat_headers, fielding_stat_headers
elif called_by == 'mlbgamestats':
hitting_stat_headers = collections.OrderedDict()
hitting_stat_headers['atBats'] = 'AB'
hitting_stat_headers['hits'] = 'H'
hitting_stat_headers['runs'] = 'R'
hitting_stat_headers['baseOnBalls'] = 'BB'
hitting_stat_headers['strikeOuts'] = 'SO'
hitting_stat_headers['doubles'] = '2B'
hitting_stat_headers['triples'] = '3B'
hitting_stat_headers['homeRuns'] = 'HR'
hitting_stat_headers['stolenBases'] = 'SB'
hitting_stat_headers['caughtStealing'] = 'CS'
hitting_stat_headers['totalBases'] = 'TB'
hitting_stat_headers['rbi'] = 'RBI'
hitting_stat_headers['avg'] = 'AVG'
pitching_stat_headers = collections.OrderedDict()
pitching_stat_headers['inningsPitched'] = 'IP'
pitching_stat_headers['battersFaced'] = 'BF'
pitching_stat_headers['hits'] = 'H'
pitching_stat_headers['baseOnBalls'] = 'BB'
pitching_stat_headers['strikeOuts'] = 'K'
pitching_stat_headers['pitchesThrown'] = '#P'
pitching_stat_headers['balls'] = 'B-S'
pitching_stat_headers['strikes'] = 'B-S'
pitching_stat_headers['hitBatsmen'] = 'HBP'
pitching_stat_headers['earnedRuns'] = 'ER'
pitching_stat_headers['runs'] = 'R'
pitching_stat_headers['homeRuns'] = 'HR'
pitching_stat_headers['flyOuts'] = 'FO'
pitching_stat_headers['groundOuts'] = 'GO'
pitching_stat_headers['era'] = 'gERA'
fielding_stat_headers = None
return hitting_stat_headers, pitching_stat_headers, fielding_stat_headers
else:
return None, None, None
@wrap([getopts({'active': '',}), 'text'])
def mlbroster(self, irc, msg, args, optlist, opttype):
"""<--active> <team> <type>
Fetches roster for given <team> filtered by <type>"""
optlist = dict(optlist)
positions = {'pitchers': 'Pitcher', 'infielders': 'Infielder',
'catchers': 'Catcher', 'outfielders': 'Outfielder'}
base_url = 'http://statsapi.mlb.com/api/v1/teams/{team}/roster/{roster}'
api_base = 'http://statsapi.mlb.com'
try:
team = opttype.split()[0].upper()
except:
irc.reply('Invalid input')
return
try:
filter_ = opttype.split()[1]
except:
filter_ = None
#print(filter_)
try:
filter_ = filter_.lower()
filter_ = positions[filter_]
except:
if filter_:
filter_ = filter_.title()
if team not in self._TEAM_BY_TRI:
irc.reply('ERROR: Invalid team. Valid teams: {}'.format(', '.join(i for i in self._TEAM_BY_TRI)))
return
team_id = self._TEAM_BY_TRI[team]
url = base_url.format(team=team_id, roster='active')
data = requests.get(url).json()
#print(data.json())
roster = []
tmp = data['roster']
tmp = sorted(tmp, key=lambda k: k['person']['fullName'].split()[-1])
#print(tmp)
for player in tmp:
num = self._red('#{}'.format(player['jerseyNumber']))
name = player['person']['fullName']
info_url = player['person']['link']
#print(api_base + info_url)
info = requests.get(api_base + info_url).json()
bats = info['people'][0]['batSide']['code']
pits = info['people'][0]['pitchHand']['code']
string = '{} {} (B:{} T:{})'.format(num, name, bats, pits)
if filter_:
if player['position']['type'] == filter_:
roster.append(string)
else:
roster.append(string)
if not roster:
irc.reply('Nothing found for that query')
return
else:
irc.reply(', '.join(i for i in roster))
return
@wrap
def mlbdaysleft(self, irc, msg, args):
"""How many days are left in the current MLB season"""
now = pendulum.now()
end = pendulum.parse('201920-09-30')
left = end-now
irc.reply("There are {} days left in the {} MLB season.".format(left.days, end.year))
# @wrap(['text'])
# def mlbstats(self, irc, msg, args, player):
# """<player>
# Fetches current season stats for the <player> provided.
# """
# data = batting_stats_bref()
# #print(data.head())
@wrap(['text'])
def lineup2(self, irc, msg, args, team):
"""<team tri code>
Fetches lineup for the game <team> is playing
"""
abbv = team.upper()
#team, date, tz = self._parseInput(team)
team_codes, _ = self._getTeams(league=['1,17', '103,104,119,131,132,133,135,162,516,595'])
try:
team, date, tz = inputParser.parseInput(team, team_codes, self._TEAM_BY_NICK)
print('external parser worked')
except:
team, date, tz = self._parseInput(team)
print('internal parser worked')
#print(team)
#print(date)
#print('MLBScores: No cached scores, pulling fresh')
if date:
test = pendulum.parse(date)
now = pendulum.now().format('YYYY-MM-DD')
now = pendulum.parse(now)
k = (test > now)
#print(date, ' | ', k, ' | ', pendulum.now())
if k:
#irc_args = '{} {}'.format(team, date)
#self.mlb(msg, args, irc_args)
irc.reply("Sorry I can't predict the future.")
return
if not team:
irc.reply('No team provided.')
return
games = self._fetchGames(team, date, league=['1,17', '103,104,119,131,132,133,135,162,516,595'])
#games = self._fetchGames(team, date)
if not games:
irc.reply('No games found')
return
games = self._parseGames(games, date)
games = self._sortGames(games)
lineup_url = 'http://statsapi.mlb.com/api/v1/game/{}/boxscore'.format(games[0]['id'])
lineup_url_2 = 'https://statsapi.mlb.com/api/v1/schedule?gamePk={}&language=en&hydrate=lineups,person,probablePitcher,team(leaders(showOnPreview(leaderCategories=[homeRuns,runsBattedIn,battingAverage],statGroup=[pitching,hitting])))'.format(games[0]['id'])
print(lineup_url, lineup_url_2)
try:
data = requests.get(lineup_url).json()
data2 = requests.get(lineup_url_2).json()
except:
irc.reply('Something went wrong fetching game data.')
return
#print(team)
lineup = []
tmp_plyr_data = []
opp_id = None
#try:
teams = data['teams']
lineups = data2['dates'][0]['games'][0]['lineups']
#print(lineups)
ppitchers = data2['dates'][0]['games'][0]['teams']
for item in teams:
if int(team) == teams[item]['team']['id']:
#print('h/a: ', item)
if item == 'home':
opp_t = 'away'
hora = item
elif item == 'away':
opp_t = 'home'
hora = item
#print('pitcher: ', opp_t)
battingOrder = teams[item]['battingOrder']
tmp_plyr_data = teams[item]['players']
vs_name = teams[opp_t]['team']['abbreviation']
#pprint(teams[opp_t])
if teams[opp_t]['pitchers']:
opp_id = teams[opp_t]['pitchers'][-1]
hm_id = teams[item]['pitchers'][-1]
#print('teams')
else:
opp_id = ppitchers[opp_t]['probablePitcher']['id']
hm_id = ppitchers[item]['probablePitcher']['id']
#print('ppitchers')
break
#print(tmp_plyr_data)
if lineups:
#print('Got a lineup')
tstr = '{}Players'.format(hora)
#print(lineups)
try:
lineups = lineups[tstr]
except:
irc.reply('No lineup found')
return
for idx, player in enumerate(lineups):
if battingOrder:
if int(player['id']) != int(battingOrder[idx]):
player['id'] = int(battingOrder[idx])
#print(idx, player)
plyr_url = 'http://statsapi.mlb.com/api/v1/people/{}'.format(player['id'])
#print(plyr_url)
n_player_data = requests.get(plyr_url).json()
for pid in tmp_plyr_data:
if str(player['id']) in str(pid):
player_data = tmp_plyr_data[pid]
bats = n_player_data['people'][0]['batSide']['code']
name = player_data['person']['fullName']
try:
post = lineups[idx]['primaryPosition']['abbreviation']
except:
post = player_data['position']['abbreviation']
if idx == 9:
bats = n_player_data['people'][0]['pitchHand']['code']
tmp = '\x02\x0312{}\x03\x02 {} ({})'.format('P', name, bats)
else:
tmp = '\x02\x0312{}\x03\x02 {} ({}) {}'.format(idx+1, name, bats, post)
lineup.append(tmp)
#umps = item['value']
if opp_id:
pitcher_url = 'http://statsapi.mlb.com/api/v1/people/{}'.format(opp_id)
#print(pitcher_url)
pitcher_data = requests.get(pitcher_url).json()
pitch_name = pitcher_data['people'][0]['fullName']
pitches = pitcher_data['people'][0]['pitchHand']['code']
for pplayer in data['teams'][opp_t]['players']:
if str(opp_id) in pplayer:
era = data['teams'][opp_t]['players'][pplayer]['seasonStats']['pitching']['era']
pitcher = '{} ({}) {}'.format(pitch_name, pitches, era)
else:
pitcher = ''
if hm_id and len(lineup) == 9:
pitcher_url = 'http://statsapi.mlb.com/api/v1/people/{}'.format(hm_id)
#print(pitcher_url)
pitcher_data = requests.get(pitcher_url).json()
pitch_name = pitcher_data['people'][0]['fullName']
pitches = pitcher_data['people'][0]['pitchHand']['code']
for pplayer in data['teams'][hora]['players']:
if str(hm_id) in pplayer:
era = data['teams'][hora]['players'][pplayer]['seasonStats']['pitching']['era']
hm_pitcher = ' :: \x02\x0312{}\x03\x02 {} ({}) {}'.format('P', pitch_name, pitches, era)
else:
hm_pitcher = ''
# except:
# irc.reply('Something went wrong parsing game data.')
# return
if not lineup:
irc.reply('No lineup found yet, game active?')
return
irc.reply('{} Lineup vs {} - \x02{}\x02 :: {}{}'.format(abbv, vs_name, pitcher, ', '.join(plr for plr in lineup), hm_pitcher))
@wrap(['text'])
def umps(self, irc, msg, args, team):
"""<team tri code>
Fetches umpires for the game <team> is playing
"""
team, date, tz = self._parseInput(team)
if date:
test = pendulum.parse(date)
now = pendulum.now().format('YYYY-MM-DD')
now = pendulum.parse(now)
k = (test > now)
#print(date, ' | ', k, ' | ', pendulum.now())
if k:
#irc_args = '{} {}'.format(team, date)
#self.mlb(msg, args, irc_args)
irc.reply("Sorry I can't predict the future.")
return
if not team:
irc.reply('No team provided.')
return
games = self._fetchGames(team, date)
if not games:
irc.reply('No games found')
return
games = self._parseGames(games, date)
games = self._sortGames(games)
ump_url = 'http://statsapi.mlb.com/api/v1/game/{}/boxscore'.format(games[0]['id'])
#print(ump_url)
try:
data = requests.get(ump_url).json()
except:
irc.reply('Something went wrong fetching game data.')
return
umps = None
try:
for item in data['info']:
if item['label'] == 'Umpires':
umps = item['value']
break
except:
irc.reply('Something went wrong parsing game data.')
return
if not umps:
irc.reply('No umpires found yet, game active?')
return
irc.reply('Umpires: {}'.format(umps))
@wrap([optional('text')])
def mlbpitcher(self, irc, msg, args, irc_args=None):
"""<team tri code> [<date>]
Fetches pitcher(s) for given team and/or date. Defaults to today
if no input provided"""
override = False
starter_only = False
if irc_args:
if '--all' in irc_args:
override = True
irc_args = irc_args.replace('--all', '')
if 'was' in irc_args:
irc_args = irc_args.replace('was', 'wsh')
if '--starter' in irc_args:
starter_only = True
override = True
irc_args = irc_args.replace('--starter', '')
team, date, tz = self._parseInput(irc_args)
if date:
test = pendulum.parse(date)
now = pendulum.now().format('YYYY-MM-DD')
now = pendulum.parse(now)
k = (test > now)
#print(date, ' | ', k, ' | ', pendulum.now())
if k:
#irc_args = '{} {}'.format(team, date)
#self.mlb(msg, args, irc_args)
irc.reply("Sorry I can't predict the future.")
return
if not team:
irc.reply('No team provided.')
return
games = self._fetchGames(team, date)
if not games:
irc.reply('No games found')
return
games = self._parseGames(games, date)
games = self._sortGames(games)
pitchers = self._fetchPitchers(games, team, override)
if not pitchers:
irc.reply('No pitchers found, has game started yet?')
return
#print(pitchers)
# if len(pitchers) == 2:
# if 'Game 2' in pitchers[1]:
# irc.reply('No pitchers found, has game started yet?')
# return
reply_string = self._replyPitchersAsString(pitchers)
# if len(reply_string) > 3:
# print(reply_string)
# if 'Game 2' in reply_string[-1]:
# reply_string.append('Not started yet')
# what = type(reply_string)
# print(what)
#print(reply_string)
if type(reply_string) is tuple or type(reply_string) is list or type(reply_string) is dict:
if type(reply_string) is dict:
for string in reply_string:
irc.reply('\x02{}\x02'.format(string))
if starter_only:
irc.reply(reply_string[string][0])
else:
for pit in reply_string[string]:
irc.reply(pit)
else:
if starter_only:
irc.reply(reply_string[0])
else:
for string in reply_string:
irc.reply(string)
else:
irc.reply(reply_string)
@wrap(['text'])
def mlbinjuries(self, irc, msg, args, optteam):
"""<team>
Returns injuries for given <team>.
"""
# get team id for matching
team, _, _ = self._parseInput(optteam)
# url to get data
url = 'http://mlb.mlb.com/fantasylookup/json/named.wsfb_news_injury.bam'
# try to get the data
try:
data = requests.get(url).json()
except:
irc.reply('Something went wrong fetching the data.')
return
# pull out the relevant data
injuries = data['wsfb_news_injury']['queryResults']['row']
# build output
output = []
for injury in injuries:
#print(team, int(injury['team_id']))
if not team:
if optteam.lower() in '{} {}'.format(injury['name_first'].lower(), injury['name_last'].lower()):
name = '\x02\x0312{} {}\x03\x02 ({})'.format(injury['name_first'],
injury['name_last'],
injury['position'])
inj = '{} on {} ({})'.format(injury['injury_status'],
injury['insert_ts'],
injury['injury_desc'])
upd = '\x02Latest:\x02 {}'.format(injury['injury_update'])
due = '\x02Returning:\x02 {}'.format(injury['due_back'])
output.append('{} :: {} | {} | {}'.format(name, inj, upd, due))
else:
if int(team) == int(injury['team_id']):
# our team query matches let's go
name = '\x02\x0312{} {}\x03\x02 ({})'.format(injury['name_first'],
injury['name_last'],
injury['position'])
inj = '{} on {}'.format(injury['injury_status'],
injury['insert_ts'])
output.append('{} {}'.format(name, inj))
if not output:
irc.reply('ERROR: Team or player not found or no injuries found for provided team or player.')
return
if team:
team_name = '\x02{}:\x02 '.format(self._TEAM_BY_ID['{}'.format(team)])
irc.reply('{}{}'.format(team_name, ', '.join(i for i in output)))
else:
irc.reply(' || '.join(i for i in output))
@wrap([optional('int'), 'somethingwithoutspaces', optional('somethingwithoutspaces')])
def next(self, irc, msg, args, optdays, optteam, optteam2):
"""[<#>] <team> [<team>]
Returns the next # of games for team (or team vs team), defaults to 1 if not given
"""
tids = self._TEAM_BY_TRI
if not optdays:
optdays = 1
if optdays == 0:
optdays = 1
if optdays < 0:
optdays = optdays * -1
if optdays > 10:
irc.reply('ERROR: Too many games, has to be less than 10')
return
optteam = optteam.upper()
if optteam not in tids:
irc.reply('ERROR: Invalid team, must be team abbreviation (ex: BOS)')
return
if optteam2:
optteam2 = optteam2.upper()
if optteam == optteam2:
irc.reply('ERROR: Both provided teams are the same')
return
if optteam2 not in tids:
irc.reply('ERROR: Invalid team, must be team abbreviation (ex: BOS)')
return
today = self._getTodayDate()
end = '2019-11-01'
try:
tid = tids[optteam]
except:
irc.reply('ERROR: Something went wrong parsing data')
return
#print(optdays, optteam)
# TBD switch out season=YYYYYYYY automatically
if optteam2:
try:
tid2 = tids[optteam2]
except:
irc.reply('ERROR: Something went wrong parsing data')
return
# url = ("https://statsapi.web.nhl.com/api/v1/schedule?startDate={}&endDate={}" +
# "&expand=schedule.teams,schedule.linescore,schedule.broadcasts.all,schedule.ticket,schedule.game.content.media.epg" +
# "&leaderCategories=&site=en_nhl&teamId={}&teamId={}")
url = ('https://statsapi.mlb.com/api/v1/schedule'
'?sportId=1&startDate={}&endDate={}'
'&hydrate=linescore,team,probablePitcher'
'&teamId={}&teamId={}')
# Fetch content
content = requests.get(url.format(today, end, tid, tid2))
content_json = content.json()
#print(url.format(today, end, tid))
else:
url = ('https://statsapi.mlb.com/api/v1/schedule'
'?sportId=1&startDate={}&endDate={}'
'&hydrate=linescore,team,probablePitcher'
'&teamId={}')
# Fetch content
content = requests.get(url.format(today, end, tid))
content_json = content.json()
#print(url.format(today, end, tid))
games = []
if optteam2:
for idx, item in enumerate(content_json['dates']):
for gidx, _ in enumerate(item['games']):
if optteam in item['games'][gidx]['teams']['away']['team']['abbreviation'] and optteam2 in item['games'][gidx]['teams']['home']['team']['abbreviation']:
string1 = '{}'.format(self._ISODateToEasternTimeNext(item['games'][gidx]['gameDate']))
string2 = '{} @ {}'.format(self._bold(item['games'][gidx]['teams']['away']['team']['abbreviation']), item['games'][gidx]['teams']['home']['team']['abbreviation'])
ppitchers = ''
if 'probablePitcher' in item['games'][gidx]['teams']['away'] and 'probablePitcher' in item['games'][gidx]['teams']['home']:
ppitchers = ' - {} vs {}'.format(item['games'][gidx]['teams']['away']['probablePitcher']['fullName'].split(',')[0], item['games'][gidx]['teams']['home']['probablePitcher']['fullName'].split(',')[0])
games.append(string1 + ' | ' + string2 + ppitchers)
elif optteam2 in item['games'][gidx]['teams']['away']['team']['abbreviation'] and optteam in item['games'][gidx]['teams']['home']['team']['abbreviation']:
string1 = '{}'.format(self._ISODateToEasternTimeNext(item['games'][gidx]['gameDate']))
string2 = '{} @ {}'.format(item['games'][gidx]['teams']['away']['team']['abbreviation'], self._bold(item['games'][gidx]['teams']['home']['team']['abbreviation']))
ppitchers = ''
if 'probablePitcher' in item['games'][gidx]['teams']['away'] and 'probablePitcher' in item['games'][gidx]['teams']['home']:
ppitchers = ' - {} vs {}'.format(item['games'][gidx]['teams']['away']['probablePitcher']['fullName'].split(',')[0], item['games'][gidx]['teams']['home']['probablePitcher']['fullName'].split(',')[0])
games.append(string1 + ' | ' + string2 + ppitchers)
else:
pass
if len(games) == 0:
irc.reply('No future games found for {} vs {}'.format(optteam, optteam2))
return
#print(games)
games = games[:optdays]
if len(games) <= 4:
for game in games:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
else:
#m = len(games)
for game in games[:4]:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
for game in games[4:]:
irc.reply(game)
else:
for idx, item in enumerate(content_json['dates'][:optdays]):
for gidx, _ in enumerate(item['games']):
#print(item['games'][gidx]['teams']['away']['team']['id'])
string1 = '{}'.format(self._ISODateToEasternTimeNext(item['games'][gidx]['gameDate']))
necessary = ''
if item['games'][gidx]['ifNecessary'] == 'Y':
necessary = ' - If Necessary'
#string2 = '{}'.format('{} {}'.format('at', item['games'][gidx]['teams']['home']['team']['abbreviation']) if int(tid) == item['games'][gidx]['teams']['away']['team']['id'] else '{} {}'.format('vs', item['games'][gidx]['teams']['away']['team']['abbreviation']))
if optteam in item['games'][gidx]['teams']['away']['team']['abbreviation']:
string2 = '{} @ {}'.format(self._bold(item['games'][gidx]['teams']['away']['team']['abbreviation']), item['games'][gidx]['teams']['home']['team']['abbreviation'])
else:
string2 = '{} @ {}'.format(item['games'][gidx]['teams']['away']['team']['abbreviation'], self._bold(item['games'][gidx]['teams']['home']['team']['abbreviation']))
ppitchers = ''
if 'probablePitcher' in item['games'][gidx]['teams']['away'] and 'probablePitcher' in item['games'][gidx]['teams']['home']:
ppitchers = ' - {} vs {}'.format(item['games'][gidx]['teams']['away']['probablePitcher']['fullName'].split(',')[0], item['games'][gidx]['teams']['home']['probablePitcher']['fullName'].split(',')[0])
games.append(string1 + ' | ' + string2 + ppitchers + necessary)
if len(games) <= 4:
for game in games:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
else:
#m = len(games)
for game in games[:4]:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
for game in games[4:]:
irc.reply(game)
@wrap([optional('int'), 'somethingwithoutspaces', optional('somethingwithoutspaces')])
def last(self, irc, msg, args, optdays, optteam, optteam2):
"""[<#>] <team> [<team>]
Returns the last # of games for team (or team vs team), defaults to 1 if not given
"""
tids = self._TEAM_BY_TRI
if not optdays:
optdays = -1
numdays = 1
else:
if optdays > 10:
irc.reply('ERROR: Too many games, has to be less than 10')
return
if optdays == 0:
optdays = 1
if optdays < 0:
optdays = optdays * -1
if optdays > 10:
irc.reply('ERROR: Too many games, has to be less than 10')
return
numdays = optdays
optdays = optdays * -1
optteam = optteam.upper()
if optteam not in tids:
irc.reply('ERROR: Invalid team, must be team abbreviation (ex: BOS)')
return
if optteam2:
optteam2 = optteam2.upper()
if optteam == optteam2:
irc.reply('ERROR: Both provided teams are the same')
return
if optteam2 not in tids:
irc.reply('ERROR: Invalid team, must be team abbreviation (ex: BOS)')
return
today = self._getTodayDate()
dt_today = datetime.datetime.strptime(today, "%Y-%m-%d")
dt_yesterday = dt_today - datetime.timedelta(1)
yesterday = dt_yesterday.strftime('%Y-%m-%d')
#last_date = datetime.datetime.today() - datetime.timedelta(days=optdays)
#print(last_date)
end = '2019-03-01'
try:
tid = tids[optteam]
except:
irc.reply('ERROR: Something went wrong parsing data')
return
#print(optdays, optteam)
# TBD switch out season=YYYYYYYY automatically
if optteam2:
try:
tid2 = tids[optteam2]
except:
irc.reply('ERROR: Something went wrong parsing data')
return
url = ('https://statsapi.mlb.com/api/v1/schedule'
'?sportId=1&startDate={}&endDate={}'
'&hydrate=linescore,team,decisions'
'&teamId={}&teamId={}')
# Fetch content
content = requests.get(url.format(end, yesterday, tid, tid2))
content_json = content.json()
#print(url.format(today, end, tid, tid2))
else:
url = ('https://statsapi.mlb.com/api/v1/schedule'
'?sportId=1&startDate={}&endDate={}'
'&hydrate=linescore,team,decisions'
'&teamId={}')
# Fetch content
content = requests.get(url.format(end, yesterday, tid))
content_json = content.json()
#print(url.format(end, yesterday, tid))
games = []
if optteam2: # team vs team
for idx, item in enumerate(content_json['dates']):
for gidx, _ in enumerate(item['games']):
if (optteam in item['games'][gidx]['teams']['away']['team']['abbreviation'] and optteam2 in item['games'][gidx]['teams']['home']['team']['abbreviation']) or (optteam2 in item['games'][gidx]['teams']['away']['team']['abbreviation'] and optteam in item['games'][gidx]['teams']['home']['team']['abbreviation']):
date = self._ISODateToEasternTimeNext(item['games'][gidx]['gameDate'])[:-3]
status_codes = ['DI', 'DC', 'DR', 'DS', 'PI']
#print(item['games'][gidx]['status']['statusCode'])
if item['games'][gidx]['status']['statusCode'] in status_codes:
#print('hi ppd')
home = item['games'][gidx]['teams']['home']['team']['abbreviation']
away = item['games'][gidx]['teams']['away']['team']['abbreviation']
#ppd = ' \x037P\x03'
ppd = ' '
reason = item['games'][gidx]['status']['reason']
str_reply = '{} @ {} \x034PPD\x03 ({})'.format(away, home, reason)
string1 = '{}'.format(date.split(',')[0])
games.append(string1 + ppd + ' | ' + str_reply)
continue
if int(item['games'][gidx]['linescore']['currentInning']) > 9:
ot_type = ' (' + item['games'][gidx]['linescore']['currentInningOrdinal'] + ')'
else:
ot_type = ''
string1 = '{}'.format(date.split(',')[0])
if int(item['games'][gidx]['teams']['away']['score']) > int(item['games'][gidx]['teams']['home']['score']):
away = self._bold(item['games'][gidx]['teams']['away']['team']['abbreviation'])
away_s = self._bold(item['games'][gidx]['teams']['away']['score'])
home = item['games'][gidx]['teams']['home']['team']['abbreviation']
home_s = item['games'][gidx]['teams']['home']['score']
if optteam in away:
result = self._green(' W')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['winner']['fullName'])
except:
pitcher = ''
else:
result = self._red(' L')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['loser']['fullName'])
except:
pitcher = ''
else:
home = self._bold(item['games'][gidx]['teams']['home']['team']['abbreviation'])
home_s = self._bold(item['games'][gidx]['teams']['home']['score'])
away = item['games'][gidx]['teams']['away']['team']['abbreviation']
away_s = item['games'][gidx]['teams']['away']['score']
if optteam in home:
result = self._green(' W')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['winner']['fullName'])
except:
pitcher = ''
else:
result = self._red(' L')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['loser']['fullName'])
except:
pitcher = ''
string3 = '{} {} @ {} {}{}{}'.format(away, away_s, home, home_s, ot_type, pitcher)
games.append(string1 + result + ' | ' + string3)
else:
pass
#games = games[::-1]
games_r = games[optdays:]
games_r.reverse()
if len(games) <= 4:
for game in games_r:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
else:
for game in games_r[:4]:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
for game in games_r[4:]:
irc.reply(game)
else: # just team
for idx, item in enumerate(content_json['dates'][optdays:]):
for gidx, _ in enumerate(item['games']):
date = self._ISODateToEasternTimeNext(item['games'][gidx]['gameDate'])#[:-3]
status_codes = ['DI', 'DC', 'DR', 'DS']
#print(item['games'][gidx]['status']['statusCode'])
if item['games'][gidx]['status']['statusCode'] in status_codes:
#print('hi ppd')
home = item['games'][gidx]['teams']['home']['team']['abbreviation']
away = item['games'][gidx]['teams']['away']['team']['abbreviation']
#ppd = ' \x037P\x03'
ppd = ' '
reason = item['games'][gidx]['status']['reason']
str_reply = '{} @ {} \x034PPD\x03 ({})'.format(away, home, reason)
string1 = '{}'.format(date.split(',')[0])
games.append(string1 + ppd + ' | ' + str_reply)
continue
if int(item['games'][gidx]['linescore']['currentInning']) > 9:
ot_type = ' (F/' + item['games'][gidx]['linescore']['currentInningOrdinal'] + ')'
else:
ot_type = ''
string1 = '{}'.format(date.split(',')[0])
if int(item['games'][gidx]['teams']['away']['score']) > int(item['games'][gidx]['teams']['home']['score']):
away = self._bold(item['games'][gidx]['teams']['away']['team']['abbreviation'])
away_s = self._bold(item['games'][gidx]['teams']['away']['score'])
home = item['games'][gidx]['teams']['home']['team']['abbreviation']
home_s = item['games'][gidx]['teams']['home']['score']
if optteam in away:
result = self._green(' W')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['winner']['fullName'])
except:
pitcher = ''
else:
result = self._red(' L')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['loser']['fullName'])
except:
pitcher = ''
else:
home = self._bold(item['games'][gidx]['teams']['home']['team']['abbreviation'])
home_s = self._bold(item['games'][gidx]['teams']['home']['score'])
away = item['games'][gidx]['teams']['away']['team']['abbreviation']
away_s = item['games'][gidx]['teams']['away']['score']
if optteam in home:
result = self._green(' W')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['winner']['fullName'])
except:
pitcher = ''
else:
result = self._red(' L')
try:
pitcher = ' - {}'.format(item['games'][gidx]['decisions']['loser']['fullName'])
except:
pitcher = ''
string3 = '{} {} @ {} {}{}{}'.format(away, away_s, home, home_s, ot_type, pitcher)
games.append(string1 + result + ' | ' + string3)
games_r = games[::-1]
if len(games) <= 4:
for game in games_r:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
else:
for game in games_r[:4]:
irc.sendMsg(ircmsgs.privmsg(msg.args[0], game))
for game in games_r[4:]:
irc.reply(game)
# @wrap(["text"])
# def recap(self, irc, msg, args, optargs):
# """<team> [<date>]
# Returns a video recap from <team> optionally on <date>.
# """
# # hq = False
# # if '--hq' in optargs or '--HQ' in optargs:
# # hq = True
# # optargs = optargs.strip('--hq')
# # optargs = optargs.strip('--HQ')
# # optargs = optargs.strip()
# # print(optargs)
# tids = self._TEAM_BY_TRI
# # try:
# # gamepk = self._findGamepk("summary", optargs)
# # except:
# # # try looking for yesterday's game
# # #optargs += ' yesterday'
# # try:
# api_url = 'https://statsapi.mlb.com/api/v1/teams/{}/?expand=team.schedule.previous'.format(tids[optargs.upper()])
# print(api_url)
# data = requests.get(api_url)
# data = data.json()
# gamepk = str(data['teams'][0]['previousGameSchedule']['dates'][0]['games'][gidx]['gamePk'])
# # except:
# # irc.reply('Nothing found for given input')
# # return
# if not gamepk:
# irc.reply('Nothing found, check your input')
# return
# url = ("http://statsapi.mlb.com/api/v1/schedule?expand=schedule.game.content.media.epg&leaderCategories=&site=en_nhl&gamePk=" + gamepk)
# content = requests.get(url)
# content_json = content.json()
# print(url)
# info = {}
# #print(gamepk)
# VIDEOurl = {}
# try:
# for item in content_json['dates'][0]['games'][gidx]['content']['media']['epg']:
# if item['title'] == 'Recap':
# info['title'] = item['items'][0]['title'].strip('Recap: ')
# info['blurb'] = item['items'][0]['blurb']
# info['description'] = item['items'][0]['description']
# info['duration'] = "{}m{}s".format(item['items'][0]['duration'].split(':')[0].lstrip('0'), item['items'][0]['duration'].split(':')[1])
# for video in item['items'][0]['playbacks']:
# if 'HTTP_CLOUD_WIRED_60' in video['name']:
# VIDEOurl['hls'] = self._shortenUrl(video['url'])
# if '1800K' in video['name']:
# VIDEOurl['mp4'] = self._shortenUrl(video['url'])
# # if not VIDEOurl:
# # VIDEOurl = 'No video recap available'
# # else:
# # VIDEOurl = self._shortenUrl(VIDEOurl)
# # info['url'] = VIDEOurl
# except:
# VIDEOurl = 'No video recap available'
# if not VIDEOurl:
# VIDEOurl = 'No video recap available'
# #test = {}
# #test['url'] = 'hi this is a test'
# #print(len(test))
# if len(info) <= 1:
# irc.reply('No video recap available.')
# return
# reply_string = ["\x02{}\x02 :: {}".format(info['title'],
# info['blurb']),
# "{}".format(info['description']),
# "\x02MP4:\x02 {} | \x02HLS:\x02 {} | {}".format(VIDEOurl['mp4'], VIDEOurl['hls'], info['duration'])]
# for item in reply_string:
# irc.sendMsg(ircmsgs.privmsg(msg.args[0], item))
def _red(self, string):
"""Returns a red string."""
return ircutils.mircColor(string, 'red')
def _yellow(self, string):
"""Returns a yellow string."""
return ircutils.mircColor(string, 'yellow')
def _green(self, string):
"""Returns a green string."""
return ircutils.mircColor(string, 'green')
def _blue(self, string):
"""Returns a blue string."""
return ircutils.mircColor(string, 'blue')
def _bold(self, string):
"""Returns a bold string."""
return ircutils.bold(string)
def _ul(self, string):
"""Returns an underline string."""
return ircutils.underline(string)
def _bu(self, string):
"""Returns a bold/underline string."""
return ircutils.bold(ircutils.underline(string))
############################
# Date-manipulation helpers
############################
def _getTodayDate(self):
"""Get the current date formatted as "YYYYMMDD".
Because the API separates games by day of start, we will consider and
return the date in the Pacific timezone.
The objective is to avoid reading future games anticipatedly when the
day rolls over at midnight, which would cause us to ignore games
in progress that may have started on the previous day.
Taking the west coast time guarantees that the day will advance only
when the whole continental US is already on that day."""
today = self._pacificTimeNow().date()
today_iso = today.isoformat()
return today_iso #.replace('-', '')
def _easternTimeNow(self):
return datetime.datetime.now(pytz.timezone('US/Eastern'))
def _pacificTimeNow(self):
return datetime.datetime.now(pytz.timezone('US/Pacific'))
def _ISODateToEasternTimeNext(self, iso):
"""Convert the ISO date in UTC time that the API outputs into an
Eastern time formatted with am/pm. (The default human-readable format
for the listing of games)."""
date = dateutil.parser.parse(iso)
date_eastern = date.astimezone(pytz.timezone('US/Eastern'))
eastern_time = date_eastern.strftime('%a %m/%d, %I:%M %p %Z')
return "{}".format(eastern_time) # Strip the seconds
def _fetchPitchers(self, games, team, override):
"""fetch pitchers"""
data = {}
current_only = False
ss_dh = False
test_status = 'I'
#print(games)
for idx, game in enumerate(games):
data['Game {}'.format(idx+1)] = []
# if len(games) > 1:
# ss_dh = True
# data.append('\x02Game {}\x02'.format(idx+1))
gpk = game['id']
#print(game['status'])
if 'I' in game['status']:
current_only = True if not override else False
if 'S' == game['status']:
data['Game {}'.format(idx+1)] = False
break
url = 'https://statsapi.mlb.com/api/v1/game/{}/boxscore'.format(gpk)
#print(url)
temp = requests.get(url).json()
for teams in temp['teams']:
#print(temp['teams'][teams]['team']['id'])
if int(team) == temp['teams'][teams]['team']['id']:
pitcher_ids = temp['teams'][teams]['pitchers']
for pitcher_id in pitcher_ids:
for player in temp['teams'][teams]['players']:
if int(pitcher_id) == temp['teams'][teams]['players'][player]['person']['id']:
if current_only:
#if temp['teams'][teams]['players'][player]['gameStatus']['isCurrentPitcher']:
data['Game {}'.format(idx+1)] = [temp['teams'][teams]['players'][player]]
else:
data['Game {}'.format(idx+1)].append(temp['teams'][teams]['players'][player])
#print(data)
#print(data)
#print(current_only, data)
if current_only and not data:
return ['No current pitcher for {} (use --all to see every pitcher)'.format(self._TEAM_BY_ID[team])]
if not data:
return None
if len(data) > 1:
for d in data:
if not data[d]:
data[d] = ['No current pitcher for {} in {} (use --all to see every pitcher)'.format(self._TEAM_BY_ID[team], d)]
else:
for d in data:
if not data[d]:
data[d] = ['No current pitcher for {} (use --all to see every pitcher)'.format(self._TEAM_BY_ID[team])]
return data
def _replyPitchersAsString(self, pitchers):
"""parses and returns pitchers"""
resp = []
width = 0
def _iteratePitchers(pitchers):
resp = []
width = 0
#print(pitchers)
for idx, pitcher in enumerate(pitchers):
#print(pitcher)
if type(pitcher) == str:
continue
name = pitcher['person']['fullName']
name = ' '.join(name.split())
suffixes = ['jr.']
lname = -1
for suffix in suffixes:
if name.split(' ')[lname].lower() in suffix:
lname = -2
else:
lname = -1
if len(name.split(' ')[lname]) > width:
width = len(name.split(' ')[lname])
for pitcher in pitchers:
if type(pitcher) == str:
resp.append(pitcher)
continue
name = pitcher['person']['fullName']
name = ' '.join(name.split())
stats = pitcher['stats']['pitching']
try:
era = '{:.2f}'.format((stats['earnedRuns']/float(stats['inningsPitched']))*9)
except:
if float(stats['inningsPitched']) == 0.0 and stats['earnedRuns'] > 0:
era = ''
else:
era = '0.00'
try:
opBA = '{:.3f}'.format((stats['hits'])/(stats['battersFaced'] - stats['baseOnBalls']))
except:
opBA = '.000'
suffixes = ['jr.']
lname = -1
#print(name.split(' ')[lname].lower())
for suffix in suffixes:
#print(suffix)
if name.split(' ')[lname].lower() in suffix:
#print('hi')
lname = -2
else:
lname = -1
string = ('\x02\x0312{}. {:{width}}\x03 IP:\x02 {} '
'\x02H:\x02 {} '
'\x02R:\x02 {} '
'\x02ER:\x02 {} '
'\x02BB:\x02 {} '
'\x02K:\x02 {} '
'\x02HR:\x02 {} '
'\x02BF:\x02 {:>2} '
'\x02Pit:\x02 {:>3} '
'\x02B-S:\x02 {:>2}-{:<2} '
'\x02ERA:\x02 {:>6} '
'\x02OpBA:\x02 {}').format(
name[0],
name.split(' ')[lname],
'0' if not stats.get('inningsPitched') else stats.get('inningsPitched'),
'0' if not stats.get('hits') else stats.get('hits'),
'0' if not stats.get('runs') else stats.get('runs'),
'0' if not stats.get('earnedRuns') else stats.get('earnedRuns'),
'0' if not stats.get('baseOnBalls') else stats.get('baseOnBalls'),
'0' if not stats.get('strikeOuts') else stats.get('strikeOuts'),
'0' if not stats.get('homeRuns') else stats.get('homeRuns'),
'0' if not stats.get('battersFaced') else stats.get('battersFaced'),
'0' if not stats.get('pitchesThrown') else stats.get('pitchesThrown'),
'0' if not stats.get('balls') else stats.get('balls'),
'0' if not stats.get('strikes') else stats.get('strikes'),
era,
opBA,
width=str(width))
resp.append(string)
return resp
#print(len(pitchers))
if len(pitchers) > 1:
# double header
#print('hi')
resp = {}
for game in pitchers:
#print(pitchers[game])
if "No current pitcher" not in pitchers[game][0]:
resp[game] = _iteratePitchers(pitchers[game])
else:
g1_pitchers = pitchers['Game 1']
resp = _iteratePitchers(g1_pitchers)
#print(resp)
return resp
def _sortGames(self, games):
"""sort based on status"""
#sorted_games = sorted(games, key=lambda k: k['timestamp'])
sorted_games = sorted(games, key=lambda k: k['ended'])
return sorted_games
def _replyAsString(self, team, games, tz='US/Eastern', tv=False):
"""parse games and return a string"""
tmp_dt = '\x02{}\x02: '.format(games[0]['date'])
def _parseStatus(state, inning):
if not state:
state = 'F'
#print(state)
if 'T' in state or 'B' in state:
if 'T' in state:
resp = '\x033{}{}\x03'.format('', inning)
else:
resp = '\x033{}{}\x03'.format('', inning)
elif 'M' in state:
resp = '\x037{}{}\x03'.format(state, inning)
elif 'E' in state or 'F' in state:
if inning == 9 and 'E' not in state:
resp = '\x034{}\x03'.format(state)
elif 'E' in state:
resp = '\x037{}{}\x03'.format(state, inning)
else:
resp = '\x034{}/{}\x03'.format(state, inning)
else:
resp = '{}{}'.format(state, inning)
return resp
def _parseTimezone(time, tz='US/Eastern'):
if not tz:
tz = 'US/Eastern'
if 'Game 2' == time:
return time
def _checkTarget(target):
"""check input among common tz"""
target2 = target.upper()
common = {'CT': 'US/Central',
'CDT': 'US/Central',
'CST': 'US/Central',
'MT': 'US/Mountain',
'MDT': 'US/Mountain',
'MST': 'US/Mountain',
'PT': 'US/Pacific',
'PDT': 'US/Pacific',
'PST': 'US/Pacific',
'ET': 'US/Eastern',
'EDT': 'US/Eastern',
'EST': 'US/Eastern',
'CENTRAL': 'US/Central',
'EASTERN': 'US/Eastern',
'PACIFIC': 'US/Pacific',
'MOUNTAIN': 'US/Mountain'}
if target2 in common:
target = common[target2]
#print(target)
return target
tz = _checkTarget(tz)
return pendulum.parse(time, strict=False).in_tz(tz).format('h:mm A zz')
tmp = []
if len(games) == 1:
team = True
for game in games:
#print(game['homeTeam'], game['status'])
if game['status'] == 'I':
status = _parseStatus(game['state'], game['inning'])
if '' in status and game['risp']:
if 'Corners' in game['runners'] or 'Loaded' in game['runners'] or '3rd' in game['runners']:
game['homeTeam']['abbr'] = '\x034{}\x03'.format(game['homeTeam']['abbr'])
game['homeTeam']['full'] = '\x034{}\x03'.format(game['homeTeam']['full'])
elif '2nd' in game['runners']:
game['homeTeam']['abbr'] = '\x037{}\x03'.format(game['homeTeam']['abbr'])
game['homeTeam']['full'] = '\x037{}\x03'.format(game['homeTeam']['full'])
else:
if 'Corners' in game['runners'] or 'Loaded' in game['runners'] or '3rd' in game['runners']:
game['awayTeam']['abbr'] = '\x034{}\x03'.format(game['awayTeam']['abbr'])
game['awayTeam']['full'] = '\x034{}\x03'.format(game['awayTeam']['full'])
elif '2nd' in game['runners']:
game['awayTeam']['abbr'] = '\x037{}\x03'.format(game['awayTeam']['abbr'])
game['awayTeam']['full'] = '\x037{}\x03'.format(game['awayTeam']['full'])
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
if game['homeScore'] > game['awayScore']:
tmp_st = '{} {} \x02{} {}\x02 {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
elif game['awayScore'] > game['homeScore']:
tmp_st = '\x02{} {}\x02 {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
else:
tmp_st = '{} {} {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
if game['broadcasts'] and tv:
if game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' [\x02TV:\x02 {} | \x02Radio:\x02 {}]'.format(
', '.join(tv for tv in game['broadcasts']['tv']),
', '.join(radio for radio in game['broadcasts']['radio']))
elif game['broadcasts']['tv'] and not game['broadcasts']['radio']:
watch = ' [\x02TV:\x02 {}]'.format(
', '.join(tv for tv in game['broadcasts']['tv']))
elif not game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' [\x02Radio:\x02 {}]'.format(
', '.join(radio for radio in game['broadcasts']['radio']))
else:
watch = ' [No TV or Radio broadcasts found]'
tmp_st += watch
elif not game['broadcasts'] and tv:
tmp_st += ' [No TV or Radio broadcasts found]'
if team and ('M' not in status and 'E' not in status) and not tv:
if game['pitcher'] and game['batter']:
pb = ' | \x02P:\x02 {}, \x02AB:\x02 {} '.format(game['pitcher'], game['batter'])
else:
pb = ''
if game['runners']:
ro = ' | \x037Runners\x03: {}'.format(game['runners'])
else:
ro = ''
tmp_st += ' | \x033B\x03:{} \x037S\x03:{} \x034O\x03:{}{}{}| {}'
tmp_st = tmp_st.format(game['balls'], game['strikes'], game['outs'], ro, pb, game['last'])
elif team and ('M' in status or 'E' in status) and not tv:
tmp_st += ' | {}'
tmp_st = tmp_st.format(game['last'])
#if team:
#print(game['id'])
tmp.append(tmp_st)
elif ('F' in game['status'] or 'O' in game['status']) and not team:
status = _parseStatus(game['state'], game['inning'])
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
if game['homeScore'] > game['awayScore']:
tmp_st = '{} {} \x02{} {}\x02 {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
elif game['awayScore'] > game['homeScore']:
tmp_st = '\x02{} {}\x02 {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
else:
tmp_st = '{} {} {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
tmp.append(tmp_st)
elif (game['status'] == 'S' or game['status'] == 'P') and team and not tv:
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
tmp_st = '{} {} @ {} {} {}'.format(away_disp, game['awayRecord'],
home_disp, game['homeRecord'],
game['dt'] if game['dh'] else _parseTimezone(game['dt'], tz))
pitchers = ' | {} vs {}'.format(game['awayProb'], game['homeProb'])
tmp_st += pitchers
#print(game['broadcasts'])
if game['broadcasts']:
if game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' | \x02TV:\x02 {} | \x02Radio:\x02 {}'.format(
', '.join(tv for tv in game['broadcasts']['tv']),
', '.join(radio for radio in game['broadcasts']['radio']))
elif game['broadcasts']['tv'] and not game['broadcasts']['radio']:
watch = ' | \x02TV:\x02 {}'.format(
', '.join(tv for tv in game['broadcasts']['tv']))
elif not game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' | \x02Radio:\x02 {}'.format(
', '.join(radio for radio in game['broadcasts']['radio']))
else:
watch = ''
tmp_st += watch
if game['description']:
tmp_st += ' | {}'.format(game['description'])
tmp.append(tmp_st)
elif ('F' in game['status'] or 'O' in game['status']) and team:
status = _parseStatus(game['state'], game['inning'])
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
if game['homeScore'] > game['awayScore']:
tmp_st = '{} {} \x02{} {}\x02 {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
elif game['awayScore'] > game['homeScore']:
tmp_st = '\x02{} {}\x02 {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
else:
tmp_st = '{} {} {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
wls_line = ' | \x033W:\x03 {} \x034L:\x03 {}'.format(
game['decisions']['W'], game['decisions']['L'])
if game['decisions'].get('S'):
wls_line += ' \x037S:\x03 {}'.format(game['decisions']['S'])
tmp_st += wls_line
if game['homers']:
hr_str = ' | \x02HR: {}\x02: {} \x02{}\x02: {}'.format(
game['awayTeam']['abbr'],
' '.join(item for item in game['homers'][game['awayTeam']['abbr']]),
game['homeTeam']['abbr'],
' '.join(item for item in game['homers'][game['homeTeam']['abbr']]))
tmp_st += hr_str
tmp.append(tmp_st)
elif game['status'] == 'DI' or game['status'] == 'DC' or game['status'] == 'DS' or game['status'] == 'DR' \
or game['status'] == 'DV' or game['status'] == 'DG':
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
tmp_st = '{} @ {} \x034PPD\x03'.format(away_disp, home_disp)
if game['reason'] and team:
tmp_st += ' - {}'.format(game['reason'])
tmp.append(tmp_st)
# elif game['status'] == 'DI':
# tmp_st = '{} @ {} \x034PPD\x03'.format(game['awayTeam'], game['homeTeam'])
# if game['reason'] and team:
# tmp_st += ' - {}'.format(game['reason'])
# tmp.append(tmp_st)
elif game['status'] == 'PW':
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
tmp_st = '{} @ {} {} - Warmup'.format(away_disp, home_disp,
_parseTimezone(game['dt'], tz))
if team:
pitchers = ' | {} vs {}'.format(game['awayProb'], game['homeProb'])
tmp_st += pitchers
tv = True
if tv:
if game['broadcasts']:
if game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' [\x02TV:\x02 {} | \x02Radio:\x02 {}]'.format(
', '.join(tv for tv in game['broadcasts']['tv']),
', '.join(radio for radio in game['broadcasts']['radio']))
elif game['broadcasts']['tv'] and not game['broadcasts']['radio']:
watch = ' [\x02TV:\x02 {}]'.format(
', '.join(tv for tv in game['broadcasts']['tv']))
elif not game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' [\x02Radio:\x02 {}]'.format(
', '.join(radio for radio in game['broadcasts']['radio']))
else:
watch = ' [No TV or Radio broadcasts found]'
else:
watch = ' [No TV or Radio broadcasts found]'
tmp_st += watch
tmp.append(tmp_st)
elif game['status'] == 'PC' or game['status'] == 'PS' or game['status'] == 'PR' or game['status'] == 'PI':
status = _parseStatus(game['state'], game['inning'])
if game['homeScore'] > game['awayScore']:
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
tmp_st = '{} {} \x02{} {}\x02 {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
elif game['awayScore'] > game['homeScore']:
tmp_st = '\x02{} {}\x02 {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
else:
tmp_st = '{} {} {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
status)
tmp_st += ' \x037Delay\x03'
if game['reason'] and team:
tmp_st += ' - {}'.format(game['reason'])
tmp.append(tmp_st)
elif game['status'] == 'IW' or game['status'] == 'IC' or game['status'] == 'IS' or game['status'] == 'IR':
# status = _parseStatus(game['state'], game['inning'])
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
if game['homeScore'] > game['awayScore']:
tmp_st = '{} {} \x02{} {}\x02'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
)
elif game['awayScore'] > game['homeScore']:
tmp_st = '\x02{} {}\x02 {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
)
else:
tmp_st = '{} {} {} {}'.format(away_disp,
game['awayScore'],
home_disp,
game['homeScore'],
)
tmp_st += ' \x037Delay\x03'
if game['reason'] and team:
tmp_st += ' - {}'.format(game['reason'])
tmp.append(tmp_st)
else:
if team:
away_disp = game['awayTeam']['full']
home_disp = game['homeTeam']['full']
else:
away_disp = game['awayTeam']['abbr']
home_disp = game['homeTeam']['abbr']
tmp_st = '{} @ {} {}'.format(away_disp, home_disp,
game['dt'] if game['dh'] else _parseTimezone(game['dt'], tz))
if game['status'] in self._STATUSES.keys() \
and game['status'] not in ['S', 'P', 'D']:
tmp_st += ' - {}'.format(self._STATUSES[game['status']])
if tv:
if game['broadcasts']:
if game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' [\x02TV:\x02 {} | \x02Radio:\x02 {}]'.format(
', '.join(tv for tv in game['broadcasts']['tv']),
', '.join(radio for radio in game['broadcasts']['radio']))
elif game['broadcasts']['tv'] and not game['broadcasts']['radio']:
watch = ' [\x02TV:\x02 {}]'.format(
', '.join(tv for tv in game['broadcasts']['tv']))
elif not game['broadcasts']['tv'] and game['broadcasts']['radio']:
watch = ' [\x02Radio:\x02 {}]'.format(
', '.join(radio for radio in game['broadcasts']['radio']))
else:
watch = ' [No TV or Radio broadcasts found]'
else:
watch = ' [No TV or Radio broadcasts found]'
tmp_st += watch
tmp.append(tmp_st)
if len(tmp) > 1 and team:
tmp_dt = [tmp_dt + tmp[0]]
for item in tmp[1:]:
tmp_dt.append(item)
return tmp_dt
tmp_len = len(tmp)
if tmp_len > 12:
split_at_pre = ":{}".format(tmp_len // 2)
split_at_post = "{}:".format(tmp_len // 2)
split_at = tmp_len // 2
#print(split_at)
tmp_dt = (tmp_dt + ' | '.join(item for item in tmp[:split_at]), ' | '.join(item for item in tmp[split_at:]))
else:
tmp_dt += ' | '.join(item for item in tmp)
return tmp_dt
def _parseInput(self, args=None):
"""parse user input from mlb2"""
# return team, date, timezone
tz = 'US/Eastern'
date = None
team = None
is_date = None
if not args:
return team, date, tz
arg_array = []
for arg in args.split(' '):
arg_array.append(arg)
for idx, arg in enumerate(arg_array):
#print(arg)
if '--tz' in arg:
#print(arg_array[idx+1])
try:
tz = arg_array[idx+1]
except:
tz = 'US/Eastern'
if arg.lower() in self._FUZZY_DAYS or arg[:3].lower() in self._FUZZY_DAYS:
date = self._parseDate(arg)
#print(date)
#date = pendulum.parse(date).in_tz(tz)
try:
arg = arg.strip('-')
arg = arg.strip('/')
if arg[0].isdigit() and arg[1].isdigit() and arg[2].isalpha():
if arg[-1].isdigit():
yr = arg[-2:]
mnth = " ".join(re.findall("[a-zA-Z]+", arg))
#print(mnth,yr)
rebuild = '{}-{}-{}'.format(mnth, arg[:2], yr)
else:
rebuild = arg[2:] + arg[:2]
#print('both', rebuild)
elif arg[0].isdigit() and arg[1].isalpha():
rebuild = arg[1:] + arg[0]
#print('one', rebuild)
else:
rebuild = arg
#print(rebuild)
is_date = pendulum.parse(rebuild, strict=False)
#print(is_date)
except:
is_date = None
if is_date:
date = is_date.format('YYYY-MM-DD')
if arg.upper() in self._TEAM_BY_TRI:
team = str(self._TEAM_BY_TRI[arg.upper()])
elif arg.lower() in self._TEAM_BY_NICK:
abbr = str(self._TEAM_BY_NICK[arg.lower()])
team = str(self._TEAM_BY_TRI[abbr])
# else:
# return team, date, tz
return team, date, tz
def _parseDate(self, string):
"""parse date"""
date = string[:3].lower()
if date in self._FUZZY_DAYS or string.lower() in self._FUZZY_DAYS:
if date == 'yes':
date_string = pendulum.yesterday('US/Pacific').format('YYYY-MM-DD')
#print(date_string)
return date_string
elif date == 'tod' or date == 'ton':
date_string = pendulum.now('US/Pacific').format('YYYY-MM-DD')
return date_string
elif date == 'tom':
date_string = pendulum.tomorrow('US/Pacific').format('YYYY-MM-DD')
return date_string
elif date == 'sun':
date_string = pendulum.now('US/Pacific').next(pendulum.SUNDAY).format('YYYY-MM-DD')
return date_string
elif date == 'mon':
date_string = pendulum.now('US/Pacific').next(pendulum.MONDAY).format('YYYY-MM-DD')
return date_string
elif date == 'tue':
date_string = pendulum.now('US/Pacific').next(pendulum.TUESDAY).format('YYYY-MM-DD')
return date_string
elif date == 'wed':
date_string = pendulum.now('US/Pacific').next(pendulum.WEDNESDAY).format('YYYY-MM-DD')
return date_string
elif date == 'thu':
date_string = pendulum.now('US/Pacific').next(pendulum.THURSDAY).format('YYYY-MM-DD')
return date_string
elif date == 'fri':
date_string = pendulum.now('US/Pacific').next(pendulum.FRIDAY).format('YYYY-MM-DD')
return date_string
elif date == 'sat':
date_string = pendulum.now('US/Pacific').next(pendulum.SATURDAY).format('YYYY-MM-DD')
return date_string
def _fetchGames(self, team=None, date=None, league=None):
"""fetches games for mlb2"""
team = 'all' if not team else team
#print(team)
date = pendulum.now('US/Pacific').to_date_string() if not date else date
if league:
url = ('https://statsapi.mlb.com/api/v1/schedule'
'?sportId={}&leagueId={}&date={}'
'&hydrate=team(leaders(showOnPreview('
'leaderCategories=[homeRuns,runsBattedIn,'
'battingAverage],statGroup=[pitching,'
'hitting]))),linescore(matchup,runners),'
'flags,liveLookin,review,broadcasts(all),'
'decisions,person,probablePitcher,stats,'
'homeRuns,previousPlay,game(content('
'media(featured,epg),summary),tickets),'
'seriesStatus(useOverride=true)').format(league[0], league[1], date)
else:
url = self._SCOREBOARD_ENDPOINT.format(date)
if 'all' not in team:
url += '&teamId={}'.format(team)
#print(url)
try:
data = requests.get(url).json()
except:
return None
try:
games = data['dates'][0]['games']
except:
return None
return games
def _parseGames(self, games, date, team=None):
"""parse games for mlb2"""
#print('http://statsapi.mlb.com/api/v1/game/{}/linescore'.format(games[0]['gamePk']))
#print(games)
if team:
#date = pendulum.now('US/Pacific').to_date_string() if not date else date
#games_url = self._SCOREBOARD_ENDPOINT.format(date)
#games_url += '&teamId={}'.format(team)
#games = requests.get(games_url).json()
#print(games_url)
try:
#games = games['dates'][0]['games']
tmpg = []
for game in games:
#print(game['teams']['away']['team']['id'], game['teams']['home']['team']['id'])
if str(team) in [str(game['teams']['away']['team']['id']), str(game['teams']['home']['team']['id'])]:
tmpg.append(game)
if tmpg:
games = tmpg
else:
return None
except:
return None
#print(games)
def _parseLastPlay():
#print('len:', len(games))
if len(games) == 1:
url = 'http://statsapi.mlb.com/api/v1/game/{}/playByPlay'
#print(url)
url = url.format(games[0]['gamePk'])
print(url, 'http://statsapi.mlb.com/api/v1/game/{}/playByPlay'.format(games[0]['gamePk']))
data = requests.get(url)
data = data.json()
plays = reversed(data['allPlays'])
for play in plays:
if play['about']['isComplete'] == True:
last_play = play['result']['description']
break
#print(last_play)
return last_play
def _parseAllAtBats():
if len(games) == 1:
url = 'https://statsapi.mlb.com/api/v1.1/game/{}/feed/live'
#print(url)
url = url.format(games[0]['gamePk'])
print(url)
data = requests.get(url)
data = data.json()
plays = data['liveData']['plays']['allPlays']
#print(len(plays))
desc = ''
at_bats = {}
for play in plays:
#print(play)
if 'result' in play:
if play['result'].get('type') == 'atBat':
if play['about'].get('isComplete'):
atidx = play['atBatIndex']
#print(atidx)
res = play['result']['description'].strip()
res = ' '.join(res.split())
desc = ' | \x02Result:\x02 {} :: {}'.format(play['result']['event'],
res)
#print(desc)
count = '\x02B:\x02{} \x02S:\x02{} \x02O:\x02{}'.format(play['count']['balls'],
play['count']['strikes'],
play['count']['outs'])
#print(count)
batter = '\x02AB:\x02 {}'.format(play['matchup']['batter']['fullName'])
#print(batter)
pitcher = '\x02P:\x02 {}'.format(play['matchup']['pitcher']['fullName'])
#print(pitcher)
pitches = []
pit_num = 0
if play['playEvents']:
for idx, pitch in enumerate(play['playEvents']):
if pitch['isPitch']:
pit_num += 1
t = '({}){} - \x02{}mph {}\x02'.format(pit_num, pitch['details']['description'],
pitch['pitchData']['startSpeed'],
pitch['details']['type']['description'])
pitches.append(t)
#print(pitches)
at_bat = '{} | {} | {} | {}{}'.format(batter, pitcher, count,
' \x034::\x03 '.join(p for p in pitches),
desc)
#print(at_bat)
at_bats[str(atidx)] = [at_bat, atidx+1, play['matchup']['batter']['fullName']]
#print(at_bats)
return at_bats
def _parseAtBat():
if len(games) == 1:
url = 'https://statsapi.mlb.com/api/v1.1/game/{}/feed/live'
#print(url)
url = url.format(games[0]['gamePk'])
print(url)
data = requests.get(url)
data = data.json()
play = data['liveData']['plays']['currentPlay']
#print(play)
desc = ''
if 'result' in play:
if play['about']['isComplete']:
res = play['result']['description'].strip()
res = ' '.join(res.split())
desc = ' | \x02Result:\x02 {} :: {}'.format(play['result']['event'],
res)
#print('desc')
count = '\x02B:\x02{} \x02S:\x02{} \x02O:\x02{}'.format(play['count']['balls'],
play['count']['strikes'],
play['count']['outs'])
#print('count')
batter = '\x02AB:\x02 {}'.format(play['matchup']['batter']['fullName'])
#print('batter')
pitcher = '\x02P:\x02 {}'.format(play['matchup']['pitcher']['fullName'])
#print('pitcher')
pitches = []
pit_num = 0
if play['playEvents']:
for idx, pitch in enumerate(play['playEvents']):
if pitch['isPitch']:
pit_num += 1
t = '({}){} - \x02{}mph {}\x02'.format(pit_num, pitch['details']['description'],
pitch['pitchData']['startSpeed'],
pitch['details']['type']['description'])
pitches.append(t)
#print('pitches')
at_bat = '{} | {} | {} | {}{}'.format(batter, pitcher, count,
' \x034::\x03 '.join(p for p in pitches),
desc)
#print(at_bat)
return at_bat
def _parsePitcher(pitcher):
name = pitcher['lastInitName']
pitches = pitcher['stats'][1]['stats']['pitchesThrown']
tmp = '{} ({})'.format(name, pitches)
return tmp
def _parseBatter(batter):
name = batter['lastInitName']
line = '{}/{}'.format(batter['stats'][0]['stats']['hits'], batter['stats'][0]['stats']['atBats'])
tmp = '{} ({})'.format(name, line)
return tmp
def _parseRunners(runners):
first = True if runners.get('first') else False
second = True if runners.get('second') else False
third = True if runners.get('third') else False
#print(first, second, third)
if first and not second and not third:
resp = '1st'
shrt = '\x039⠠\x03'
risp = False
elif first and second and not third:
resp = '1st and 2nd'
shrt = ''
risp = True
elif first and second and third:
resp = 'Loaded'
shrt = ''
risp = True
elif not first and second and not third:
resp = '2nd'
shrt = ''
risp = True
elif not first and not second and third:
resp = "3rd"
shrt = '\x034⠄\x03'
risp = True
elif not first and not second and not third:
resp = ''
shrt = ''
risp = False
elif first and not second and third:
resp = 'Corners'
shrt = ''
risp = True
elif not first and second and third:
resp = '2nd and 3rd'
shrt = ''
risp = True
return resp, shrt, risp
tmp = []
for game in games:
dh = False
description = None
gamePk = game['gamePk']
dt = game['gameDate']
#print(dt)
timestamp = pendulum.parse(dt).in_tz('US/Eastern').int_timestamp
#print(timestamp)
date = pendulum.parse(game['gameDate']).in_tz('US/Eastern').format('MM/DD/YY')
time = pendulum.parse(game['gameDate']).in_tz('US/Eastern').format('h:mm A zz')
#print(date, time)
status = game['status']['statusCode']
reason = game['status'].get('reason')
at_bat = ''
at_bats = {}
try:
description = game['description']
except:
description = None
if game['doubleHeader'] == 'Y' or game['doubleHeader'] == 'S':
#print('doubleheader')
if game['gameNumber'] > 1:
#print('game 2+')
timestamp = pendulum.parse(dt).in_tz('US/Eastern')
timestamp = timestamp.add(days=1)
timestamp = timestamp.int_timestamp
dt = 'Game {}'.format(game['gameNumber'])
dh = True
#print(time)
try:
broadcasts = {}
broadcasts['tv'] = []
broadcasts['radio'] = []
for channel in game['broadcasts']:
if 'TV' in channel['type']:
if 'MLB.com' not in channel['name'] and 'out-of-market' not in channel['name']:
broadcasts['tv'].append(channel['name'])
elif 'M' in channel['type']:
if 'MLB.com' not in channel['name'] and 'out-of-market' not in channel['name']:
broadcasts['radio'].append(channel['name'])
broadcasts['tv'] = [*{*broadcasts['tv']}]
broadcasts['radio'] = [*{*broadcasts['radio']}]
except:
broadcasts = None
away_team = game['teams']['away']['team']['abbreviation']
home_team = game['teams']['home']['team']['abbreviation']
away_full = game['teams']['away']['team']['name']
home_full = game['teams']['home']['team']['name']
away_record = '({}-{})'.format(game['teams']['away']['leagueRecord']['wins'],
game['teams']['away']['leagueRecord']['losses'])
home_record = '({}-{})'.format(game['teams']['home']['leagueRecord']['wins'],
game['teams']['home']['leagueRecord']['losses'])
try:
try:
away_era = game['teams']['away']['probablePitcher']['stats'][1]['stats']['era']
away_wins = game['teams']['away']['probablePitcher']['stats'][1]['stats']['wins']
away_loss = game['teams']['away']['probablePitcher']['stats'][1]['stats']['losses']
away_line = ' {}/{}-{}'. format(away_era, away_wins, away_loss)
except:
away_line = ''
try:
home_era = game['teams']['home']['probablePitcher']['stats'][1]['stats']['era']
home_wins = game['teams']['home']['probablePitcher']['stats'][1]['stats']['wins']
home_loss = game['teams']['home']['probablePitcher']['stats'][1]['stats']['losses']
home_line = ' {}/{}-{}'. format(home_era, home_wins, home_loss)
except:
home_line = ''
try:
away_prob = '{} ({}HP{})'.format(
game['teams']['away']['probablePitcher']['lastInitName'],
game['teams']['away']['probablePitcher']['pitchHand']['code'],
away_line)
except:
away_prob = 'TBD'
try:
home_prob = '{} ({}HP{})'.format(
game['teams']['home']['probablePitcher']['lastInitName'],
game['teams']['home']['probablePitcher']['pitchHand']['code'],
home_line)
except:
home_prob = 'TBD'
except:
away_prob = 'TBD'
home_prob = 'TBD'
away_score = game['teams']['away'].get('score')
home_score = game['teams']['home'].get('score')
#print('scores', away_score, home_score)
if not away_score:
away_score = 0
if not home_score:
home_score = 0
try:
inning = game['linescore'].get('currentInning')
except:
inning = 1
try:
state = game['linescore'].get('inningState')
except:
state = None
#print(state)
balls = '0'
strikes = '0'
outs = '0'
pitcher = None
batter = None
runners = None
short_runners = None
risp = False
if not state:
if 'F' in status or 'O' in status:
state = 'F'
ended = True
last_play = ''
elif status == 'DI' or status == 'DC' or status == 'DS' or status == 'DR' \
or status == 'DV' or status == 'DG':
state = state
ended = True
last_play = ''
else:
state = None
ended = False
last_play = ''
else:
if 'F' in status or 'O' in status:
state = 'F'
ended = True
last_play = ''
elif status == 'DI' or status == 'DC' or status == 'DS' or status == 'DR' \
or status == 'DV' or status == 'DG':
state = state
ended = True
last_play = ''
else:
state = state[:1]
ended = False
if 'I' in status:
try:
pitcher = _parsePitcher(game['linescore']['defense']['pitcher'])
except:
pitcher = None
try:
batter = _parseBatter(game['linescore']['offense']['batter'])
except:
batter = None
try:
runners, short_runners, risp = _parseRunners(game['linescore']['offense'])
except:
runners = None
short_runners = None
risp = False
try:
try:
last_play = _parseLastPlay()
last_play = last_play.strip()
last_play = " ".join(last_play.split())
except:
last_play = game['previousPlay']['result'].get('description').strip()
last_play = " ".join(last_play.split())
except:
last_play = ''
try:
at_bat = _parseAtBat()
except:
at_bat = ''
try:
at_bats = _parseAllAtBats()
except:
at_bats = {}
try:
balls = str(game['linescore']['balls'])
except:
balls = balls
try:
strikes = str(game['linescore']['strikes'])
except:
strikes = strikes
try:
outs = str(game['linescore']['outs'])
except:
outs = outs
else:
last_play = ''
at_bat = ''
at_bats = {}
if 'F' in status or 'O' in status:
decisions = {}
try:
decisions['W'] = '{} ({}/{}-{})'.format(
game['decisions']['winner']['lastInitName'],
game['decisions']['winner']['stats'][3]['stats']['era'],
game['decisions']['winner']['stats'][3]['stats']['wins'],
game['decisions']['winner']['stats'][3]['stats']['losses'])
except:
decisions['W'] = 'TBD'
try:
decisions['L'] = '{} ({}/{}-{})'.format(
game['decisions']['loser']['lastInitName'],
game['decisions']['loser']['stats'][3]['stats']['era'],
game['decisions']['loser']['stats'][3]['stats']['wins'],
game['decisions']['loser']['stats'][3]['stats']['losses'])
except:
decisions['L'] = 'TBD'
try:
save = game['decisions'].get('save')
except:
save = None
if save:
decisions['S'] = '{} ({}/{}-{}/{}-{})'.format(
save['lastInitName'],
save['stats'][3]['stats']['era'],
save['stats'][3]['stats']['wins'],
save['stats'][3]['stats']['losses'],
save['stats'][3]['stats']['saves'],
save['stats'][3]['stats']['blownSaves'])
homers = {}
homeRuns = game.get('homeRuns')
if homeRuns:
homers[away_team] = []
homers[home_team] = []
for item in homeRuns:
#print(item)
try:
name = item['matchup']['batter']['lastInitName']
except:
name = item['matchup']['batter']['fullName']
num = item['matchup']['batter']['stats'][2]['stats']['homeRuns']
string = '{}({})'.format(name,num)
if 'top' in item['about']['halfInning']:
homers[away_team].append(string)
elif 'bot' in item['about']['halfInning']:
homers[home_team].append(string)
if not homers[away_team]:
homers[away_team] = ['None']
if not homers[home_team]:
homers[home_team] = ['None']
if homers[away_team]:
#print('hi')
homers[away_team] = [*{*homers[away_team]}]
if homers[home_team]:
#print('bye')
homers[home_team] = [*{*homers[home_team]}]
else:
homers = None
decisions = None
#print(time)
tmp.append({'id': gamePk, 'date': date, 'time': time, 'dt': dt, 'dh': dh, 'timestamp': timestamp,
'awayTeam': {'abbr': away_team, 'full': away_full}, 'awayScore': away_score,
'homeTeam': {'abbr': home_team, 'full': home_full}, 'homeScore': home_score,
'inning': inning, 'state': state, 'last': last_play, 'atBat': at_bat, 'atBats': at_bats,
'status': status, 'reason': reason, 'broadcasts': broadcasts, 'ended': ended,
'balls': balls, 'strikes': strikes, 'outs': outs,
'pitcher': pitcher, 'batter': batter, 'runners': runners, 'sh_runs': short_runners, 'risp': risp,
'awayRecord': away_record, 'homeRecord': home_record,
'awayProb': away_prob, 'homeProb': home_prob,
'decisions': decisions, 'homers': homers, 'description': description})
return(tmp)
Class = MLBScores
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: