-
Notifications
You must be signed in to change notification settings - Fork 224
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #196 from cwendt94/InitialBaseball
Initial Baseball Implementation
- Loading branch information
Showing
13 changed files
with
443 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
__all__ = ['League', | ||
'Team', | ||
'Player', | ||
'Matchup', | ||
] | ||
|
||
from .league import League | ||
from .team import Team | ||
from .player import Player | ||
from .matchup import Matchup |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from .constant import ACTIVITY_MAP | ||
|
||
class Activity(object): | ||
def __init__(self, data, player_map, get_team_data): | ||
self.actions = [] # List of tuples (Team, action, player) | ||
self.date = data['date'] | ||
for msg in data['messages']: | ||
team = '' | ||
action = 'UNKNOWN' | ||
player = '' | ||
msg_id = msg['messageTypeId'] | ||
if msg_id == 244: | ||
team = get_team_data(msg['from']) | ||
elif msg_id == 239: | ||
team = get_team_data(msg['for']) | ||
else: | ||
team = get_team_data(msg['to']) | ||
if msg_id in ACTIVITY_MAP: | ||
action = ACTIVITY_MAP[msg_id] | ||
if msg['targetId'] in player_map: | ||
player = player_map[msg['targetId']] | ||
self.actions.append((team, action, player)) | ||
|
||
def __repr__(self): | ||
return 'Activity(' + ' '.join("(%s,%s,%s)" % tup for tup in self.actions) + ')' | ||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
POSITION_MAP = { | ||
0: 'C', | ||
1: '1B', | ||
2: '2B', | ||
3: '3B', | ||
4: 'SS', | ||
5: 'OF', | ||
6: '2B/SS', | ||
7: '1B/3B', | ||
8: 'DH', | ||
9: '9', # For unknown use stat number | ||
10: '10', | ||
11: 'DH', | ||
12: 'UTIL', | ||
13: 'P', | ||
14: 'SP', | ||
15: 'RP', | ||
16: 'BE', | ||
17: 'IL', | ||
18: '18', | ||
19: '19' | ||
# reverse TODO | ||
} | ||
|
||
PRO_TEAM_MAP = { | ||
0: 'FA', | ||
1: 'Bal', | ||
2: 'Bos', | ||
3: 'LAA', | ||
4: 'ChW', | ||
5: 'Cle', | ||
6: 'Det', | ||
7: 'KC', | ||
8: 'Mil', | ||
9: 'Min', | ||
10: 'NYY', | ||
11: 'Oak', | ||
12: 'Sea', | ||
13: 'Tex', | ||
14: 'Tor', | ||
15: 'Atl', | ||
16: 'ChC', | ||
17: 'Cin', | ||
18: 'Hou', | ||
19: 'LAD', | ||
20: 'Wsh', | ||
21: 'NYM', | ||
22: 'Phi', | ||
23: 'Pit', | ||
24: 'StL', | ||
25: 'SD', | ||
26: 'SF', | ||
27: 'Col', | ||
28: 'Mia', | ||
29: 'Ari', | ||
30: 'TB', | ||
} | ||
|
||
STATS_MAP = { | ||
0: 'AB', | ||
1: 'H', | ||
2: 'AVG', | ||
5: 'HR', | ||
10: 'BB', | ||
16: 'PA', | ||
17: 'OBP', | ||
20: 'R', | ||
21: 'RBI', | ||
23: 'SB', | ||
34: 'OUTS', | ||
35: 'BATTERS', | ||
36: 'PITCHES', | ||
37: 'P_H', | ||
39: 'P_BB', | ||
41: 'WHIP', | ||
42: 'HBP', | ||
44: 'P_R', | ||
45: 'ER', | ||
46: 'P_HR', | ||
47: 'ERA', | ||
48: 'K', | ||
53: 'W', | ||
54: 'L', | ||
57: 'SV', | ||
99: 'STARTER', | ||
} | ||
|
||
ACTIVITY_MAP = { | ||
178: 'FA ADDED', | ||
180: 'WAIVER ADDED', | ||
179: 'DROPPED', | ||
181: 'DROPPED', | ||
239: 'DROPPED', | ||
244: 'TRADED', | ||
'FA': 178, | ||
'WAIVER': 180, | ||
'TRADED': 244 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import datetime | ||
import time | ||
import json | ||
import math | ||
from typing import List, Tuple | ||
import pdb | ||
|
||
from ..base_league import BaseLeague | ||
from .team import Team | ||
from .player import Player | ||
from .matchup import Matchup | ||
from .constant import PRO_TEAM_MAP | ||
from.activity import Activity | ||
from .constant import POSITION_MAP, ACTIVITY_MAP | ||
|
||
class League(BaseLeague): | ||
'''Creates a League instance for Public/Private ESPN league''' | ||
def __init__(self, league_id: int, year: int, espn_s2=None, swid=None, username=None, password=None, debug=False): | ||
super().__init__(league_id=league_id, year=year, sport='mlb', espn_s2=espn_s2, swid=swid, username=username, password=password, debug=debug) | ||
|
||
data = self._fetch_league() | ||
self._fetch_teams(data) | ||
|
||
def _fetch_league(self): | ||
data = super()._fetch_league() | ||
self._fetch_players() | ||
return(data) | ||
|
||
def _fetch_teams(self, data): | ||
'''Fetch teams in league''' | ||
super()._fetch_teams(data, TeamClass=Team) | ||
|
||
# replace opponentIds in schedule with team instances | ||
for team in self.teams: | ||
team.division_name = self.settings.division_map.get(team.division_id, '') | ||
for week, matchup in enumerate(team.schedule): | ||
for opponent in self.teams: | ||
if matchup.away_team == opponent.team_id: | ||
matchup.away_team = opponent | ||
if matchup.home_team == opponent.team_id: | ||
matchup.home_team = opponent | ||
|
||
def standings(self) -> List[Team]: | ||
standings = sorted(self.teams, key=lambda x: x.final_standing if x.final_standing != 0 else x.standing, reverse=False) | ||
return standings | ||
|
||
def scoreboard(self, matchupPeriod: int = None) -> List[Matchup]: | ||
'''Returns list of matchups for a given matchup period''' | ||
if not matchupPeriod: | ||
matchupPeriod=self.currentMatchupPeriod | ||
|
||
params = { | ||
'view': 'mMatchup', | ||
} | ||
data = self.espn_request.league_get(params=params) | ||
schedule = data['schedule'] | ||
matchups = [Matchup(matchup) for matchup in schedule if matchup['matchupPeriodId'] == matchupPeriod] | ||
|
||
for team in self.teams: | ||
for matchup in matchups: | ||
if matchup.home_team == team.team_id: | ||
matchup.home_team = team | ||
elif matchup.away_team == team.team_id: | ||
matchup.away_team = team | ||
|
||
return matchups | ||
|
||
def get_team_data(self, team_id: int) -> Team: | ||
for team in self.teams: | ||
if team_id == team.team_id: | ||
return team | ||
return None | ||
|
||
def recent_activity(self, size: int = 25, msg_type: str = None) -> List[Activity]: | ||
'''Returns a list of recent league activities (Add, Drop, Trade)''' | ||
if self.year < 2019: | ||
raise Exception('Cant use recent activity before 2019') | ||
|
||
msg_types = [178,180,179,239,181,244] | ||
if msg_type in ACTIVITY_MAP: | ||
msg_types = [ACTIVITY_MAP[msg_type]] | ||
params = { | ||
'view': 'kona_league_communication' | ||
} | ||
|
||
filters = {"topics":{"filterType":{"value":["ACTIVITY_TRANSACTIONS"]},"limit":size,"limitPerMessageSet":{"value":25},"offset":0,"sortMessageDate":{"sortPriority":1,"sortAsc":False},"sortFor":{"sortPriority":2,"sortAsc":False},"filterIncludeMessageTypeIds":{"value":msg_types}}} | ||
headers = {'x-fantasy-filter': json.dumps(filters)} | ||
data = self.espn_request.league_get(extend='/communication/', params=params, headers=headers) | ||
data = data['topics'] | ||
activity = [Activity(topic, self.player_map, self.get_team_data) for topic in data] | ||
|
||
return activity | ||
|
||
def free_agents(self, week: int=None, size: int=50, position: str=None, position_id: int=None) -> List[Player]: | ||
'''Returns a List of Free Agents for a Given Week\n | ||
Should only be used with most recent season''' | ||
|
||
if self.year < 2019: | ||
raise Exception('Cant use free agents before 2019') | ||
if not week: | ||
week = self.current_week | ||
|
||
slot_filter = [] | ||
if position and position in POSITION_MAP: | ||
slot_filter = [POSITION_MAP[position]] | ||
if position_id: | ||
slot_filter.append(position_id) | ||
|
||
|
||
params = { | ||
'view': 'kona_player_info', | ||
'scoringPeriodId': week, | ||
} | ||
filters = {"players":{"filterStatus":{"value":["FREEAGENT","WAIVERS"]},"filterSlotIds":{"value":slot_filter},"limit":size,"sortPercOwned":{"sortPriority":1,"sortAsc":False},"sortDraftRanks":{"sortPriority":100,"sortAsc":True,"value":"STANDARD"}}} | ||
headers = {'x-fantasy-filter': json.dumps(filters)} | ||
|
||
data = self.espn_request.league_get(params=params, headers=headers) | ||
players = data['players'] | ||
|
||
return [Player(player) for player in players] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import pdb | ||
|
||
from .constant import STATS_MAP | ||
|
||
class Matchup(object): | ||
'''Creates Matchup instance''' | ||
def __init__(self, data): | ||
self.home_team_live_score = None | ||
self.away_team_live_score = None | ||
self._fetch_matchup_info(data) | ||
|
||
def __repr__(self): | ||
# TODO: use final score when that's available? | ||
# writing this too early to see if data['home']['totalPoints'] is final score | ||
# it might also be used for points leagues instead of category leagues | ||
if not self.away_team_live_score: | ||
return 'Matchup(%s, %s)' % (self.home_team, self.away_team, ) | ||
else: | ||
return 'Matchup(%s %s - %s %s)' % (self.home_team, | ||
str(round(self.home_team_live_score, 1)), | ||
str(round(self.away_team_live_score, 1)), | ||
self.away_team) | ||
|
||
def _fetch_matchup_info(self, data): | ||
'''Fetch info for matchup''' | ||
self.home_team = data['home']['teamId'] | ||
self.home_final_score = data['home']['totalPoints'] | ||
self.away_team = data['away']['teamId'] | ||
self.away_final_score = data['away']['totalPoints'] | ||
self.winner = data['winner'] | ||
self.home_team_cats = None | ||
self.away_team_cats = None | ||
|
||
# if stats are available | ||
if 'cumulativeScore' in data['home'].keys() and data['home']['cumulativeScore']['scoreByStat']: | ||
|
||
self.home_team_live_score = (data['home']['cumulativeScore']['wins'] + | ||
data['home']['cumulativeScore']['ties']/2) | ||
self.away_team_live_score = (data['away']['cumulativeScore']['wins'] + | ||
data['away']['cumulativeScore']['ties']/2) | ||
|
||
self.home_team_cats = { STATS_MAP[i]: {'score': data['home']['cumulativeScore']['scoreByStat'][i]['score'], | ||
'result': data['home']['cumulativeScore']['scoreByStat'][i]['result']} for i in data['home']['cumulativeScore']['scoreByStat'].keys()} | ||
|
||
self.away_team_cats = { STATS_MAP[i]: {'score': data['away']['cumulativeScore']['scoreByStat'][i]['score'], | ||
'result': data['away']['cumulativeScore']['scoreByStat'][i]['result']} for i in data['away']['cumulativeScore']['scoreByStat'].keys()} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from .constant import POSITION_MAP, PRO_TEAM_MAP, STATS_MAP | ||
from .utils import json_parsing | ||
import pdb | ||
|
||
class Player(object): | ||
'''Player are part of team''' | ||
def __init__(self, data): | ||
self.name = json_parsing(data, 'fullName') | ||
self.playerId = json_parsing(data, 'id') | ||
self.position = POSITION_MAP[json_parsing(data, 'defaultPositionId') - 1] | ||
self.lineupSlot = POSITION_MAP.get(data.get('lineupSlotId'), '') | ||
self.eligibleSlots = [POSITION_MAP[pos] for pos in json_parsing(data, 'eligibleSlots')] | ||
self.acquisitionType = json_parsing(data, 'acquisitionType') | ||
self.proTeam = PRO_TEAM_MAP[json_parsing(data, 'proTeamId')] | ||
self.injuryStatus = json_parsing(data, 'injuryStatus') | ||
self.stats = {} | ||
|
||
# add available stats | ||
player = data['playerPoolEntry']['player'] if 'playerPoolEntry' in data else data['player'] | ||
self.injuryStatus = player.get('injuryStatus', self.injuryStatus) | ||
self.injured = player.get('injured', False) | ||
|
||
def __repr__(self): | ||
return 'Player(%s)' % (self.name, ) |
Oops, something went wrong.