diff --git a/src/nhl_managers.py b/src/nhl_managers.py index 40a59870..dbf5c6c3 100644 --- a/src/nhl_managers.py +++ b/src/nhl_managers.py @@ -76,6 +76,8 @@ class BaseNHLManager: _no_data_warning_logged = False _last_warning_time = 0 _warning_cooldown = 60 # Only log warnings once per minute + _shared_data = None + _last_shared_update = 0 def __init__(self, config: Dict[str, Any], display_manager: DisplayManager): self.display_manager = display_manager @@ -110,6 +112,89 @@ class BaseNHLManager: self.logger.info(f"Initialized NHL manager with display dimensions: {self.display_width}x{self.display_height}") self.logger.info(f"Logo directory: {self.logo_dir}") + @classmethod + def _fetch_shared_data(cls, date_str: str = None) -> Optional[Dict]: + """Fetch and cache data for all managers to share.""" + current_time = time.time() + + # If we have recent data, use it + if cls._shared_data and (current_time - cls._last_shared_update) < 300: # 5 minutes + return cls._shared_data + + try: + # Check cache first + cache_key = date_str if date_str else 'today' + cached_data = cls.cache_manager.get(cache_key, max_age=300) # 5 minutes cache + if cached_data: + cls.logger.info(f"[NHL] Using cached data for {cache_key}") + cls._shared_data = cached_data + cls._last_shared_update = current_time + return cached_data + + # If not in cache or stale, fetch from API + url = ESPN_NHL_SCOREBOARD_URL + params = {} + if date_str: + params['dates'] = date_str + + response = requests.get(url, params=params) + response.raise_for_status() + data = response.json() + cls.logger.info(f"[NHL] Successfully fetched data from ESPN API") + + # Cache the response + cls.cache_manager.set(cache_key, data) + cls._shared_data = data + cls._last_shared_update = current_time + + # If no date specified, fetch data from multiple days + if not date_str: + # Get today's date in YYYYMMDD format + today = datetime.now(timezone.utc).date() + dates_to_fetch = [ + (today - timedelta(days=2)).strftime('%Y%m%d'), + (today - timedelta(days=1)).strftime('%Y%m%d'), + today.strftime('%Y%m%d') + ] + + # Fetch data for each date + all_events = [] + for fetch_date in dates_to_fetch: + if fetch_date != today.strftime('%Y%m%d'): # Skip today as we already have it + # Check cache for this date + cached_date_data = cls.cache_manager.get(fetch_date, max_age=300) + if cached_date_data: + cls.logger.info(f"[NHL] Using cached data for date {fetch_date}") + if "events" in cached_date_data: + all_events.extend(cached_date_data["events"]) + continue + + params['dates'] = fetch_date + response = requests.get(url, params=params) + response.raise_for_status() + date_data = response.json() + if date_data and "events" in date_data: + all_events.extend(date_data["events"]) + cls.logger.info(f"[NHL] Fetched {len(date_data['events'])} events for date {fetch_date}") + # Cache the response + cls.cache_manager.set(fetch_date, date_data) + + # Combine events from all dates + if all_events: + data["events"].extend(all_events) + cls.logger.info(f"[NHL] Combined {len(data['events'])} total events from all dates") + cls._shared_data = data + cls._last_shared_update = current_time + + return data + except requests.exceptions.RequestException as e: + cls.logger.error(f"[NHL] Error fetching data from ESPN: {e}") + return None + + def _fetch_data(self, date_str: str = None) -> Optional[Dict]: + """Fetch data using shared data mechanism.""" + return self._fetch_shared_data(date_str) + def _load_fonts(self): """Load fonts used by the scoreboard.""" fonts = {} @@ -193,75 +278,6 @@ class BaseNHLManager: self.logger.error(f"Error loading logo for {team_abbrev}: {e}", exc_info=True) return None - def _fetch_data(self, date_str: str = None) -> Optional[Dict]: - """Fetch data from ESPN API with caching.""" - if self.test_mode: - return self._load_test_data() - - url = ESPN_NHL_SCOREBOARD_URL - params = {} - if date_str: - params['dates'] = date_str - - try: - # Check cache first - cache_key = date_str if date_str else 'today' - cached_data = self.cache_manager.get(cache_key, max_age=self.update_interval) - if cached_data: - self.logger.info(f"[NHL] Using cached data for {cache_key}") - return cached_data - - # If not in cache or stale, fetch from API - response = requests.get(url, params=params) - response.raise_for_status() - data = response.json() - self.logger.info(f"[NHL] Successfully fetched data from ESPN API") - - # Cache the response - self.cache_manager.set(cache_key, data) - - # If no date specified, fetch data from multiple days - if not date_str: - # Get today's date in YYYYMMDD format - today = datetime.now(timezone.utc).date() - dates_to_fetch = [ - (today - timedelta(days=2)).strftime('%Y%m%d'), - (today - timedelta(days=1)).strftime('%Y%m%d'), - today.strftime('%Y%m%d') - ] - - # Fetch data for each date - all_events = [] - for fetch_date in dates_to_fetch: - if fetch_date != today.strftime('%Y%m%d'): # Skip today as we already have it - # Check cache for this date - cached_date_data = self.cache_manager.get(fetch_date, max_age=self.update_interval) - if cached_date_data: - self.logger.info(f"[NHL] Using cached data for date {fetch_date}") - if "events" in cached_date_data: - all_events.extend(cached_date_data["events"]) - continue - - params['dates'] = fetch_date - response = requests.get(url, params=params) - response.raise_for_status() - date_data = response.json() - if date_data and "events" in date_data: - all_events.extend(date_data["events"]) - self.logger.info(f"[NHL] Fetched {len(date_data['events'])} events for date {fetch_date}") - # Cache the response - self.cache_manager.set(fetch_date, date_data) - - # Combine events from all dates - if all_events: - data["events"].extend(all_events) - self.logger.info(f"[NHL] Combined {len(data['events'])} total events from all dates") - - return data - except requests.exceptions.RequestException as e: - self.logger.error(f"[NHL] Error fetching data from ESPN: {e}") - return None - def _extract_game_details(self, game_event: Dict) -> Optional[Dict]: """Extract relevant game details from ESPN API response.""" if not game_event: