|
@@ -4,199 +4,226 @@ import gspread
|
|
from oauth2client.service_account import ServiceAccountCredentials
|
|
from oauth2client.service_account import ServiceAccountCredentials
|
|
import datetime
|
|
import datetime
|
|
import time
|
|
import time
|
|
-import timeout_decorator
|
|
|
|
from nba_api.stats.static import players
|
|
from nba_api.stats.static import players
|
|
from nba_api.stats.endpoints import playergamelog
|
|
from nba_api.stats.endpoints import playergamelog
|
|
|
|
|
|
-#spreadsheet_key = '12Zv95ZMJ008KXC5ytVnBusjX9wUnpOg0TOLwmxMNOTQ' # 2018 Official
|
|
|
|
-spreadsheet_key = '14pHOScaGXvN83iCca6_5p6QoViYvo223cIJD9nnl7TI' # 2019 Test
|
|
|
|
|
|
+spreadsheet_key = '1QBQvGSMesox1gwjpaoK-0-p3n-c4I_L73PWCggjdayM' # 2019 Official
|
|
|
|
+#spreadsheet_key = '14pHOScaGXvN83iCca6_5p6QoViYvo223cIJD9nnl7TI' # 2019 Test
|
|
json_keyfile = 'NBA Playoffs Game-1f9a46f0715c.json'
|
|
json_keyfile = 'NBA Playoffs Game-1f9a46f0715c.json'
|
|
-#current_day = 'today' # today, else:
|
|
|
|
-current_day = datetime.date(2018, 4, 14) # set date manually
|
|
|
|
-nba_cooldown = 1 # in seconds, don't hammer the NBA.com API too hard
|
|
|
|
|
|
+current_day = 'today' # today, else:
|
|
|
|
+#current_day = datetime.date(2018, 4, 15) # set date manually
|
|
|
|
+nba_cooldown = 2 # in seconds, don't hammer the NBA.com API too hard
|
|
|
|
|
|
-####################################################################################
|
|
|
|
|
|
+###############################################################################
|
|
|
|
|
|
def getWorksheet(spreadsheet_key, json_keyfile):
|
|
def getWorksheet(spreadsheet_key, json_keyfile):
|
|
- scope = ['https://spreadsheets.google.com/feeds',
|
|
|
|
- 'https://www.googleapis.com/auth/drive']
|
|
|
|
- credentials = ServiceAccountCredentials.from_json_keyfile_name(json_keyfile, scope)
|
|
|
|
- gc = gspread.authorize(credentials)
|
|
|
|
- spreadsheet = gc.open_by_key(spreadsheet_key)
|
|
|
|
- worksheet = spreadsheet.get_worksheet(0)
|
|
|
|
- return worksheet
|
|
|
|
|
|
+ scope = ['https://spreadsheets.google.com/feeds',
|
|
|
|
+ 'https://www.googleapis.com/auth/drive']
|
|
|
|
+ credentials = ServiceAccountCredentials.from_json_keyfile_name(json_keyfile, scope)
|
|
|
|
+ gc = gspread.authorize(credentials)
|
|
|
|
+ spreadsheet = gc.open_by_key(spreadsheet_key)
|
|
|
|
+ worksheet = spreadsheet.get_worksheet(0)
|
|
|
|
+ return worksheet
|
|
|
|
|
|
def setDates(current_day):
|
|
def setDates(current_day):
|
|
- if current_day == 'today':
|
|
|
|
- current_day = datetime.datetime.now() - datetime.timedelta(hours=3) # in case games go past midnight
|
|
|
|
- current_day = current_day.date()
|
|
|
|
- url_date = current_day.strftime('%m/%d/%Y')
|
|
|
|
- current_year = current_day.year
|
|
|
|
- if current_day.month > 6:
|
|
|
|
- current_season = str(current_year) + "-" + str(current_year + 1)[2:]
|
|
|
|
- else:
|
|
|
|
- current_season = str(current_year - 1) + "-" + str(current_year)[2:]
|
|
|
|
- return url_date, current_season, current_day
|
|
|
|
-
|
|
|
|
-def getFirstRowLastRow(worksheet, current_day):
|
|
|
|
- date_col_values = worksheet.col_values(1) # get all date cell values from column 1
|
|
|
|
- final_row = len(date_col_values) # get number of rows in spreadsheet
|
|
|
|
- date_cells = worksheet.range('A4:A'+str(final_row)) # get all date cells
|
|
|
|
- first_row = ""
|
|
|
|
- last_row = ""
|
|
|
|
- for date_cell in date_cells:
|
|
|
|
- if first_row != "":
|
|
|
|
- if date_cell.row == final_row:
|
|
|
|
- last_row = final_row
|
|
|
|
- elif date_cell.value != "":
|
|
|
|
- last_row = date_cell.row - 1
|
|
|
|
- break
|
|
|
|
- else:
|
|
|
|
- continue
|
|
|
|
- elif date_cell.value != "":
|
|
|
|
- date_cell_day = datetime.datetime.strptime(date_cell.value + " " + str(current_day.year), '%A, %B %d %Y')
|
|
|
|
- date_cell_day = date_cell_day.date()
|
|
|
|
- if date_cell_day == current_day:
|
|
|
|
- first_row = date_cell.row
|
|
|
|
- return first_row, last_row
|
|
|
|
|
|
+ if current_day == 'today':
|
|
|
|
+ # in case games go past midnight
|
|
|
|
+ current_date = datetime.datetime.now() - datetime.timedelta(hours=3)
|
|
|
|
+ current_date = current_date.date()
|
|
|
|
+ else:
|
|
|
|
+ current_date = current_day
|
|
|
|
+ url_date = current_date.strftime('%m/%d/%Y')
|
|
|
|
+ current_year = current_date.year
|
|
|
|
+ if current_date.month > 6:
|
|
|
|
+ current_season = '{}-{}'.format(str(current_year),
|
|
|
|
+ str(current_year + 1)[2:])
|
|
|
|
+ else:
|
|
|
|
+ current_season = '{}-{}'.format(str(current_year - 1),
|
|
|
|
+ str(current_year)[2:])
|
|
|
|
+ return url_date, current_season, current_date
|
|
|
|
+
|
|
|
|
+def getFirstRowLastRow(worksheet, current_date):
|
|
|
|
+ date_col_values = worksheet.col_values(1) # get all date cell values from column 1
|
|
|
|
+ final_row = len(date_col_values) # get number of rows in spreadsheet
|
|
|
|
+ date_cells = worksheet.range('A4:A'+str(final_row)) # get all date cells
|
|
|
|
+ first_row = ""
|
|
|
|
+ last_row = ""
|
|
|
|
+ for date_cell in date_cells:
|
|
|
|
+ if first_row != "":
|
|
|
|
+ if date_cell.row == final_row:
|
|
|
|
+ last_row = final_row
|
|
|
|
+ break
|
|
|
|
+ elif date_cell.value != "":
|
|
|
|
+ last_row = date_cell.row - 1
|
|
|
|
+ break
|
|
|
|
+ continue
|
|
|
|
+ elif date_cell.value != "":
|
|
|
|
+ date_cell_day = datetime.datetime.strptime('{} {}'.format(date_cell.value,
|
|
|
|
+ str(current_date.year)),
|
|
|
|
+ '%A, %B %d %Y')
|
|
|
|
+ date_cell_day = date_cell_day.date()
|
|
|
|
+ if date_cell_day == current_date:
|
|
|
|
+ first_row = date_cell.row
|
|
|
|
+ return first_row, last_row
|
|
|
|
|
|
def parsePlayersCells(todays_cells):
|
|
def parsePlayersCells(todays_cells):
|
|
- player_cells = []
|
|
|
|
- player_names = []
|
|
|
|
- for cell in todays_cells:
|
|
|
|
- if cell.col == 3 and cell.value != "":
|
|
|
|
- player_cells.append(cell)
|
|
|
|
- player_name = cleanPlayerName(cell)
|
|
|
|
- player_names.append(player_name)
|
|
|
|
- player_names_unique = list(dict.fromkeys(player_names))
|
|
|
|
- return player_cells, player_names_unique
|
|
|
|
-
|
|
|
|
|
|
+ player_cells = []
|
|
|
|
+ player_names = []
|
|
|
|
+ for cell in todays_cells:
|
|
|
|
+ if cell.col == 3 and cell.value != "" and cell.value[-7:] != "-FIX!!!":
|
|
|
|
+ player_cells.append(cell)
|
|
|
|
+ player_name = cleanPlayerName(cell)
|
|
|
|
+ player_names.append(player_name)
|
|
|
|
+ player_names_unique = list(dict.fromkeys(player_names))
|
|
|
|
+ return player_cells, player_names_unique
|
|
|
|
+
|
|
def cleanPlayerName(player_cell):
|
|
def cleanPlayerName(player_cell):
|
|
- raw_name = player_cell.value
|
|
|
|
- first_name_last_name = raw_name.split()
|
|
|
|
- first_name = first_name_last_name[0]
|
|
|
|
- first_name = first_name.replace('.', '')
|
|
|
|
- last_name = first_name_last_name[1]
|
|
|
|
- player_name = first_name + ' ' + last_name
|
|
|
|
- return player_name
|
|
|
|
-
|
|
|
|
-def badName(worksheet, player_cell):
|
|
|
|
- worksheet.update_cell(player_cell.row, 12, "Fix name, then delete this message!")
|
|
|
|
-
|
|
|
|
-@timeout_decorator.timeout(10)
|
|
|
|
|
|
+ raw_name = player_cell.value
|
|
|
|
+ first_name_last_name = raw_name.split()
|
|
|
|
+ first_name = first_name_last_name[0]
|
|
|
|
+ first_name = first_name.replace('.', '')
|
|
|
|
+ last_name = first_name_last_name[1]
|
|
|
|
+ player_name = first_name + ' ' + last_name
|
|
|
|
+ return player_name
|
|
|
|
+
|
|
def getPlayerStats(player_id, url_date, current_season):
|
|
def getPlayerStats(player_id, url_date, current_season):
|
|
- player_stats = {}
|
|
|
|
- player_game_logs = playergamelog.PlayerGameLog(player_id=player_id,
|
|
|
|
- season_all=current_season,
|
|
|
|
- league_id_nullable='00',
|
|
|
|
- season_type_all_star='Playoffs',
|
|
|
|
- date_from_nullable=url_date,
|
|
|
|
- date_to_nullable=url_date)
|
|
|
|
- player_game_logs = player_game_logs.get_dict()
|
|
|
|
- player_game_logs_results = player_game_logs.get('resultSets')[0]
|
|
|
|
- player_game_logs_headers = player_game_logs_results.get('headers')
|
|
|
|
- player_game_logs_values = player_game_logs_results.get('rowSet')[0]
|
|
|
|
- player_stats_dict = dict(zip(player_game_logs_headers, player_game_logs_values))
|
|
|
|
- return player_stats_dict
|
|
|
|
-
|
|
|
|
-@timeout_decorator.timeout(60)
|
|
|
|
|
|
+ player_game_logs = playergamelog.PlayerGameLog(player_id=player_id,
|
|
|
|
+ league_id_nullable='00',
|
|
|
|
+ season_type_all_star='Playoffs',
|
|
|
|
+ date_from_nullable=url_date,
|
|
|
|
+ date_to_nullable=url_date)
|
|
|
|
+ player_game_logs = player_game_logs.get_dict()
|
|
|
|
+ player_game_logs_results = player_game_logs.get('resultSets')[0]
|
|
|
|
+ player_game_logs_headers = player_game_logs_results.get('headers')
|
|
|
|
+ # if player has no stats for this day, list will be empty
|
|
|
|
+ if len(player_game_logs_results.get('rowSet')) < 1:
|
|
|
|
+ player_stats_dict = None
|
|
|
|
+ else:
|
|
|
|
+ player_game_logs_values = player_game_logs_results.get('rowSet')[0]
|
|
|
|
+ player_stats_dict = dict(zip(player_game_logs_headers, player_game_logs_values))
|
|
|
|
+ return player_stats_dict
|
|
|
|
+
|
|
def buildStatsDict(player_names_unique, url_date, current_season):
|
|
def buildStatsDict(player_names_unique, url_date, current_season):
|
|
- stats_dict = {}
|
|
|
|
- for player_name in player_names_unique:
|
|
|
|
- print("Getting " + player_name + "\'s stats from NBA.com")
|
|
|
|
- player_info = players.find_players_by_full_name(player_name)
|
|
|
|
- player_id = player_info[0].get('id')
|
|
|
|
- player_stats_dict = getPlayerStats(player_id, url_date, current_season)
|
|
|
|
- stats_dict[player_name] = player_stats_dict
|
|
|
|
- time.sleep(nba_cooldown)
|
|
|
|
- return stats_dict
|
|
|
|
-
|
|
|
|
-def checkStatsDict(player_name, stats_dict):
|
|
|
|
- player_stats_dict = stats_dict.get(player_name)
|
|
|
|
- return player_stats_dict
|
|
|
|
-
|
|
|
|
-def updatePlayerStatsLocal(todays_cells, player_cell, player_stats_dict, update):
|
|
|
|
- for cell in todays_cells:
|
|
|
|
- if cell.row == player_cell.row:
|
|
|
|
- if cell.col == 4 and player_stats_dict.get("PTS") != "" and str(cell.value) != str(player_stats_dict.get("PTS")):
|
|
|
|
- cell.value = int(player_stats_dict.get("PTS"))
|
|
|
|
- update = True
|
|
|
|
- elif cell.col == 5 and player_stats_dict.get("REB") != "" and str(cell.value) != str(player_stats_dict.get("REB")):
|
|
|
|
- cell.value = int(player_stats_dict.get("REB"))
|
|
|
|
- update = True
|
|
|
|
- elif cell.col == 6 and player_stats_dict.get("AST") != "" and str(cell.value) != str(player_stats_dict.get("AST")):
|
|
|
|
- cell.value = int(player_stats_dict.get("AST"))
|
|
|
|
- update = True
|
|
|
|
- elif cell.col == 7 and player_stats_dict.get("STL") != "" and str(cell.value) != str(player_stats_dict.get("STL")):
|
|
|
|
- cell.value = int(player_stats_dict.get("STL"))
|
|
|
|
- update = True
|
|
|
|
- elif cell.col == 8 and player_stats_dict.get("BLK") != "" and str(cell.value) != str(player_stats_dict.get("BLK")):
|
|
|
|
- cell.value = int(player_stats_dict.get("BLK"))
|
|
|
|
- update = True
|
|
|
|
- elif cell.col == 9 and player_stats_dict.get("TOV") != "" and str(cell.value) != str(player_stats_dict.get("TOV")):
|
|
|
|
- cell.value = int(player_stats_dict.get("TOV"))
|
|
|
|
- update = True
|
|
|
|
- elif cell.col == 10 and player_stats_dict.get("WL") != "" and str(cell.value) != str(player_stats_dict.get("WL")):
|
|
|
|
- cell.value = str(player_stats_dict.get("WL"))
|
|
|
|
- update = True
|
|
|
|
- return todays_cells, update
|
|
|
|
-
|
|
|
|
|
|
+ stats_dict = {}
|
|
|
|
+ for player_name in player_names_unique:
|
|
|
|
+ player_info = players.find_players_by_full_name(player_name)
|
|
|
|
+ if len(player_info) < 1:
|
|
|
|
+ print("\nPlayer \"" + player_name + "\" not found, please fix name!")
|
|
|
|
+ stats_dict[player_name] = "Fix Name!"
|
|
|
|
+ continue
|
|
|
|
+ player_id = player_info[0].get('id')
|
|
|
|
+ stats_dict[player_name] = getPlayerStats(player_id, url_date, current_season)
|
|
|
|
+ print('{} {}{} {}{}'.format('Got', player_name, '\'s (ID:', str(player_id), ') stats from NBA.com'))
|
|
|
|
+ time.sleep(nba_cooldown)
|
|
|
|
+ return stats_dict
|
|
|
|
+
|
|
|
|
+def updatePlayerStatsLocal(todays_cells, player_cell, player_stats, update, player_update):
|
|
|
|
+ for cell in todays_cells:
|
|
|
|
+ if cell.row == player_cell.row:
|
|
|
|
+ if (cell.col == 4 and player_stats.get("PTS") != "" and
|
|
|
|
+ str(cell.value) != str(player_stats.get("PTS"))):
|
|
|
|
+ cell.value = str(player_stats.get("PTS"))
|
|
|
|
+ update = True
|
|
|
|
+ player_update = True
|
|
|
|
+ elif (cell.col == 5 and player_stats.get("REB") != "" and
|
|
|
|
+ str(cell.value) != str(player_stats.get("REB"))):
|
|
|
|
+ cell.value = str(player_stats.get("REB"))
|
|
|
|
+ update = True
|
|
|
|
+ player_update = True
|
|
|
|
+ elif (cell.col == 6 and player_stats.get("AST") != "" and
|
|
|
|
+ str(cell.value) != str(player_stats.get("AST"))):
|
|
|
|
+ cell.value = str(player_stats.get("AST"))
|
|
|
|
+ update = True
|
|
|
|
+ player_update = True
|
|
|
|
+ elif (cell.col == 7 and player_stats.get("STL") != "" and
|
|
|
|
+ str(cell.value) != str(player_stats.get("STL"))):
|
|
|
|
+ cell.value = str(player_stats.get("STL"))
|
|
|
|
+ update = True
|
|
|
|
+ player_update = True
|
|
|
|
+ elif (cell.col == 8 and player_stats.get("BLK") != "" and
|
|
|
|
+ str(cell.value) != str(player_stats.get("BLK"))):
|
|
|
|
+ cell.value = str(player_stats.get("BLK"))
|
|
|
|
+ update = True
|
|
|
|
+ player_update = True
|
|
|
|
+ elif (cell.col == 9 and player_stats.get("TOV") != "" and
|
|
|
|
+ str(cell.value) != str(player_stats.get("TOV"))):
|
|
|
|
+ cell.value = str(player_stats.get("TOV"))
|
|
|
|
+ update = True
|
|
|
|
+ player_update = True
|
|
|
|
+ elif (cell.col == 10 and player_stats.get("WL") != "" and
|
|
|
|
+ str(cell.value) != str(player_stats.get("WL"))):
|
|
|
|
+ cell.value = str(player_stats.get("WL"))
|
|
|
|
+ update = True
|
|
|
|
+ player_update = True
|
|
|
|
+ return todays_cells, update, player_update
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if __name__ == "__main__":
|
|
|
|
|
|
- while True:
|
|
|
|
-
|
|
|
|
- url_date, current_season, current_day = setDates(current_day)
|
|
|
|
-
|
|
|
|
- try:
|
|
|
|
- worksheet = getWorksheet(spreadsheet_key, json_keyfile)
|
|
|
|
- first_row, last_row = getFirstRowLastRow(worksheet, current_day)
|
|
|
|
- if first_row == "":
|
|
|
|
- print("No games today! Pausing for 1000 seconds...")
|
|
|
|
- time.sleep(1000)
|
|
|
|
- continue
|
|
|
|
- todays_cells = worksheet.range(first_row, 3, last_row, 10)
|
|
|
|
- print("Getting a list of today's players...")
|
|
|
|
- player_cells, player_names_unique = parsePlayersCells(todays_cells)
|
|
|
|
- print(player_names_unique)
|
|
|
|
- except gspread.exceptions.APIError:
|
|
|
|
- print("API overloaded, retrying in 10 seconds...")
|
|
|
|
- time.sleep(10)
|
|
|
|
- continue
|
|
|
|
- except:
|
|
|
|
- time.sleep(10)
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- try:
|
|
|
|
- stats_dict = buildStatsDict(player_names_unique, url_date, current_season)
|
|
|
|
- except timeout_decorator.TimeoutError:
|
|
|
|
- print("NBA.com API not responding, retrying in 10 seconds...")
|
|
|
|
- time.sleep(10)
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- update = False # only update the sheet if it's changed
|
|
|
|
-
|
|
|
|
- for player_cell in player_cells:
|
|
|
|
- player_name = cleanPlayerName(player_cell)
|
|
|
|
- player_stats_dict = checkStatsDict(player_name, stats_dict)
|
|
|
|
- print("Updating " + player_name + "\'s stats locally")
|
|
|
|
- todays_cells, update = updatePlayerStatsLocal(todays_cells, player_cell, player_stats_dict, update)
|
|
|
|
-
|
|
|
|
- if update == True:
|
|
|
|
- while True:
|
|
|
|
- try:
|
|
|
|
- print("Updating google sheet remotely...")
|
|
|
|
- worksheet.update_cells(todays_cells)
|
|
|
|
- break
|
|
|
|
- except gspread.exceptions.APIError:
|
|
|
|
- print("API overloaded, adding a 10 second delay...")
|
|
|
|
- time.sleep(10)
|
|
|
|
- continue
|
|
|
|
- else:
|
|
|
|
- print("No remote update necessary...")
|
|
|
|
- time.sleep(30)
|
|
|
|
|
|
+ while True:
|
|
|
|
+ url_date, current_season, current_date = setDates(current_day)
|
|
|
|
+ print("Date: " + str(current_date))
|
|
|
|
|
|
- continue # restart entire loop
|
|
|
|
|
|
+ # open worksheet, find today's action, and create unique list of players
|
|
|
|
+ try:
|
|
|
|
+ worksheet = getWorksheet(spreadsheet_key, json_keyfile)
|
|
|
|
+ first_row, last_row = getFirstRowLastRow(worksheet, current_date)
|
|
|
|
+ if first_row == "":
|
|
|
|
+ print("No games today! Pausing for 1000 seconds...")
|
|
|
|
+ time.sleep(1000)
|
|
|
|
+ continue
|
|
|
|
+ todays_cells = worksheet.range(first_row, 3, last_row, 10)
|
|
|
|
+ player_cells, player_names_unique = parsePlayersCells(todays_cells)
|
|
|
|
+ print("Today's players:", end=' ', flush=True)
|
|
|
|
+ print(player_names_unique)
|
|
|
|
+ except gspread.exceptions.APIError:
|
|
|
|
+ print("Google API overloaded, retrying in 10 seconds...")
|
|
|
|
+ time.sleep(10)
|
|
|
|
+ continue
|
|
|
|
+ except:
|
|
|
|
+ time.sleep(10)
|
|
|
|
+ continue
|
|
|
|
+
|
|
|
|
+ # Build stats dictionary from unique list of players
|
|
|
|
+ print("Retrieving player stats from NBA.com...")
|
|
|
|
+ stats_dict = buildStatsDict(player_names_unique, url_date, current_season)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ update = False # only update the sheet if it has changed
|
|
|
|
+ for player_cell in player_cells:
|
|
|
|
+ player_update = False # Return if individual player stats have changed
|
|
|
|
+ player_name = cleanPlayerName(player_cell)
|
|
|
|
+ if stats_dict.get(player_name) != None: # skip players with empty stats
|
|
|
|
+ if stats_dict.get(player_name) == "Fix Name!":
|
|
|
|
+ player_cell.value = str(player_cell.value) + "-FIX!!!"
|
|
|
|
+ update = True
|
|
|
|
+ else:
|
|
|
|
+ player_stats = stats_dict.get(player_name)
|
|
|
|
+ todays_cells, update, player_update = updatePlayerStatsLocal(todays_cells,
|
|
|
|
+ player_cell,
|
|
|
|
+ player_stats,
|
|
|
|
+ update,
|
|
|
|
+ player_update)
|
|
|
|
+ if player_update == True:
|
|
|
|
+ print("Updated " + player_name + "\'s stats")
|
|
|
|
+ elif player_update == False:
|
|
|
|
+ print(player_name + "\'s stats have not changed")
|
|
|
|
+
|
|
|
|
+ if update == True:
|
|
|
|
+ while True:
|
|
|
|
+ try:
|
|
|
|
+ print("Pushing changes to google sheet...")
|
|
|
|
+ worksheet.update_cells(todays_cells, 'USER_ENTERED')
|
|
|
|
+ break
|
|
|
|
+ except gspread.exceptions.APIError:
|
|
|
|
+ print("Google API overloaded, adding a 10 second delay...")
|
|
|
|
+ time.sleep(10)
|
|
|
|
+ continue
|
|
|
|
+ else:
|
|
|
|
+ print("No update necessary, pausing for 30 seconds...")
|
|
|
|
+ time.sleep(30)
|
|
|
|
+
|
|
|
|
+ continue # restart entire loop
|
|
|
|
|
|
|
|
|