cache rework

This commit is contained in:
Chuck
2025-07-21 21:18:34 -05:00
parent 3a450b717a
commit bf44d7b55b
2 changed files with 230 additions and 190 deletions

View File

@@ -195,6 +195,7 @@
"live_update_interval": 30, "live_update_interval": 30,
"live_odds_update_interval": 3600, "live_odds_update_interval": 3600,
"odds_update_interval": 3600, "odds_update_interval": 3600,
"season_cache_duration_seconds": 86400,
"fetch_past_games": 1, "fetch_past_games": 1,
"fetch_future_games": 2, "fetch_future_games": 2,
"favorite_teams": ["UGA", "AUB"], "favorite_teams": ["UGA", "AUB"],

View File

@@ -12,6 +12,8 @@ from src.cache_manager import CacheManager # Keep CacheManager import
from src.config_manager import ConfigManager from src.config_manager import ConfigManager
from src.odds_manager import OddsManager from src.odds_manager import OddsManager
import pytz import pytz
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# Constants # Constants
ESPN_NCAAFB_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/football/college-football/scoreboard" # Changed URL for NCAA FB ESPN_NCAAFB_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/football/college-football/scoreboard" # Changed URL for NCAA FB
@@ -23,56 +25,7 @@ logging.basicConfig(
datefmt='%Y-%m-%d %H:%M:%S' 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 BaseNCAAFBManager: # Renamed class class BaseNCAAFBManager: # Renamed class
@@ -83,6 +36,8 @@ class BaseNCAAFBManager: # Renamed class
_warning_cooldown = 60 # Only log warnings once per minute _warning_cooldown = 60 # Only log warnings once per minute
_shared_data = None _shared_data = None
_last_shared_update = 0 _last_shared_update = 0
_processed_games_cache = {} # Cache for processed game data
_processed_games_timestamp = 0
cache_manager = CacheManager() cache_manager = CacheManager()
odds_manager = OddsManager(cache_manager, ConfigManager()) odds_manager = OddsManager(cache_manager, ConfigManager())
logger = logging.getLogger('NCAAFB') # Changed logger name logger = logging.getLogger('NCAAFB') # Changed logger name
@@ -98,6 +53,28 @@ class BaseNCAAFBManager: # Renamed class
self.logo_dir = self.ncaa_fb_config.get("logo_dir", "assets/sports/ncaa_fbs_logos") # Changed logo dir self.logo_dir = self.ncaa_fb_config.get("logo_dir", "assets/sports/ncaa_fbs_logos") # Changed logo dir
self.update_interval = self.ncaa_fb_config.get("update_interval_seconds", 60) self.update_interval = self.ncaa_fb_config.get("update_interval_seconds", 60)
self.show_records = self.ncaa_fb_config.get('show_records', False) 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
# Set up session with retry logic
self.session = requests.Session()
retry_strategy = Retry(
total=5, # increased number of retries
backoff_factor=1, # increased backoff factor
status_forcelist=[429, 500, 502, 503, 504], # added 429 to retry list
allowed_methods=["GET", "HEAD", "OPTIONS"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
self.session.mount("https://", adapter)
self.session.mount("http://", adapter)
# Set up headers
self.headers = {
'User-Agent': 'LEDMatrix/1.0 (https://github.com/yourusername/LEDMatrix; contact@example.com)',
'Accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive'
}
self.last_update = 0 self.last_update = 0
self.current_game = None self.current_game = None
self.fonts = self._load_fonts() self.fonts = self._load_fonts()
@@ -172,10 +149,16 @@ class BaseNCAAFBManager: # Renamed class
except Exception as e: except Exception as e:
self.logger.error(f"Error fetching odds for game {game.get('id', 'N/A')}: {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 NCAAFB, caches it, and then filters Fetches the full season schedule for NCAAFB, caches it, and then filters
for relevant games based on the current configuration. for relevant games based on the current configuration.
Caching Strategy:
- Season schedules: Cached for 24 hours (configurable) - schedules rarely change
- Live games: Cached for 60 seconds - scores update frequently
- Processed data: Cached for 5 minutes - avoids re-processing
- Recent/Upcoming: Use shared season data + local processing cache
""" """
now = datetime.now(pytz.utc) now = datetime.now(pytz.utc)
current_year = now.year current_year = now.year
@@ -187,7 +170,9 @@ class BaseNCAAFBManager: # Renamed class
all_events = [] all_events = []
for year in years_to_check: for year in years_to_check:
cache_key = f"ncaafb_schedule_{year}" cache_key = f"ncaafb_schedule_{year}"
cached_data = BaseNCAAFBManager.cache_manager.get(cache_key) # Use much longer cache duration for season schedules (configurable, default 24 hours)
# Season schedules rarely change and can be cached for days
cached_data = BaseNCAAFBManager.cache_manager.get(cache_key, max_age=self.season_cache_duration)
if cached_data: if cached_data:
self.logger.info(f"[NCAAFB] Using cached schedule for {year}") self.logger.info(f"[NCAAFB] Using cached schedule for {year}")
@@ -201,7 +186,7 @@ class BaseNCAAFBManager: # Renamed class
response.raise_for_status() response.raise_for_status()
data = response.json() data = response.json()
events = data.get('events', []) events = data.get('events', [])
BaseNCAAFBManager.cache_manager.set(cache_key, events, expiration_seconds=86400) # Cache for 24 hours BaseNCAAFBManager.cache_manager.update_cache(cache_key, events)
self.logger.info(f"[NCAAFB] Successfully fetched and cached {len(events)} events for the {year} season.") self.logger.info(f"[NCAAFB] Successfully fetched and cached {len(events)} events for the {year} season.")
all_events.extend(events) all_events.extend(events)
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
@@ -210,7 +195,7 @@ class BaseNCAAFBManager: # Renamed class
if not all_events: if not all_events:
self.logger.warning("[NCAAFB] No events found in the schedule data for checked years.") self.logger.warning("[NCAAFB] No events found in the schedule data for checked years.")
return return None
# Filter the events for live, upcoming, and recent games # Filter the events for live, upcoming, and recent games
live_events = [] live_events = []
@@ -279,10 +264,40 @@ class BaseNCAAFBManager: # Renamed class
BaseNCAAFBManager.all_events = live_events + selected_upcoming + selected_past BaseNCAAFBManager.all_events = live_events + selected_upcoming + selected_past
self.logger.info(f"[NCAAFB] Processed schedule: {len(live_events)} live, {len(selected_upcoming)} upcoming, {len(selected_past)} recent games.") self.logger.info(f"[NCAAFB] Processed schedule: {len(live_events)} live, {len(selected_upcoming)} upcoming, {len(selected_past)} recent games.")
# Return the data in the expected format
return {'events': BaseNCAAFBManager.all_events}
def _get_cached_processed_games(self, manager_type: str) -> Optional[List[Dict]]:
"""Get cached processed games for a specific manager type."""
current_time = time.time()
cache_key = f"processed_games_{manager_type}"
# Cache processed games for 5 minutes
if (current_time - BaseNCAAFBManager._processed_games_timestamp < 300 and
cache_key in BaseNCAAFBManager._processed_games_cache):
return BaseNCAAFBManager._processed_games_cache[cache_key]
return None
def _cache_processed_games(self, manager_type: str, games: List[Dict]) -> None:
"""Cache processed games for a specific manager type."""
cache_key = f"processed_games_{manager_type}"
BaseNCAAFBManager._processed_games_cache[cache_key] = games
BaseNCAAFBManager._processed_games_timestamp = time.time()
def _fetch_data(self, date_str: str = None) -> Optional[Dict]: def _fetch_data(self, date_str: str = None) -> Optional[Dict]:
"""Fetch data using shared data mechanism or direct fetch for live.""" """Fetch data using shared data mechanism or direct fetch for live."""
# Check if the instance is NCAAFBLiveManager # Check if the instance is NCAAFBLiveManager
if isinstance(self, NCAAFBLiveManager): # Changed class name if isinstance(self, NCAAFBLiveManager): # Changed class name
# For live games, use shorter cache duration (60 seconds)
# Live scores can be fetched more frequently if needed
cache_key = f"ncaafb_live_{date_str or 'current'}"
cached_data = self.cache_manager.get(cache_key, max_age=60)
if cached_data:
self.logger.debug(f"[NCAAFB] Using cached live data")
return cached_data
try: try:
url = ESPN_NCAAFB_SCOREBOARD_URL # Use NCAA FB URL url = ESPN_NCAAFB_SCOREBOARD_URL # Use NCAA FB URL
params = {} params = {}
@@ -292,6 +307,8 @@ class BaseNCAAFBManager: # Renamed class
response = requests.get(url, params=params) response = requests.get(url, params=params)
response.raise_for_status() response.raise_for_status()
data = response.json() data = response.json()
# Cache live data for 60 seconds
self.cache_manager.update_cache(cache_key, data)
self.logger.info(f"[NCAAFB] Successfully fetched live game data from ESPN API") self.logger.info(f"[NCAAFB] Successfully fetched live game data from ESPN API")
return data return data
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
@@ -299,7 +316,11 @@ class BaseNCAAFBManager: # Renamed class
return None return None
else: else:
# For non-live games, use the shared cache # 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("[NCAAFB] No shared data available")
return None
return shared_data
def _load_fonts(self): def _load_fonts(self):
"""Load fonts used by the scoreboard.""" """Load fonts used by the scoreboard."""
@@ -961,70 +982,79 @@ class NCAAFBRecentManager(BaseNCAAFBManager): # Renamed class
return return
self.last_update = current_time # Update time even if fetch fails self.last_update = current_time # Update time even if fetch fails
try:
data = self._fetch_data() # Uses shared cache
if not data or 'events' not in data:
self.logger.warning("[NCAAFB Recent] No events found in shared data.") # Changed log prefix
if not self.games_list: self.current_game = None # Clear display if no games were showing
return
events = data['events'] # Check for cached processed games first
# self.logger.info(f"[NCAAFB Recent] Processing {len(events)} events from shared data.") # Changed log prefix cached_games = self._get_cached_processed_games('recent')
if cached_games:
self.logger.debug("[NCAAFB Recent] Using cached processed games")
team_games = cached_games
else:
try:
data = self._fetch_data() # Uses shared cache
if not data or 'events' not in data:
self.logger.warning("[NCAAFB Recent] No events found in shared data.") # Changed log prefix
if not self.games_list: self.current_game = None # Clear display if no games were showing
return
# Process games and filter for final & within window & favorite teams events = data['events']
processed_games = [] # self.logger.info(f"[NCAAFB Recent] Processing {len(events)} events from shared data.") # Changed log prefix
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
processed_games.append(game)
# Filter for favorite teams # Process games and filter for final & within window & favorite teams
if self.favorite_teams: processed_games = []
team_games = [game for game in processed_games for event in events:
if game['home_abbr'] in self.favorite_teams or game = self._extract_game_details(event)
game['away_abbr'] in self.favorite_teams] # Filter criteria: must be final, within time window
else: if game and game['is_final'] and game.get('is_within_window', True): # Assume within window if key missing, check logic
team_games = processed_games # Show all recent games if no favorites defined processed_games.append(game)
# Sort by game time, most recent first # Filter for favorite teams
team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.min.replace(tzinfo=timezone.utc), reverse=True) if self.favorite_teams:
team_games = [game for game in processed_games
# Check if the list of games to display has changed if game['home_abbr'] in self.favorite_teams or
new_game_ids = {g['id'] for g in team_games} game['away_abbr'] in self.favorite_teams]
current_game_ids = {g['id'] for g in self.games_list}
if new_game_ids != current_game_ids:
self.logger.info(f"[NCAAFB Recent] Found {len(team_games)} final games within window for display.") # Changed log prefix
self.games_list = team_games
# Reset index if list changed or current game removed
if not self.current_game or not self.games_list or self.current_game['id'] not in new_game_ids:
self.current_game_index = 0
self.current_game = self.games_list[0] if self.games_list else None
self.last_game_switch = current_time # Reset switch timer
else: else:
# Try to maintain position if possible team_games = processed_games # Show all recent games if no favorites defined
try:
self.current_game_index = next(i for i, g in enumerate(self.games_list) if g['id'] == self.current_game['id'])
self.current_game = self.games_list[self.current_game_index] # Update data just in case
except StopIteration:
self.current_game_index = 0
self.current_game = self.games_list[0]
self.last_game_switch = current_time
elif self.games_list: # Sort by game time, most recent first
# List content is same, just update data for current game team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.min.replace(tzinfo=timezone.utc), reverse=True)
self.current_game = self.games_list[self.current_game_index]
# Cache the processed games
self._cache_processed_games('recent', team_games)
if not self.games_list: # Check if the list of games to display has changed
self.logger.info("[NCAAFB Recent] No relevant recent games found to display.") # Changed log prefix new_game_ids = {g['id'] for g in team_games}
self.current_game = None # Ensure display clears if no games current_game_ids = {g['id'] for g in self.games_list}
except Exception as e: if new_game_ids != current_game_ids:
self.logger.error(f"[NCAAFB Recent] Error updating recent games: {e}", exc_info=True) # Changed log prefix self.logger.info(f"[NCAAFB Recent] Found {len(team_games)} final games within window for display.") # Changed log prefix
# Don't clear current game on error, keep showing last known state self.games_list = team_games
# self.current_game = None # Decide if we want to clear display on error # Reset index if list changed or current game removed
if not self.current_game or not self.games_list or self.current_game['id'] not in new_game_ids:
self.current_game_index = 0
self.current_game = self.games_list[0] if self.games_list else None
self.last_game_switch = current_time # Reset switch timer
else:
# Try to maintain position if possible
try:
self.current_game_index = next(i for i, g in enumerate(self.games_list) if g['id'] == self.current_game['id'])
self.current_game = self.games_list[self.current_game_index] # Update data just in case
except StopIteration:
self.current_game_index = 0
self.current_game = self.games_list[0]
self.last_game_switch = current_time
elif self.games_list:
# List content is same, just update data for current game
self.current_game = self.games_list[self.current_game_index]
if not self.games_list:
self.logger.info("[NCAAFB Recent] No relevant recent games found to display.") # Changed log prefix
self.current_game = None # Ensure display clears if no games
except Exception as e:
self.logger.error(f"[NCAAFB Recent] Error updating recent games: {e}", exc_info=True) # Changed log prefix
# Don't clear current game on error, keep showing last known state
# self.current_game = None # Decide if we want to clear display on error
def _draw_scorebug_layout(self, game: Dict, force_clear: bool = False) -> None: def _draw_scorebug_layout(self, game: Dict, force_clear: bool = False) -> None:
"""Draw the layout for a recently completed NCAA FB game.""" # Updated docstring """Draw the layout for a recently completed NCAA FB game.""" # Updated docstring
@@ -1162,101 +1192,110 @@ class NCAAFBUpcomingManager(BaseNCAAFBManager): # Renamed class
return return
self.last_update = current_time self.last_update = current_time
try:
data = self._fetch_data() # Uses shared cache
if not data or 'events' not in data:
self.logger.warning("[NCAAFB Upcoming] No events found in shared data.") # Changed log prefix
if not self.games_list: self.current_game = None
return
events = data['events'] # Check for cached processed games first
# self.logger.info(f"[NCAAFB Upcoming] Processing {len(events)} events from shared data.") # Changed log prefix cached_games = self._get_cached_processed_games('upcoming')
if cached_games:
self.logger.debug("[NCAAFB Upcoming] Using cached processed games")
team_games = cached_games
else:
try:
data = self._fetch_data() # Uses shared cache
if not data or 'events' not in data:
self.logger.warning("[NCAAFB Upcoming] No events found in shared data.") # Changed log prefix
if not self.games_list: self.current_game = None
return
processed_games = [] events = data['events']
for event in events: # self.logger.info(f"[NCAAFB Upcoming] Processing {len(events)} events from shared data.") # Changed log prefix
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
processed_games.append(game)
# Debug logging to see what games we have processed_games = []
self.logger.debug(f"[NCAAFB Upcoming] Processed {len(processed_games)} upcoming games") for event in events:
for game in processed_games: game = self._extract_game_details(event)
self.logger.debug(f"[NCAAFB Upcoming] Game: {game['away_abbr']}@{game['home_abbr']} - Upcoming: {game['is_upcoming']}") # 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
processed_games.append(game)
# Log all unique teams found for debugging # Debug logging to see what games we have
all_teams = set() self.logger.debug(f"[NCAAFB Upcoming] Processed {len(processed_games)} upcoming games")
for game in processed_games: for game in processed_games:
all_teams.add(game['away_abbr']) self.logger.debug(f"[NCAAFB Upcoming] Game: {game['away_abbr']}@{game['home_abbr']} - Upcoming: {game['is_upcoming']}")
all_teams.add(game['home_abbr'])
self.logger.debug(f"[NCAAFB Upcoming] All teams found in API: {sorted(all_teams)}")
# Debug: Log what events we received and what we extracted # Log all unique teams found for debugging
self.logger.debug(f"[NCAAFB Upcoming] Received {len(events)} events from shared data") all_teams = set()
for i, event in enumerate(events): for game in processed_games:
self.logger.debug(f"[NCAAFB Upcoming] Event {i}: ID={event.get('id')}, Status={event.get('competitions', [{}])[0].get('status', {}).get('type', {}).get('name', 'unknown')}") all_teams.add(game['away_abbr'])
all_teams.add(game['home_abbr'])
self.logger.debug(f"[NCAAFB Upcoming] All teams found in API: {sorted(all_teams)}")
# Filter for favorite teams # Debug: Log what events we received and what we extracted
if self.favorite_teams: self.logger.debug(f"[NCAAFB Upcoming] Received {len(events)} events from shared data")
team_games = [game for game in processed_games for i, event in enumerate(events):
if game['home_abbr'] in self.favorite_teams or self.logger.debug(f"[NCAAFB Upcoming] Event {i}: ID={event.get('id')}, Status={event.get('competitions', [{}])[0].get('status', {}).get('type', {}).get('name', 'unknown')}")
game['away_abbr'] in self.favorite_teams]
self.logger.debug(f"[NCAAFB Upcoming] After favorite team filtering: {len(team_games)} games")
for game in team_games:
self.logger.debug(f"[NCAAFB Upcoming] Favorite game: {game['away_abbr']}@{game['home_abbr']}")
else:
team_games = processed_games # Show all upcoming if no favorites
# Sort by game time, earliest first # Filter for favorite teams
team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.max.replace(tzinfo=timezone.utc)) if self.favorite_teams:
team_games = [game for game in processed_games
if game['home_abbr'] in self.favorite_teams or
game['away_abbr'] in self.favorite_teams]
self.logger.debug(f"[NCAAFB Upcoming] After favorite team filtering: {len(team_games)} games")
for game in team_games:
self.logger.debug(f"[NCAAFB Upcoming] Favorite game: {game['away_abbr']}@{game['home_abbr']}")
else:
team_games = processed_games # Show all upcoming if no favorites
# Log changes or periodically # Sort by game time, earliest first
should_log = ( team_games.sort(key=lambda g: g.get('start_time_utc') or datetime.max.replace(tzinfo=timezone.utc))
current_time - self.last_log_time >= self.log_interval or
len(team_games) != len(self.games_list) or
any(g1['id'] != g2.get('id') for g1, g2 in zip(self.games_list, team_games)) or
(not self.games_list and team_games)
)
# Check if the list of games to display has changed # Cache the processed games
new_game_ids = {g['id'] for g in team_games} self._cache_processed_games('upcoming', team_games)
current_game_ids = {g['id'] for g in self.games_list}
if new_game_ids != current_game_ids: # Log changes or periodically
self.logger.info(f"[NCAAFB Upcoming] Found {len(team_games)} upcoming games within window for display.") # Changed log prefix should_log = (
self.games_list = team_games current_time - self.last_log_time >= self.log_interval or
if not self.current_game or not self.games_list or self.current_game['id'] not in new_game_ids: len(team_games) != len(self.games_list) or
self.current_game_index = 0 any(g1['id'] != g2.get('id') for g1, g2 in zip(self.games_list, team_games)) or
self.current_game = self.games_list[0] if self.games_list else None (not self.games_list and team_games)
self.last_game_switch = current_time )
else:
try:
self.current_game_index = next(i for i, g in enumerate(self.games_list) if g['id'] == self.current_game['id'])
self.current_game = self.games_list[self.current_game_index]
except StopIteration:
self.current_game_index = 0
self.current_game = self.games_list[0]
self.last_game_switch = current_time
elif self.games_list: # Check if the list of games to display has changed
self.current_game = self.games_list[self.current_game_index] # Update data new_game_ids = {g['id'] for g in team_games}
current_game_ids = {g['id'] for g in self.games_list}
if not self.games_list: if new_game_ids != current_game_ids:
self.logger.info("[NCAAFB Upcoming] No relevant upcoming games found to display.") # Changed log prefix self.logger.info(f"[NCAAFB Upcoming] Found {len(team_games)} upcoming games within window for display.") # Changed log prefix
self.current_game = None self.games_list = team_games
if not self.current_game or not self.games_list or self.current_game['id'] not in new_game_ids:
self.current_game_index = 0
self.current_game = self.games_list[0] if self.games_list else None
self.last_game_switch = current_time
else:
try:
self.current_game_index = next(i for i, g in enumerate(self.games_list) if g['id'] == self.current_game['id'])
self.current_game = self.games_list[self.current_game_index]
except StopIteration:
self.current_game_index = 0
self.current_game = self.games_list[0]
self.last_game_switch = current_time
if should_log and not self.games_list: elif self.games_list:
# Log favorite teams only if no games are found and logging is needed self.current_game = self.games_list[self.current_game_index] # Update data
self.logger.debug(f"[NCAAFB Upcoming] Favorite teams: {self.favorite_teams}") # Changed log prefix
self.logger.debug(f"[NCAAFB Upcoming] Total upcoming games before filtering: {len(processed_games)}") # Changed log prefix
self.last_log_time = current_time
elif should_log:
self.last_log_time = current_time
if not self.games_list:
self.logger.info("[NCAAFB Upcoming] No relevant upcoming games found to display.") # Changed log prefix
self.current_game = None
except Exception as e: if should_log and not self.games_list:
self.logger.error(f"[NCAAFB Upcoming] Error updating upcoming games: {e}", exc_info=True) # Changed log prefix # Log favorite teams only if no games are found and logging is needed
# self.current_game = None # Decide if clear on error self.logger.debug(f"[NCAAFB Upcoming] Favorite teams: {self.favorite_teams}") # Changed log prefix
self.logger.debug(f"[NCAAFB Upcoming] Total upcoming games before filtering: {len(processed_games)}") # Changed log prefix
self.last_log_time = current_time
elif should_log:
self.last_log_time = current_time
except Exception as e:
self.logger.error(f"[NCAAFB Upcoming] Error updating upcoming games: {e}", exc_info=True) # Changed log prefix
# self.current_game = None # Decide if clear on error
def _draw_scorebug_layout(self, game: Dict, force_clear: bool = False) -> None: def _draw_scorebug_layout(self, game: Dict, force_clear: bool = False) -> None:
"""Draw the layout for an upcoming NCAA FB game.""" # Updated docstring """Draw the layout for an upcoming NCAA FB game.""" # Updated docstring