mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
huge cache refactor, dictonary error updates, and changed from time based game searching to game based for recent and upcoming
This commit is contained in:
@@ -119,7 +119,6 @@
|
||||
"scroll_speed": 1,
|
||||
"scroll_delay": 0.01,
|
||||
"display_duration": 60,
|
||||
"future_fetch_days": 45,
|
||||
"loop": true
|
||||
},
|
||||
"calendar": {
|
||||
@@ -138,7 +137,6 @@
|
||||
"live_update_interval": 30,
|
||||
"recent_update_interval": 3600,
|
||||
"upcoming_update_interval": 3600,
|
||||
"recent_game_hours": 48,
|
||||
"favorite_teams": ["TB"],
|
||||
"logo_dir": "assets/sports/nhl_logos",
|
||||
"show_records": true,
|
||||
@@ -176,8 +174,8 @@
|
||||
"live_update_interval": 30,
|
||||
"live_odds_update_interval": 3600,
|
||||
"odds_update_interval": 3600,
|
||||
"fetch_past_games": 1,
|
||||
"fetch_future_games": 2,
|
||||
"recent_games_to_show": 0,
|
||||
"upcoming_games_to_show": 2,
|
||||
"favorite_teams": ["TB", "DAL"],
|
||||
"logo_dir": "assets/sports/nfl_logos",
|
||||
"show_records": true,
|
||||
@@ -196,8 +194,8 @@
|
||||
"live_odds_update_interval": 3600,
|
||||
"odds_update_interval": 3600,
|
||||
"season_cache_duration_seconds": 86400,
|
||||
"fetch_past_games": 1,
|
||||
"fetch_future_games": 2,
|
||||
"recent_games_to_show": 0,
|
||||
"upcoming_games_to_show": 2,
|
||||
"favorite_teams": ["UGA", "AUB"],
|
||||
"logo_dir": "assets/sports/ncaa_fbs_logos",
|
||||
"show_records": true,
|
||||
@@ -255,8 +253,8 @@
|
||||
"odds_update_interval": 3600,
|
||||
"recent_update_interval": 3600,
|
||||
"upcoming_update_interval": 3600,
|
||||
"fetch_past_games": 1,
|
||||
"fetch_future_games": 5,
|
||||
"recent_games_to_show": 1,
|
||||
"upcoming_games_to_show": 1,
|
||||
"favorite_teams": ["TB", "TEX"],
|
||||
"logo_dir": "assets/sports/mlb_logos",
|
||||
"show_records": true,
|
||||
@@ -273,7 +271,8 @@
|
||||
"live_update_interval": 30,
|
||||
"recent_update_interval": 3600,
|
||||
"upcoming_update_interval": 3600,
|
||||
"recent_game_hours": 48,
|
||||
"recent_games_to_show": 1,
|
||||
"upcoming_games_to_show": 1,
|
||||
"favorite_teams": ["TAM"],
|
||||
"logo_dir": "assets/sports/milb_logos",
|
||||
"show_records": true,
|
||||
@@ -303,7 +302,6 @@
|
||||
"recent_update_interval": 3600,
|
||||
"upcoming_update_interval": 3600,
|
||||
"recent_game_hours": 168,
|
||||
"upcoming_fetch_days": 7,
|
||||
"favorite_teams": ["LIV"],
|
||||
"leagues": ["eng.1", "esp.1", "ger.1", "ita.1", "fra.1", "uefa.champions", "usa.1"],
|
||||
"logo_dir": "assets/sports/soccer_logos",
|
||||
|
||||
@@ -942,7 +942,7 @@ class MiLBRecentManager(BaseMiLBManager):
|
||||
self.current_game_index = 0
|
||||
self.last_update = 0
|
||||
self.update_interval = self.milb_config.get('recent_update_interval', 3600) # 1 hour
|
||||
self.recent_hours = self.milb_config.get('recent_game_hours', 72) # Increased from 48 to 72 hours
|
||||
self.recent_games_to_show = self.milb_config.get('recent_games_to_show', 5) # Show last 5 games
|
||||
self.last_game_switch = 0 # Track when we last switched games
|
||||
self.game_display_duration = 10 # Display each game for 10 seconds
|
||||
self.last_warning_time = 0
|
||||
@@ -966,10 +966,8 @@ class MiLBRecentManager(BaseMiLBManager):
|
||||
|
||||
# Process games
|
||||
new_recent_games = []
|
||||
now = datetime.now(timezone.utc) # Make timezone-aware
|
||||
recent_cutoff = now - timedelta(hours=self.recent_hours)
|
||||
|
||||
logger.info(f"[MiLB] Time window: {recent_cutoff} to {now}")
|
||||
logger.info(f"[MiLB] Processing {len(games)} games for recent games...")
|
||||
|
||||
for game_id, game in games.items():
|
||||
# Convert game time to UTC datetime
|
||||
@@ -989,16 +987,19 @@ class MiLBRecentManager(BaseMiLBManager):
|
||||
|
||||
# Use status_state to determine if game is final
|
||||
is_final = game['status_state'] in ['post', 'final', 'completed']
|
||||
is_within_time = recent_cutoff <= game_time <= now
|
||||
|
||||
self.logger.info(f"[MiLB] Game Time: {game_time.isoformat()}, Cutoff Time: {recent_cutoff.isoformat()}, Now: {now.isoformat()}")
|
||||
self.logger.info(f"[MiLB] Is final: {is_final}, Is within time window: {is_within_time}")
|
||||
self.logger.info(f"[MiLB] Game Time: {game_time.isoformat()}")
|
||||
self.logger.info(f"[MiLB] Is final: {is_final}")
|
||||
|
||||
# Only add favorite team games that are final and within time window
|
||||
if is_final and is_within_time:
|
||||
# Only add favorite team games that are final
|
||||
if is_final:
|
||||
new_recent_games.append(game)
|
||||
logger.info(f"[MiLB] Added favorite team game to recent list: {game['away_team']} @ {game['home_team']}")
|
||||
|
||||
# Sort by game time (most recent first) and limit to recent_games_to_show
|
||||
new_recent_games.sort(key=lambda x: x['start_time'], reverse=True)
|
||||
new_recent_games = new_recent_games[:self.recent_games_to_show]
|
||||
|
||||
if new_recent_games:
|
||||
logger.info(f"[MiLB] Found {len(new_recent_games)} recent games for favorite teams: {self.favorite_teams}")
|
||||
self.recent_games = new_recent_games
|
||||
@@ -1053,6 +1054,7 @@ class MiLBUpcomingManager(BaseMiLBManager):
|
||||
self.current_game_index = 0
|
||||
self.last_update = 0
|
||||
self.update_interval = self.milb_config.get('upcoming_update_interval', 3600) # 1 hour
|
||||
self.upcoming_games_to_show = self.milb_config.get('upcoming_games_to_show', 10) # Show next 10 games
|
||||
self.last_warning_time = 0
|
||||
self.warning_cooldown = 300 # Only show warning every 5 minutes
|
||||
self.last_game_switch = 0 # Track when we last switched games
|
||||
@@ -1073,24 +1075,44 @@ class MiLBUpcomingManager(BaseMiLBManager):
|
||||
if games:
|
||||
# Process games
|
||||
new_upcoming_games = []
|
||||
now = datetime.now(timezone.utc) # Make timezone-aware
|
||||
upcoming_cutoff = now + timedelta(hours=24)
|
||||
|
||||
logger.info(f"Looking for games between {now} and {upcoming_cutoff}")
|
||||
logger.info(f"[MiLB] Processing {len(games)} games for upcoming games...")
|
||||
|
||||
for game in games.get('events', []):
|
||||
game_data = self._extract_game_details(game)
|
||||
if game_data:
|
||||
new_upcoming_games.append(game_data)
|
||||
for game_id, game in games.items():
|
||||
# Convert game time to UTC datetime
|
||||
game_time_str = game['start_time'].replace('Z', '+00:00')
|
||||
game_time = datetime.fromisoformat(game_time_str)
|
||||
if game_time.tzinfo is None:
|
||||
game_time = game_time.replace(tzinfo=timezone.utc)
|
||||
|
||||
# Check if this is a favorite team game
|
||||
is_favorite_game = (game['home_team'] in self.favorite_teams or
|
||||
game['away_team'] in self.favorite_teams)
|
||||
|
||||
if is_favorite_game:
|
||||
logger.info(f"[MiLB] Checking favorite team game: {game['away_team']} @ {game['home_team']}")
|
||||
logger.info(f"[MiLB] Game time (UTC): {game_time}")
|
||||
logger.info(f"[MiLB] Game status: {game['status']}, State: {game['status_state']}")
|
||||
|
||||
# For upcoming games, we'll consider any game that:
|
||||
# 1. Is not final (not 'post' or 'final' state)
|
||||
# 2. Has a future start time
|
||||
is_upcoming = (
|
||||
game['status_state'] not in ['post', 'final', 'completed'] and
|
||||
game_time > datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
if is_upcoming:
|
||||
new_upcoming_games.append(game)
|
||||
logger.info(f"[MiLB] Added favorite team game to upcoming list: {game['away_team']} @ {game['home_team']}")
|
||||
|
||||
# Filter for favorite teams (though we already filtered above, this is a safety check)
|
||||
new_team_games = [game for game in new_upcoming_games
|
||||
if game['home_team'] in self.favorite_teams or
|
||||
game['away_team'] in self.favorite_teams]
|
||||
# Sort by game time (soonest first) and limit to upcoming_games_to_show
|
||||
new_upcoming_games.sort(key=lambda x: x['start_time'])
|
||||
new_upcoming_games = new_upcoming_games[:self.upcoming_games_to_show]
|
||||
|
||||
if new_team_games:
|
||||
logger.info(f"[MiLB] Found {len(new_team_games)} upcoming games for favorite teams")
|
||||
self.upcoming_games = new_team_games
|
||||
if new_upcoming_games:
|
||||
logger.info(f"[MiLB] Found {len(new_upcoming_games)} upcoming games for favorite teams")
|
||||
self.upcoming_games = new_upcoming_games
|
||||
if not self.current_game:
|
||||
self.current_game = self.upcoming_games[0]
|
||||
else:
|
||||
|
||||
@@ -414,6 +414,7 @@ class BaseMLBManager:
|
||||
response.raise_for_status()
|
||||
|
||||
data = response.json()
|
||||
self.logger.info(f"Found {len(data.get('events', []))} total games for date {date}")
|
||||
|
||||
for event in data.get('events', []):
|
||||
game_id = event['id']
|
||||
@@ -436,6 +437,9 @@ class BaseMLBManager:
|
||||
# Check if this is a favorite team game
|
||||
is_favorite_game = (home_abbr in self.favorite_teams or away_abbr in self.favorite_teams)
|
||||
|
||||
# Log all teams found for debugging
|
||||
self.logger.debug(f"Found game: {away_abbr} @ {home_abbr} (Status: {status}, State: {status_state})")
|
||||
|
||||
# Only log detailed information for favorite teams
|
||||
if is_favorite_game:
|
||||
self.logger.info(f"Found favorite team game: {away_abbr} @ {home_abbr} (Status: {status}, State: {status_state})")
|
||||
@@ -1070,7 +1074,7 @@ class MLBRecentManager(BaseMLBManager):
|
||||
self.current_game_index = 0
|
||||
self.last_update = 0
|
||||
self.update_interval = self.mlb_config.get('recent_update_interval', 3600)
|
||||
self.recent_hours = self.mlb_config.get('recent_game_hours', 72) # Increased from 48 to 72 hours
|
||||
self.recent_games_to_show = self.mlb_config.get('recent_games_to_show', 5) # Show last 5 games
|
||||
self.last_game_switch = 0 # Track when we last switched games
|
||||
self.game_display_duration = 10 # Display each game for 10 seconds
|
||||
self.last_warning_time = 0
|
||||
@@ -1094,13 +1098,11 @@ class MLBRecentManager(BaseMLBManager):
|
||||
|
||||
# Process games
|
||||
new_recent_games = []
|
||||
now = datetime.now(timezone.utc) # Make timezone-aware
|
||||
recent_cutoff = now - timedelta(hours=self.recent_hours)
|
||||
|
||||
self.logger.info(f"[MLB] Recent games time window: {recent_cutoff} to {now}")
|
||||
self.logger.info(f"[MLB] Processing {len(games)} games for recent games...")
|
||||
|
||||
for game_id, game in games.items():
|
||||
self.logger.info(f"[MLB] Processing game {game_id} for recent games...")
|
||||
self.logger.debug(f"[MLB] Processing game {game_id} for recent games...")
|
||||
# Convert game time to UTC datetime
|
||||
game_time_str = game['start_time'].replace('Z', '+00:00')
|
||||
game_time = datetime.fromisoformat(game_time_str)
|
||||
@@ -1112,7 +1114,7 @@ class MLBRecentManager(BaseMLBManager):
|
||||
game['away_team'] in self.favorite_teams)
|
||||
|
||||
if not is_favorite_game:
|
||||
self.logger.info(f"[MLB] Skipping game {game_id} - not a favorite team.")
|
||||
self.logger.debug(f"[MLB] Skipping game {game_id} - not a favorite team.")
|
||||
continue
|
||||
|
||||
self.logger.info(f"[MLB] Favorite team game found: {game['away_team']} @ {game['home_team']}")
|
||||
@@ -1121,18 +1123,21 @@ class MLBRecentManager(BaseMLBManager):
|
||||
|
||||
# Use status_state to determine if game is final
|
||||
is_final = game['status_state'] in ['post', 'final', 'completed']
|
||||
is_within_time = recent_cutoff <= game_time <= now
|
||||
|
||||
self.logger.info(f"[MLB] Game Time: {game_time.isoformat()}, Cutoff Time: {recent_cutoff.isoformat()}, Now: {now.isoformat()}")
|
||||
self.logger.info(f"[MLB] Is final: {is_final}, Is within time window: {is_within_time}")
|
||||
self.logger.info(f"[MLB] Game Time: {game_time.isoformat()}")
|
||||
self.logger.info(f"[MLB] Is final: {is_final}")
|
||||
|
||||
# Only add favorite team games that are final and within time window
|
||||
if is_final and is_within_time:
|
||||
# Only add favorite team games that are final
|
||||
if is_final:
|
||||
self.logger.info(f"[MLB] Adding game {game_id} to recent games list.")
|
||||
self._fetch_odds(game)
|
||||
new_recent_games.append(game)
|
||||
else:
|
||||
self.logger.info(f"[MLB] Skipping game {game_id} - does not meet criteria for recent games.")
|
||||
self.logger.info(f"[MLB] Skipping game {game_id} - not final.")
|
||||
|
||||
# Sort by game time (most recent first) and limit to recent_games_to_show
|
||||
new_recent_games.sort(key=lambda x: x['start_time'], reverse=True)
|
||||
new_recent_games = new_recent_games[:self.recent_games_to_show]
|
||||
|
||||
if new_recent_games:
|
||||
logger.info(f"[MLB] Found {len(new_recent_games)} recent games for favorite teams: {self.favorite_teams}")
|
||||
@@ -1188,6 +1193,7 @@ class MLBUpcomingManager(BaseMLBManager):
|
||||
self.current_game_index = 0
|
||||
self.last_update = 0
|
||||
self.update_interval = self.mlb_config.get('upcoming_update_interval', 3600)
|
||||
self.upcoming_games_to_show = self.mlb_config.get('upcoming_games_to_show', 10) # Show next 10 games
|
||||
self.last_warning_time = 0
|
||||
self.warning_cooldown = 300 # Only show warning every 5 minutes
|
||||
self.last_game_switch = 0 # Track when we last switched games
|
||||
@@ -1211,19 +1217,17 @@ class MLBUpcomingManager(BaseMLBManager):
|
||||
|
||||
# Process games
|
||||
new_upcoming_games = []
|
||||
now = datetime.now(timezone.utc) # Make timezone-aware
|
||||
upcoming_cutoff = now + timedelta(hours=24)
|
||||
|
||||
self.logger.info(f"[MLB] Upcoming games time window: {now} to {upcoming_cutoff}")
|
||||
self.logger.info(f"[MLB] Processing {len(games)} games for upcoming games...")
|
||||
|
||||
for game_id, game in games.items():
|
||||
self.logger.info(f"[MLB] Processing game {game_id} for upcoming games...")
|
||||
self.logger.debug(f"[MLB] Processing game {game_id} for upcoming games...")
|
||||
# Check if this is a favorite team game first
|
||||
is_favorite_game = (game['home_team'] in self.favorite_teams or
|
||||
game['away_team'] in self.favorite_teams)
|
||||
|
||||
if not is_favorite_game:
|
||||
self.logger.info(f"[MLB] Skipping game {game_id} - not a favorite team.")
|
||||
self.logger.debug(f"[MLB] Skipping game {game_id} - not a favorite team.")
|
||||
continue
|
||||
|
||||
game_time = datetime.fromisoformat(game['start_time'].replace('Z', '+00:00'))
|
||||
@@ -1234,20 +1238,14 @@ class MLBUpcomingManager(BaseMLBManager):
|
||||
self.logger.info(f"[MLB] Favorite team game found: {game['away_team']} @ {game['home_team']} at {game_time}")
|
||||
self.logger.info(f"[MLB] Game status: {game['status']}, State: {game['status_state']}")
|
||||
|
||||
# Check if game is within our time window
|
||||
is_within_time = now <= game_time <= upcoming_cutoff
|
||||
|
||||
# For upcoming games, we'll consider any game that:
|
||||
# 1. Is within our time window
|
||||
# 2. Is not final (not 'post' or 'final' state)
|
||||
# 3. Has a future start time
|
||||
# 1. Is not final (not 'post' or 'final' state)
|
||||
# 2. Has a future start time
|
||||
is_upcoming = (
|
||||
is_within_time and
|
||||
game['status_state'] not in ['post', 'final', 'completed'] and
|
||||
game_time > now
|
||||
game_time > datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
self.logger.info(f"[MLB] Is within time window: {is_within_time}")
|
||||
self.logger.info(f"[MLB] Is upcoming: {is_upcoming}")
|
||||
|
||||
if is_upcoming:
|
||||
@@ -1255,16 +1253,15 @@ class MLBUpcomingManager(BaseMLBManager):
|
||||
self._fetch_odds(game)
|
||||
new_upcoming_games.append(game)
|
||||
else:
|
||||
self.logger.info(f"[MLB] Skipping game {game_id} - does not meet criteria for upcoming games.")
|
||||
self.logger.info(f"[MLB] Skipping game {game_id} - not upcoming.")
|
||||
|
||||
# Filter for favorite teams (though we already filtered above, this is a safety check)
|
||||
new_team_games = [game for game in new_upcoming_games
|
||||
if game['home_team'] in self.favorite_teams or
|
||||
game['away_team'] in self.favorite_teams]
|
||||
# Sort by game time (soonest first) and limit to upcoming_games_to_show
|
||||
new_upcoming_games.sort(key=lambda x: x['start_time'])
|
||||
new_upcoming_games = new_upcoming_games[:self.upcoming_games_to_show]
|
||||
|
||||
if new_team_games:
|
||||
logger.info(f"[MLB] Found {len(new_team_games)} upcoming games for favorite teams")
|
||||
self.upcoming_games = new_team_games
|
||||
if new_upcoming_games:
|
||||
logger.info(f"[MLB] Found {len(new_upcoming_games)} upcoming games for favorite teams")
|
||||
self.upcoming_games = new_upcoming_games
|
||||
if not self.current_game:
|
||||
self.current_game = self.upcoming_games[0]
|
||||
else:
|
||||
|
||||
@@ -54,6 +54,9 @@ class BaseNCAAFBManager: # Renamed class
|
||||
self.update_interval = self.ncaa_fb_config.get("update_interval_seconds", 60)
|
||||
self.show_records = self.ncaa_fb_config.get('show_records', False)
|
||||
self.season_cache_duration = self.ncaa_fb_config.get("season_cache_duration_seconds", 86400) # 24 hours default
|
||||
# Number of games to show (instead of time-based windows)
|
||||
self.recent_games_to_show = self.ncaa_fb_config.get("recent_games_to_show", 5) # Show last 5 games
|
||||
self.upcoming_games_to_show = self.ncaa_fb_config.get("upcoming_games_to_show", 10) # Show next 10 games
|
||||
|
||||
# Set up session with retry logic
|
||||
self.session = requests.Session()
|
||||
@@ -79,8 +82,6 @@ class BaseNCAAFBManager: # Renamed class
|
||||
self.current_game = None
|
||||
self.fonts = self._load_fonts()
|
||||
self.favorite_teams = self.ncaa_fb_config.get("favorite_teams", [])
|
||||
self.fetch_past_games = self.ncaa_fb_config.get("fetch_past_games", 1)
|
||||
self.fetch_future_games = self.ncaa_fb_config.get("fetch_future_games", 1)
|
||||
|
||||
# Check display modes to determine what data to fetch
|
||||
display_modes = self.ncaa_fb_config.get("display_modes", {})
|
||||
@@ -219,46 +220,9 @@ class BaseNCAAFBManager: # Renamed class
|
||||
upcoming_events.sort(key=lambda x: x['date'])
|
||||
past_events.sort(key=lambda x: x['date'], reverse=True)
|
||||
|
||||
# Select the correct number of games for favorite teams
|
||||
selected_upcoming = []
|
||||
if self.upcoming_enabled and self.favorite_teams:
|
||||
games_found = {team: 0 for team in self.favorite_teams}
|
||||
for game in upcoming_events:
|
||||
competitors = game.get('competitions', [{}])[0].get('competitors', [])
|
||||
home_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'home'), '')
|
||||
away_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'away'), '')
|
||||
|
||||
team_in_game = None
|
||||
if home_team in self.favorite_teams and games_found[home_team] < self.fetch_future_games:
|
||||
team_in_game = home_team
|
||||
elif away_team in self.favorite_teams and games_found[away_team] < self.fetch_future_games:
|
||||
team_in_game = away_team
|
||||
|
||||
if team_in_game:
|
||||
selected_upcoming.append(game)
|
||||
games_found[team_in_game] += 1
|
||||
if all(count >= self.fetch_future_games for count in games_found.values()):
|
||||
break
|
||||
|
||||
selected_past = []
|
||||
if self.recent_enabled and self.favorite_teams:
|
||||
games_found = {team: 0 for team in self.favorite_teams}
|
||||
for game in past_events:
|
||||
competitors = game.get('competitions', [{}])[0].get('competitors', [])
|
||||
home_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'home'), '')
|
||||
away_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'away'), '')
|
||||
|
||||
team_in_game = None
|
||||
if home_team in self.favorite_teams and games_found[home_team] < self.fetch_past_games:
|
||||
team_in_game = home_team
|
||||
elif away_team in self.favorite_teams and games_found[away_team] < self.fetch_past_games:
|
||||
team_in_game = away_team
|
||||
|
||||
if team_in_game:
|
||||
selected_past.append(game)
|
||||
games_found[team_in_game] += 1
|
||||
if all(count >= self.fetch_past_games for count in games_found.values()):
|
||||
break
|
||||
# Include all games in shared data - let individual managers filter by count
|
||||
selected_upcoming = upcoming_events
|
||||
selected_past = past_events
|
||||
|
||||
# Combine all relevant events into a single list
|
||||
BaseNCAAFBManager.all_events = live_events + selected_upcoming + selected_past
|
||||
@@ -559,6 +523,9 @@ class BaseNCAAFBManager: # Renamed class
|
||||
home_timeouts = home_team.get("timeouts", 3) # Default to 3 if not specified
|
||||
away_timeouts = away_team.get("timeouts", 3) # Default to 3 if not specified
|
||||
|
||||
# For upcoming games, we'll show based on number of games, not time window
|
||||
# For recent games, we'll show based on number of games, not time window
|
||||
is_within_window = True # Always include games, let the managers filter by count
|
||||
|
||||
details = {
|
||||
"id": game_event.get("id"),
|
||||
@@ -586,6 +553,7 @@ class BaseNCAAFBManager: # Renamed class
|
||||
"down_distance_text": down_distance_text, # Added Down/Distance
|
||||
"possession": situation.get("possession") if situation else None, # ID of team with possession
|
||||
"possession_indicator": possession_indicator, # Added for easy home/away check
|
||||
"is_within_window": is_within_window, # Whether game is within display window
|
||||
}
|
||||
|
||||
# Basic validation (can be expanded)
|
||||
@@ -999,12 +967,12 @@ class NCAAFBRecentManager(BaseNCAAFBManager): # Renamed class
|
||||
events = data['events']
|
||||
# self.logger.info(f"[NCAAFB Recent] Processing {len(events)} events from shared data.") # Changed log prefix
|
||||
|
||||
# Process games and filter for final & within window & favorite teams
|
||||
# Process games and filter for final games & favorite teams
|
||||
processed_games = []
|
||||
for event in events:
|
||||
game = self._extract_game_details(event)
|
||||
# Filter criteria: must be final, within time window
|
||||
if game and game['is_final'] and game.get('is_within_window', True): # Assume within window if key missing, check logic
|
||||
# Filter criteria: must be final
|
||||
if game and game['is_final']:
|
||||
processed_games.append(game)
|
||||
|
||||
# Filter for favorite teams
|
||||
@@ -1017,6 +985,9 @@ class NCAAFBRecentManager(BaseNCAAFBManager): # Renamed class
|
||||
|
||||
# Sort by game time, most recent first
|
||||
team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.min.replace(tzinfo=timezone.utc), reverse=True)
|
||||
|
||||
# Limit to the specified number of recent games
|
||||
team_games = team_games[:self.recent_games_to_show]
|
||||
|
||||
# Cache the processed games
|
||||
self._cache_processed_games('recent', team_games)
|
||||
@@ -1212,8 +1183,8 @@ class NCAAFBUpcomingManager(BaseNCAAFBManager): # Renamed class
|
||||
processed_games = []
|
||||
for event in events:
|
||||
game = self._extract_game_details(event)
|
||||
# Filter criteria: must be upcoming ('pre' state) and within time window
|
||||
if game and game['is_upcoming'] and game.get('is_within_window', True): # Assume within window if key missing, check logic
|
||||
# Filter criteria: must be upcoming ('pre' state)
|
||||
if game and game['is_upcoming']:
|
||||
processed_games.append(game)
|
||||
|
||||
# Debug logging to see what games we have
|
||||
@@ -1246,6 +1217,9 @@ class NCAAFBUpcomingManager(BaseNCAAFBManager): # Renamed class
|
||||
|
||||
# Sort by game time, earliest first
|
||||
team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.max.replace(tzinfo=timezone.utc))
|
||||
|
||||
# Limit to the specified number of upcoming games
|
||||
team_games = team_games[:self.upcoming_games_to_show]
|
||||
|
||||
# Cache the processed games
|
||||
self._cache_processed_games('upcoming', team_games)
|
||||
|
||||
@@ -23,56 +23,7 @@ logging.basicConfig(
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
|
||||
# Re-add CacheManager definition temporarily until it's confirmed where it lives
|
||||
class CacheManager:
|
||||
"""Manages caching of ESPN API responses."""
|
||||
_instance = None
|
||||
_cache = {}
|
||||
_cache_timestamps = {}
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = super(CacheManager, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
@classmethod
|
||||
def get(cls, key: str, max_age: int = 60) -> Optional[Dict]:
|
||||
"""
|
||||
Get data from cache if it exists and is not stale.
|
||||
Args:
|
||||
key: Cache key (usually the date string)
|
||||
max_age: Maximum age of cached data in seconds
|
||||
Returns:
|
||||
Cached data if valid, None if missing or stale
|
||||
"""
|
||||
if key not in cls._cache:
|
||||
return None
|
||||
|
||||
timestamp = cls._cache_timestamps.get(key, 0)
|
||||
if time.time() - timestamp > max_age:
|
||||
# Data is stale, remove it
|
||||
del cls._cache[key]
|
||||
del cls._cache_timestamps[key]
|
||||
return None
|
||||
|
||||
return cls._cache[key]
|
||||
|
||||
@classmethod
|
||||
def set(cls, key: str, data: Dict) -> None:
|
||||
"""
|
||||
Store data in cache with current timestamp.
|
||||
Args:
|
||||
key: Cache key (usually the date string)
|
||||
data: Data to cache
|
||||
"""
|
||||
cls._cache[key] = data
|
||||
cls._cache_timestamps[key] = time.time()
|
||||
|
||||
@classmethod
|
||||
def clear(cls) -> None:
|
||||
"""Clear all cached data."""
|
||||
cls._cache.clear()
|
||||
cls._cache_timestamps.clear()
|
||||
|
||||
|
||||
class BaseNFLManager: # Renamed class
|
||||
@@ -102,8 +53,6 @@ class BaseNFLManager: # Renamed class
|
||||
self.current_game = None
|
||||
self.fonts = self._load_fonts()
|
||||
self.favorite_teams = self.nfl_config.get("favorite_teams", [])
|
||||
self.fetch_past_games = self.nfl_config.get("fetch_past_games", 1)
|
||||
self.fetch_future_games = self.nfl_config.get("fetch_future_games", 1)
|
||||
|
||||
# Check display modes to determine what data to fetch
|
||||
display_modes = self.nfl_config.get("display_modes", {})
|
||||
@@ -122,6 +71,16 @@ class BaseNFLManager: # Renamed class
|
||||
|
||||
self._logo_cache = {}
|
||||
|
||||
# Set up session with retry logic
|
||||
self.session = requests.Session()
|
||||
self.session.mount('http://', requests.adapters.HTTPAdapter(max_retries=3))
|
||||
self.session.mount('https://', requests.adapters.HTTPAdapter(max_retries=3))
|
||||
|
||||
# Set up headers for ESPN API
|
||||
self.headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
||||
}
|
||||
|
||||
self.logger.info(f"Initialized NFL manager with display dimensions: {self.display_width}x{self.display_height}")
|
||||
self.logger.info(f"Logo directory: {self.logo_dir}")
|
||||
self.logger.info(f"Display modes - Recent: {self.recent_enabled}, Upcoming: {self.upcoming_enabled}, Live: {self.live_enabled}")
|
||||
@@ -172,7 +131,7 @@ class BaseNFLManager: # Renamed class
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error fetching odds for game {game.get('id', 'N/A')}: {e}")
|
||||
|
||||
def _fetch_shared_data(self) -> None:
|
||||
def _fetch_shared_data(self) -> Optional[Dict]:
|
||||
"""
|
||||
Fetches the full season schedule for NFL, caches it, and then filters
|
||||
for relevant games based on the current configuration.
|
||||
@@ -199,11 +158,11 @@ class BaseNFLManager: # Renamed class
|
||||
self.logger.info(f"[NFL] Successfully fetched and cached {len(events)} events for the {current_year} season.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.logger.error(f"[NFL] API error fetching full schedule: {e}")
|
||||
return
|
||||
return None
|
||||
|
||||
if not events:
|
||||
self.logger.warning("[NFL] No events found in the schedule data.")
|
||||
return
|
||||
return None
|
||||
|
||||
# Filter the events for live, upcoming, and recent games
|
||||
live_events = []
|
||||
@@ -227,52 +186,16 @@ class BaseNFLManager: # Renamed class
|
||||
upcoming_events.sort(key=lambda x: x['date'])
|
||||
past_events.sort(key=lambda x: x['date'], reverse=True)
|
||||
|
||||
# Select the correct number of games for favorite teams
|
||||
selected_upcoming = []
|
||||
if self.upcoming_enabled and self.favorite_teams:
|
||||
games_found = {team: 0 for team in self.favorite_teams}
|
||||
for game in upcoming_events:
|
||||
competitors = game.get('competitions', [{}])[0].get('competitors', [])
|
||||
home_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'home'), '')
|
||||
away_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'away'), '')
|
||||
|
||||
# Check if this game involves any favorite teams that still need games
|
||||
team_in_game = None
|
||||
if home_team in self.favorite_teams and games_found[home_team] < self.fetch_future_games:
|
||||
team_in_game = home_team
|
||||
elif away_team in self.favorite_teams and games_found[away_team] < self.fetch_future_games:
|
||||
team_in_game = away_team
|
||||
|
||||
if team_in_game:
|
||||
selected_upcoming.append(game)
|
||||
games_found[team_in_game] += 1
|
||||
# Stop if we have found enough games for all teams
|
||||
if all(count >= self.fetch_future_games for count in games_found.values()):
|
||||
break
|
||||
|
||||
selected_past = []
|
||||
if self.recent_enabled and self.favorite_teams:
|
||||
games_found = {team: 0 for team in self.favorite_teams}
|
||||
for game in past_events:
|
||||
competitors = game.get('competitions', [{}])[0].get('competitors', [])
|
||||
home_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'home'), '')
|
||||
away_team = next((c['team']['abbreviation'] for c in competitors if c.get('homeAway') == 'away'), '')
|
||||
|
||||
team_in_game = None
|
||||
if home_team in self.favorite_teams and games_found[home_team] < self.fetch_past_games:
|
||||
team_in_game = home_team
|
||||
elif away_team in self.favorite_teams and games_found[away_team] < self.fetch_past_games:
|
||||
team_in_game = away_team
|
||||
|
||||
if team_in_game:
|
||||
selected_past.append(game)
|
||||
games_found[team_in_game] += 1
|
||||
if all(count >= self.fetch_past_games for count in games_found.values()):
|
||||
break
|
||||
# Include all games in shared data - let individual managers filter by count
|
||||
selected_upcoming = upcoming_events
|
||||
selected_past = past_events
|
||||
|
||||
# Combine all relevant events into a single list
|
||||
BaseNFLManager.all_events = live_events + selected_upcoming + selected_past
|
||||
self.logger.info(f"[NFL] Processed schedule: {len(live_events)} live, {len(selected_upcoming)} upcoming, {len(selected_past)} recent games.")
|
||||
|
||||
# Return the data in the expected format
|
||||
return {'events': BaseNFLManager.all_events}
|
||||
|
||||
def _fetch_data(self, date_str: str = None) -> Optional[Dict]:
|
||||
"""Fetch data using shared data mechanism or direct fetch for live."""
|
||||
@@ -294,7 +217,11 @@ class BaseNFLManager: # Renamed class
|
||||
return None
|
||||
else:
|
||||
# For non-live games, use the shared cache
|
||||
return self._fetch_shared_data()
|
||||
shared_data = self._fetch_shared_data()
|
||||
if shared_data is None:
|
||||
self.logger.warning("[NFL] No shared data available")
|
||||
return None
|
||||
return shared_data
|
||||
|
||||
def _load_fonts(self):
|
||||
"""Load fonts used by the scoreboard."""
|
||||
@@ -949,8 +876,8 @@ class NFLRecentManager(BaseNFLManager): # Renamed class
|
||||
processed_games = []
|
||||
for event in events:
|
||||
game = self._extract_game_details(event)
|
||||
# Filter criteria: must be final, within time window
|
||||
if game and game['is_final'] and game.get('is_within_window', True): # Assume within window if key missing
|
||||
# Filter criteria: must be final
|
||||
if game and game['is_final']:
|
||||
# Fetch odds if enabled
|
||||
if self.show_odds:
|
||||
self._fetch_odds(game)
|
||||
@@ -966,6 +893,10 @@ class NFLRecentManager(BaseNFLManager): # Renamed class
|
||||
|
||||
# Sort by game time, most recent first
|
||||
team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.min.replace(tzinfo=self._get_timezone()), reverse=True)
|
||||
|
||||
# Limit to the specified number of recent games (default 5)
|
||||
recent_games_to_show = self.nfl_config.get("recent_games_to_show", 5)
|
||||
team_games = team_games[:recent_games_to_show]
|
||||
|
||||
# Check if the list of games to display has changed
|
||||
new_game_ids = {g['id'] for g in team_games}
|
||||
@@ -1152,8 +1083,8 @@ class NFLUpcomingManager(BaseNFLManager): # Renamed class
|
||||
processed_games = []
|
||||
for event in events:
|
||||
game = self._extract_game_details(event)
|
||||
# Filter criteria: must be upcoming ('pre' state) and within time window
|
||||
if game and game['is_upcoming'] and game.get('is_within_window', True): # Assume within window if key missing
|
||||
# Filter criteria: must be upcoming ('pre' state)
|
||||
if game and game['is_upcoming']:
|
||||
# Fetch odds if enabled
|
||||
if self.show_odds:
|
||||
self._fetch_odds(game)
|
||||
@@ -1177,6 +1108,10 @@ class NFLUpcomingManager(BaseNFLManager): # Renamed class
|
||||
|
||||
# Sort by game time, earliest first
|
||||
team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.max.replace(tzinfo=self._get_timezone()))
|
||||
|
||||
# Limit to the specified number of upcoming games (default 10)
|
||||
upcoming_games_to_show = self.nfl_config.get("upcoming_games_to_show", 10)
|
||||
team_games = team_games[:upcoming_games_to_show]
|
||||
|
||||
# Log changes or periodically
|
||||
should_log = (
|
||||
|
||||
Reference in New Issue
Block a user