From ecf1690185e514bc1c08fad6fd034e3e57632fc0 Mon Sep 17 00:00:00 2001 From: riffnshred Date: Sun, 9 Aug 2020 00:14:22 -0400 Subject: [PATCH] Fix Issue 130, Changed how goal details are handled and preped for rendering --- VERSION | 2 +- src/boards/seriesticker.py | 108 +++++++++++++++++++++---------------- src/boards/team_summary.py | 2 +- src/data/scoreboard.py | 50 ++++++++++++----- src/main.py | 2 +- src/renderer/goal.py | 46 +++++++++++----- src/renderer/main.py | 36 +++++++++++-- 7 files changed, 168 insertions(+), 78 deletions(-) diff --git a/VERSION b/VERSION index f0bb29e7..3a3cd8cc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.0 +1.3.1 diff --git a/src/boards/seriesticker.py b/src/boards/seriesticker.py index 63174344..32c06a96 100644 --- a/src/boards/seriesticker.py +++ b/src/boards/seriesticker.py @@ -62,11 +62,17 @@ def render(self): font=self.font, fill=(0,0,0) ) + self.index += 1 + # # If something fails in the process of drawing the series table due to failed API request + # # Continue in the loop and skip this series. + # if not self.draw_series_table(series): + # debug.error('Failed Draw the series table due to failed API request. Skiping to the next series') + # continue + + self.draw_series_table(series) - self.matrix.render() - self.index += 1 self.sleepEvent.wait(10) def draw_series_table(self, series): @@ -106,49 +112,61 @@ def draw_series_table(self, series): offset_correction = 0 for game in series.games: - - # Request the game overview - overview = nhl_api.overview(game["gameId"]) - - # get the scoreboard - scoreboard = Scoreboard(overview, self.data) - - if self.data.status.is_final(overview.status) and hasattr(scoreboard, "winning_team"): - if scoreboard.winning_team == series.top_team.id: - winning_row = top_row - loosing_row = bottom_row - winning_team_color = color_top_team - winning_bg_color = color_top_bg - else: - winning_row = bottom_row - loosing_row = top_row - winning_team_color = color_bottom_team - winning_bg_color = color_bottom_bg - - # Look loosing score text needs an offset - if len(str(scoreboard.winning_score)) == 2 and len(str(scoreboard.winning_score)) == 1: - offset_correction = 1 - - self.matrix.draw_text( - ((rec_width + 15 + offset_correction), loosing_row), - str(scoreboard.loosing_score), - font=self.font, - fill=loosing_color, - backgroundColor=None, - backgroundOffset=[1, 1, 1, 1] - ) - - position = self.matrix.draw_text( - (rec_width + 15, winning_row), - str(scoreboard.winning_score), - font=self.font, - fill=(winning_team_color['r'], winning_team_color['g'], winning_team_color['b']), - backgroundColor=(winning_bg_color['r'], winning_bg_color['g'], winning_bg_color['b']), - backgroundOffset=[1, 1, 1, 1] - ) - - # Increment - rec_width += (position["size"][0] + 4) + attempts_remaining = 5 + while attempts_remaining > 0: + try: + # Request the game overview + overview = nhl_api.overview(game["gameId"]) + # get the scoreboard + scoreboard = Scoreboard(overview, self.data) + + if self.data.status.is_final(overview.status) and hasattr(scoreboard, "winning_team"): + if scoreboard.winning_team == series.top_team.id: + winning_row = top_row + loosing_row = bottom_row + winning_team_color = color_top_team + winning_bg_color = color_top_bg + else: + winning_row = bottom_row + loosing_row = top_row + winning_team_color = color_bottom_team + winning_bg_color = color_bottom_bg + + # Look loosing score text needs an offset + if len(str(scoreboard.winning_score)) == 2 and len(str(scoreboard.winning_score)) == 1: + offset_correction = 1 + + self.matrix.draw_text( + ((rec_width + 15 + offset_correction), loosing_row), + str(scoreboard.loosing_score), + font=self.font, + fill=loosing_color, + backgroundColor=None, + backgroundOffset=[1, 1, 1, 1] + ) + + position = self.matrix.draw_text( + (rec_width + 15, winning_row), + str(scoreboard.winning_score), + font=self.font, + fill=(winning_team_color['r'], winning_team_color['g'], winning_team_color['b']), + backgroundColor=(winning_bg_color['r'], winning_bg_color['g'], winning_bg_color['b']), + backgroundOffset=[1, 1, 1, 1] + ) + + # Increment + rec_width += (position["size"][0] + 4) + break + + except ValueError as error_message: + self.data.network_issues = True + debug.error("Failed to get the Games for the {} VS {} series: {} attempts remaining".format(series.top_team.abbrev, series.bottom_team.abbrev, attempts_remaining)) + debug.error(error_message) + attempts_remaining -= 1 + sleep(2) + # If one of the request for player info failed after 5 attempts, return an empty dictionary + if attempts_remaining == 0: + return False def show_indicator(self, index, slides): diff --git a/src/boards/team_summary.py b/src/boards/team_summary.py index 9dcd51e0..407c9dae 100644 --- a/src/boards/team_summary.py +++ b/src/boards/team_summary.py @@ -203,6 +203,6 @@ def draw_team_summary(self, stats, prev_game_scoreboard, next_game_scoreboard, b draw.text((0, 61), "VS {}".format(next_game_scoreboard.away_team.abbrev), fill=(255, 255, 255), font=self.font) else: - draw.text((1, 61), "--------", fill=(200, 200, 200), font=self.font) + draw.text((1, 52), "--------", fill=(200, 200, 200), font=self.font) return image diff --git a/src/data/scoreboard.py b/src/data/scoreboard.py index 97c6896f..6a013262 100755 --- a/src/data/scoreboard.py +++ b/src/data/scoreboard.py @@ -1,6 +1,8 @@ from data.team import TeamScore from data.periods import Periods from utils import convert_time +from time import sleep +import debug import nhl_api @@ -24,7 +26,7 @@ def filter_scoring_plays(plays, away_id, home_id): return away, home -def get_goal_players(players_list): +def get_goal_players(players_list,data): """ Grab the list of players involved in a goal and return their Id except for assists which is a list of Ids """ @@ -40,24 +42,29 @@ def get_goal_players(players_list): try: if player["playerType"] == "Scorer": scorerId = player['player']['id'] - scorer = nhl_api.player(scorerId) + scorer["info"] = nhl_api.player(scorerId) + scorer["points"] = player['seasonTotal'] if player["playerType"] == "Assist": assistsId = player['player']['id'] - assists.append(nhl_api.player(assistsId)) + assists.append({"info":nhl_api.player(assistsId), "points":player['seasonTotal']}) if player["playerType"] == "Goalie": goalieId = player['player']['id'] goalie = nhl_api.player(goalieId) + data.network_issues = False break except ValueError as error_message: - self.network_issues = True + data.network_issues = True debug.error("Failed to get the players info related to a GOAL. {} attempt remaining.".format(attempts_remaining)) debug.error(error_message) attempts_remaining -= 1 - sleep(NETWORK_RETRY_SLEEP_TIME) + sleep(2) + + # If one of the request for player info failed after 5 attempts, return an empty dictionary + if attempts_remaining == 0: + return {} - return scorer, assists, goalie - + return {"scorer":scorer, "assists":assists, "goalie":goalie} class Scoreboard: def __init__(self, overview, data): @@ -74,10 +81,28 @@ def __init__(self, overview, data): if hasattr(overview,"plays"): plays = overview.plays away_scoring_plays, home_scoring_plays = filter_scoring_plays(plays,away.team.id,home.team.id) + # Get the Away Goal details + # If the request to the API fails,return an empty list of goal plays. + # This method is there to prevent the goal board to display the wrong info for play in away_scoring_plays: - away_goal_plays.append(Goal(play)) + players = get_goal_players(play['players'], data) + if players: + away_goal_plays.append(Goal(play, players)) + else: + debug.error("Failed to get Goal details for current live game. will retry on data refresh") + away_goal_plays = [] + break + # Get the Home Goal details + # If the request to the API fails,return an empty list of goal plays + # This method is there to prevent the goal board to display the wrong info for play in home_scoring_plays: - home_goal_plays.append(Goal(play)) + players = get_goal_players(play['players'], data) + if players: + home_goal_plays.append(Goal(play,players)) + else: + debug.error("Failed to get Goal details for current live game. will retry on data refresh") + home_goal_plays = [] + break self.away_team = TeamScore(away.team.id, away_abbrev, away.team.name, away.goals, away.shotsOnGoal, away.powerPlay, away.numSkaters, away.goaliePulled, away_goal_plays) @@ -107,9 +132,10 @@ def __str__(self): return output class Goal: - def __init__(self, play): - players = play['players'] - self.scorer, self.assists, self.goalie = get_goal_players(players) + def __init__(self, play, players): + self.scorer = players["scorer"] + self.assists = players["assists"] + self.goalie = players["goalie"] self.team = play['team']['id'] self.period = play['about']['ordinalNum'] self.periodTime = play['about']['periodTime'] diff --git a/src/main.py b/src/main.py index 7f062a69..d85cffb1 100644 --- a/src/main.py +++ b/src/main.py @@ -21,7 +21,7 @@ SCRIPT_NAME = "NHL-LED-SCOREBOARD" -SCRIPT_VERSION = "1.3.0" +SCRIPT_VERSION = "1.3.1" def run(): diff --git a/src/renderer/goal.py b/src/renderer/goal.py index b3a811c7..4bd79201 100755 --- a/src/renderer/goal.py +++ b/src/renderer/goal.py @@ -41,7 +41,7 @@ def render(self): #Show the Assists information self.matrix.clear() - self.draw_assists() + self.draw_details() self.matrix.render() self.sleepEvent.wait(self.rotation_rate) @@ -58,7 +58,7 @@ def draw_scorer(self): self.draw_hashtag() self.matrix.draw_text( (11, 8), - str(self.scorer.primaryNumber), + str(self.scorer["info"].primaryNumber), font=self.font_medium, fill=(255,255,255) ) @@ -72,18 +72,18 @@ def draw_scorer(self): self.matrix.draw_text( (8, 20), - self.scorer.firstName.upper(), + self.scorer["info"].firstName.upper(), font=self.font, fill=(255,255,255) ) self.matrix.draw_text( (8, 26), - self.scorer.lastName.upper(), + self.scorer["info"].lastName.upper(), font=self.font, fill=(255,255,255) ) - def draw_assists(self): + def draw_details(self): self.matrix.draw.rectangle([0,0,64,6], fill=(self.team_bg_color['r'], self.team_bg_color['g'], self.team_bg_color['b'])) self.matrix.draw_text( (1, 1), @@ -91,24 +91,44 @@ def draw_assists(self): font=self.font, fill=(self.team_txt_color['r'], self.team_txt_color['g'], self.team_txt_color['b']) ) - + + scorer_name_coord = self.matrix.draw_text( + (1, 8), + self.scorer["info"].lastName.upper(), + font=self.font, + fill=(255, 255, 255) + ) + scorer_points_x_coord = scorer_name_coord["position"][0] + scorer_name_coord["size"][0] + 3 + self.matrix.draw_text( + (scorer_points_x_coord, 8), + str(self.scorer["points"]), + font=self.font, + fill=(self.team_bg_color['r'], self.team_bg_color['g'], self.team_bg_color['b']) + ) + self.matrix.draw_text( - (1, 9), + (1, 15), "ASSISTS", font=self.font, - fill=(self.team_txt_color['r'], self.team_txt_color['g'], self.team_txt_color['b']), - backgroundColor=(self.team_bg_color['r'], self.team_bg_color['g'], self.team_bg_color['b']) + fill=(self.team_bg_color['r'], self.team_bg_color['g'], self.team_bg_color['b']), ) - assists_y_pos = 16 + assists_y_pos = 21 if self.assists: - for player in self.assists: - self.matrix.draw_text( + for i in range(len(self.assists)): + assist_name_coord = self.matrix.draw_text( (1, assists_y_pos), - player.lastName.upper(), + self.assists[i]["info"].lastName.upper(), font=self.font, fill=(255, 255, 255) ) + assists_points_x_coord = assist_name_coord["position"][0] + assist_name_coord["size"][0] + 3 + self.matrix.draw_text( + (assists_points_x_coord, assists_y_pos), + str(self.assists[i]["points"]), + font=self.font, + fill=(self.team_bg_color['r'], self.team_bg_color['g'], self.team_bg_color['b']) + ) assists_y_pos += 6 else: self.matrix.draw_text( diff --git a/src/renderer/main.py b/src/renderer/main.py index 1792d145..9d8b6b93 100755 --- a/src/renderer/main.py +++ b/src/renderer/main.py @@ -76,6 +76,8 @@ def __render_game_day(self): self.scoreboard = Scoreboard(self.data.overview, self.data) self.away_score = self.scoreboard.away_team.goals self.home_score = self.scoreboard.home_team.goals + # Cache to save goals and allow all the details to be collected on the API. + self.goal_team_cache = [] self.sleepEvent.clear() while not self.sleepEvent.is_set(): @@ -109,6 +111,7 @@ def __render_game_day(self): # Show Boards for Intermission self.draw_end_period_indicator() self.sleepEvent.wait(self.refresh_rate) + self.check_new_goals() self.boards._intermission(self.data, self.matrix,self.sleepEvent) else: self.sleepEvent.wait(self.refresh_rate) @@ -127,13 +130,15 @@ def __render_game_day(self): debug.info("FINAL") self.scoreboard = Scoreboard(self.data.overview, self.data) self.check_new_goals() + self.__render_postgame(self.scoreboard) self.sleepEvent.wait(self.refresh_rate) if self.data._next_game(): debug.info("moving to the next preferred game") return - self.boards._post_game(self.data, self.matrix,self.sleepEvent) + if not self.goal_team_cache: + self.boards._post_game(self.data, self.matrix,self.sleepEvent) elif self.status.is_scheduled(self.data.overview.status): """ Pre-game state """ @@ -191,9 +196,9 @@ def __render_irregular(self, scoreboard): ScoreboardRenderer(self.data, self.matrix, scoreboard).render() - def check_new_goals(self): debug.log("Check new goal") + pref_team_only = self.data.config.goal_anim_pref_team_only away_id = self.scoreboard.away_team.id away_name = self.scoreboard.away_team.name @@ -203,19 +208,40 @@ def check_new_goals(self): home_name = self.scoreboard.home_team.name home_goals = self.scoreboard.home_team.goals home_score = self.home_score + # Display goal details that are cached if there is any + # GoalRenderer(self.data, self.matrix, self.sleepEvent, self.scoreboard.away_team).render() + if self.goal_team_cache: + try: + while self.goal_team_cache: + # create a goal object first to see if there are any missing data + if self.goal_team_cache[0] == "away": + GoalRenderer(self.data, self.matrix, self.sleepEvent, self.scoreboard.away_team).render() + else: + GoalRenderer(self.data, self.matrix, self.sleepEvent, self.scoreboard.home_team).render() + # Remove the first cached goal + self.goal_team_cache.pop(0) + except IndexError: + print("crash") if away_score < away_goals: self.away_score = away_goals + self.goal_team_cache.append("away") if away_id not in self.data.pref_teams and pref_team_only: return + # run the goal animation self._draw_goal_animation(away_id, away_name) - GoalRenderer(self.data, self.matrix, self.sleepEvent, self.scoreboard.away_team).render() + + if home_score < home_goals: self.home_score = home_goals + self.goal_team_cache.append("home") if home_id not in self.data.pref_teams and pref_team_only: return - self._draw_goal_animation(home_id, home_name) - GoalRenderer(self.data, self.matrix, self.sleepEvent, self.scoreboard.home_team).render() + # run the goal animation + self._draw_goal_animation(away_id, home_name) + + + print(self.goal_team_cache) def _draw_goal_animation(self, id=14, name="test"): debug.info('Score by team: ' + name)