diff --git a/config/config.json b/config/config.json index 3e1dc7a6..8d10d3a4 100644 --- a/config/config.json +++ b/config/config.json @@ -44,9 +44,9 @@ "ncaa_fb_live": 30, "ncaa_fb_recent": 15, "ncaa_fb_upcoming": 15, - "ncaa_bb_live": 30, - "ncaa_bb_recent": 10, - "ncaa_bb_upcoming": 10, + "ncaa_baseball_live": 20, + "ncaa_baseball_recent": 15, + "ncaa_baseball_upcoming": 15, "calendar": 30, "youtube": 20, "mlb_live": 30, @@ -56,9 +56,9 @@ "soccer_live": 30, "soccer_recent": 20, "soccer_upcoming": 20, - "ncaam_live": 20, - "ncaam_recent": 15, - "ncaam_upcoming": 15, + "ncaam_basketball_live": 20, + "ncaam_basketball_recent": 15, + "ncaam_basketball_upcoming": 15, "music": 30 } }, @@ -167,21 +167,21 @@ "ncaa_fb_upcoming": true } }, - "ncaam_scoreboard": { + "ncaam_basketball_scoreboard": { "enabled": false, "test_mode": false, "update_interval_seconds": 3600, "live_update_interval": 15, "recent_game_hours": 72, "favorite_teams": ["UGA", "AUB"], - "logo_dir": "assets/sports/ncaam_logos", + "logo_dir": "assets/sports/ncaa_fbs_logos", "display_modes": { - "ncaam_live": true, - "ncaam_recent": true, - "ncaam_upcoming": true + "ncaam_basketball_live": true, + "ncaam_basketball_recent": true, + "ncaam_basketball_upcoming": true } }, - "ncaa_bb_scoreboard": { + "ncaa_baseball_scoreboard": { "enabled": false, "test_mode": false, "update_interval_seconds": 3600, @@ -189,12 +189,12 @@ "recent_update_interval": 3600, "upcoming_update_interval": 3600, "recent_game_hours": 72, - "favorite_teams": [], + "favorite_teams": ["UGA", "AUB"], "logo_dir": "assets/sports/ncaa_fbs_logos", "display_modes": { - "ncaa_bb_live": true, - "ncaa_bb_recent": true, - "ncaa_bb_upcoming": true + "ncaa_baseball_live": true, + "ncaa_baseball_recent": true, + "ncaa_baseball_upcoming": true } }, "youtube": { @@ -223,7 +223,7 @@ "font_path": "assets/fonts/press-start-2p.ttf", "font_size": 8, "scroll": true, - "scroll_speed": 25, + "scroll_speed": 40, "text_color": [255, 0, 0], "background_color": [0, 0, 0] }, diff --git a/src/display_controller.py b/src/display_controller.py index 0f79f464..1dbd9078 100644 --- a/src/display_controller.py +++ b/src/display_controller.py @@ -23,6 +23,8 @@ from src.mlb_manager import MLBLiveManager, MLBRecentManager, MLBUpcomingManager from src.soccer_managers import SoccerLiveManager, SoccerRecentManager, SoccerUpcomingManager from src.nfl_managers import NFLLiveManager, NFLRecentManager, NFLUpcomingManager from src.ncaa_fb_managers import NCAAFBLiveManager, NCAAFBRecentManager, NCAAFBUpcomingManager +from src.ncaa_baseball_managers import NCAABaseballLiveManager, NCAABaseballRecentManager, NCAABaseballUpcomingManager +from src.ncaam_basketball_managers import NCAAMBasketballLiveManager, NCAAMBasketballRecentManager, NCAAMBasketballUpcomingManager from src.youtube_display import YouTubeDisplay from src.calendar_manager import CalendarManager from src.text_display import TextDisplay @@ -173,6 +175,36 @@ class DisplayController: self.ncaa_fb_upcoming = None logger.info("NCAA FB managers initialized in %.3f seconds", time.time() - ncaa_fb_time) + # Initialize NCAA Baseball managers if enabled + ncaa_baseball_time = time.time() + ncaa_baseball_enabled = self.config.get('ncaa_baseball_scoreboard', {}).get('enabled', False) + ncaa_baseball_display_modes = self.config.get('ncaa_baseball_scoreboard', {}).get('display_modes', {}) + + if ncaa_baseball_enabled: + self.ncaa_baseball_live = NCAABaseballLiveManager(self.config, self.display_manager) if ncaa_baseball_display_modes.get('ncaa_baseball_live', True) else None + self.ncaa_baseball_recent = NCAABaseballRecentManager(self.config, self.display_manager) if ncaa_baseball_display_modes.get('ncaa_baseball_recent', True) else None + self.ncaa_baseball_upcoming = NCAABaseballUpcomingManager(self.config, self.display_manager) if ncaa_baseball_display_modes.get('ncaa_baseball_upcoming', True) else None + else: + self.ncaa_baseball_live = None + self.ncaa_baseball_recent = None + self.ncaa_baseball_upcoming = None + logger.info("NCAA Baseball managers initialized in %.3f seconds", time.time() - ncaa_baseball_time) + + # Initialize NCAA Men's Basketball managers if enabled + ncaam_basketball_time = time.time() + ncaam_basketball_enabled = self.config.get('ncaam_basketball_scoreboard', {}).get('enabled', False) + ncaam_basketball_display_modes = self.config.get('ncaam_basketball_scoreboard', {}).get('display_modes', {}) + + if ncaam_basketball_enabled: + self.ncaam_basketball_live = NCAAMBasketballLiveManager(self.config, self.display_manager) if ncaam_basketball_display_modes.get('ncaam_basketball_live', True) else None + self.ncaam_basketball_recent = NCAAMBasketballRecentManager(self.config, self.display_manager) if ncaam_basketball_display_modes.get('ncaam_basketball_recent', True) else None + self.ncaam_basketball_upcoming = NCAAMBasketballUpcomingManager(self.config, self.display_manager) if ncaam_basketball_display_modes.get('ncaam_basketball_upcoming', True) else None + else: + self.ncaam_basketball_live = None + self.ncaam_basketball_recent = None + self.ncaam_basketball_upcoming = None + logger.info("NCAA Men's Basketball managers initialized in %.3f seconds", time.time() - ncaam_basketball_time) + # Track MLB rotation state self.mlb_current_team_index = 0 self.mlb_showing_recent = True @@ -229,6 +261,18 @@ class DisplayController: if self.ncaa_fb_upcoming: self.available_modes.append('ncaa_fb_upcoming') # ncaa_fb_live is handled separately + # Add NCAA Baseball display modes if enabled + if ncaa_baseball_enabled: + if self.ncaa_baseball_recent: self.available_modes.append('ncaa_baseball_recent') + if self.ncaa_baseball_upcoming: self.available_modes.append('ncaa_baseball_upcoming') + # ncaa_baseball_live is handled separately + + # Add NCAA Men's Basketball display modes if enabled + if ncaam_basketball_enabled: + if self.ncaam_basketball_recent: self.available_modes.append('ncaam_basketball_recent') + if self.ncaam_basketball_upcoming: self.available_modes.append('ncaam_basketball_upcoming') + # ncaam_basketball_live is handled separately + # Set initial display to first available mode (clock) self.current_mode_index = 0 self.current_display_mode = self.available_modes[0] if self.available_modes else 'none' @@ -259,11 +303,23 @@ class DisplayController: self.in_nfl_rotation = False # Add NCAA FB rotation state - self.ncaa_fb_current_team_index = 0 - self.ncaa_fb_showing_recent = True + self.ncaa_fb_current_team_index = 0 + self.ncaa_fb_showing_recent = True # Start with recent games self.ncaa_fb_favorite_teams = self.config.get('ncaa_fb_scoreboard', {}).get('favorite_teams', []) self.in_ncaa_fb_rotation = False + # Add NCAA Baseball rotation state + self.ncaa_baseball_current_team_index = 0 + self.ncaa_baseball_showing_recent = True + self.ncaa_baseball_favorite_teams = self.config.get('ncaa_baseball_scoreboard', {}).get('favorite_teams', []) + self.in_ncaa_baseball_rotation = False + + # Add NCAA Men's Basketball rotation state + self.ncaam_basketball_current_team_index = 0 + self.ncaam_basketball_showing_recent = True + self.ncaam_basketball_favorite_teams = self.config.get('ncaam_basketball_scoreboard', {}).get('favorite_teams', []) + self.in_ncaam_basketball_rotation = False + # Update display durations to include all modes self.display_durations = self.config['display'].get('display_durations', {}) # Add defaults for soccer if missing @@ -294,7 +350,13 @@ class DisplayController: 'ncaa_fb_live': 30, # Added NCAA FB durations 'ncaa_fb_recent': 15, 'ncaa_fb_upcoming': 15, - 'music': 20 # Default duration for music, will be overridden by config if present + 'music': 20, # Default duration for music, will be overridden by config if present + 'ncaa_baseball_live': 30, # Added NCAA Baseball durations + 'ncaa_baseball_recent': 15, + 'ncaa_baseball_upcoming': 15, + 'ncaam_basketball_live': 30, # Added NCAA Men's Basketball durations + 'ncaam_basketball_recent': 15, + 'ncaam_basketball_upcoming': 15 } # Merge loaded durations with defaults for key, value in default_durations.items(): @@ -314,6 +376,10 @@ class DisplayController: logger.info(f"NFL Favorite teams: {self.nfl_favorite_teams}") if ncaa_fb_enabled: # Check if NCAA FB is enabled logger.info(f"NCAA FB Favorite teams: {self.ncaa_fb_favorite_teams}") + if ncaa_baseball_enabled: # Check if NCAA Baseball is enabled + logger.info(f"NCAA Baseball Favorite teams: {self.ncaa_baseball_favorite_teams}") + if ncaam_basketball_enabled: # Check if NCAA Men's Basketball is enabled + logger.info(f"NCAA Men's Basketball Favorite teams: {self.ncaam_basketball_favorite_teams}") logger.info(f"Available display modes: {self.available_modes}") logger.info(f"Initial display mode: {self.current_display_mode}") @@ -389,6 +455,16 @@ class DisplayController: if self.ncaa_fb_recent: self.ncaa_fb_recent.update() if self.ncaa_fb_upcoming: self.ncaa_fb_upcoming.update() + # Update NCAA Baseball managers + if self.ncaa_baseball_live: self.ncaa_baseball_live.update() + if self.ncaa_baseball_recent: self.ncaa_baseball_recent.update() + if self.ncaa_baseball_upcoming: self.ncaa_baseball_upcoming.update() + + # Update NCAA Men's Basketball managers + if self.ncaam_basketball_live: self.ncaam_basketball_live.update() + if self.ncaam_basketball_recent: self.ncaam_basketball_recent.update() + if self.ncaam_basketball_upcoming: self.ncaam_basketball_upcoming.update() + def _check_live_games(self) -> tuple[bool, str]: """ Check if there are any live games available. @@ -417,6 +493,16 @@ class DisplayController: if self.ncaa_fb_live and self.ncaa_fb_live.live_games: logger.debug("NCAA FB live games available") return True, 'ncaa_fb' + + if 'ncaa_baseball_scoreboard' in self.config and self.config['ncaa_baseball_scoreboard'].get('enabled', False): + if self.ncaa_baseball_live and self.ncaa_baseball_live.live_games: + logger.debug("NCAA Baseball live games available") + return True, 'ncaa_baseball' + + if 'ncaam_basketball_scoreboard' in self.config and self.config['ncaam_basketball_scoreboard'].get('enabled', False): + if self.ncaam_basketball_live and self.ncaam_basketball_live.live_games: + logger.debug("NCAA Men's Basketball live games available") + return True, 'ncaam_basketball' # Add more sports checks here (e.g., MLB, Soccer) if 'mlb' in self.config and self.config['mlb'].get('enabled', False): if self.mlb_live and self.mlb_live.live_games: @@ -608,7 +694,7 @@ class DisplayController: active_live_sports = [] # Use the same priority order as _check_live_games - priority_order = ['soccer', 'nfl', 'nhl', 'nba', 'mlb', 'ncaa_fb'] + priority_order = ['soccer', 'nfl', 'nhl', 'nba', 'mlb', 'ncaa_fb', 'ncaam_basketball', 'ncaa_baseball'] for sport in priority_order: live_attr = f"{sport}_live" if hasattr(self, live_attr) and getattr(self, live_attr) and getattr(self, live_attr).live_games: @@ -800,6 +886,14 @@ class DisplayController: manager_to_display = self.ncaa_fb_recent elif self.current_display_mode == 'ncaa_fb_upcoming' and self.ncaa_fb_upcoming: manager_to_display = self.ncaa_fb_upcoming + elif self.current_display_mode == 'ncaa_baseball_recent' and self.ncaa_baseball_recent: + manager_to_display = self.ncaa_baseball_recent + elif self.current_display_mode == 'ncaa_baseball_upcoming' and self.ncaa_baseball_upcoming: + manager_to_display = self.ncaa_baseball_upcoming + elif self.current_display_mode == 'ncaam_basketball_recent' and self.ncaam_basketball_recent: + manager_to_display = self.ncaam_basketball_recent + elif self.current_display_mode == 'ncaam_basketball_upcoming' and self.ncaam_basketball_upcoming: + manager_to_display = self.ncaam_basketball_upcoming # --- Perform Display Update --- @@ -832,6 +926,26 @@ class DisplayController: manager_to_display.display(force_clear=self.force_clear) elif self.current_display_mode == 'text_display': manager_to_display.display() # Assumes internal clearing + elif self.current_display_mode == 'nfl_live' and self.nfl_live: + self.nfl_live.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaa_fb_live' and self.ncaa_fb_live: + self.ncaa_fb_live.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaam_basketball_live' and self.ncaam_basketball_live: + self.ncaam_basketball_live.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaa_baseball_live' and self.ncaa_baseball_live: + self.ncaa_baseball_live.display(force_clear=self.force_clear) + elif self.current_display_mode == 'mlb_live' and self.mlb_live: + self.mlb_live.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaa_fb_upcoming' and self.ncaa_fb_upcoming: + self.ncaa_fb_upcoming.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaam_basketball_recent' and self.ncaam_basketball_recent: + self.ncaam_basketball_recent.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaam_basketball_upcoming' and self.ncaam_basketball_upcoming: + self.ncaam_basketball_upcoming.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaa_baseball_recent' and self.ncaa_baseball_recent: + self.ncaa_baseball_recent.display(force_clear=self.force_clear) + elif self.current_display_mode == 'ncaa_baseball_upcoming' and self.ncaa_baseball_upcoming: + self.ncaa_baseball_upcoming.display(force_clear=self.force_clear) elif hasattr(manager_to_display, 'display'): # General case for most managers manager_to_display.display(force_clear=self.force_clear) else: diff --git a/src/ncaa_bb_managers.py b/src/ncaa_baseball_managers.py similarity index 80% rename from src/ncaa_bb_managers.py rename to src/ncaa_baseball_managers.py index ac8a7057..0d8b789f 100644 --- a/src/ncaa_bb_managers.py +++ b/src/ncaa_baseball_managers.py @@ -18,26 +18,26 @@ logger = logging.getLogger(__name__) # Constants for NCAA Baseball API URL ESPN_NCAABB_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/baseball/college-baseball/scoreboard" -class BaseNCAABBMManager: - """Base class for NCAA BB managers with common functionality.""" +class BaseNCAABaseballManager: + """Base class for NCAA Baseball managers with common functionality.""" def __init__(self, config: Dict[str, Any], display_manager): self.config = config self.display_manager = display_manager - self.ncaa_bb_config = config.get('ncaa_bb_scoreboard', {}) - self.favorite_teams = self.ncaa_bb_config.get('favorite_teams', []) + self.ncaa_baseball_config = config.get('ncaa_baseball_scoreboard', {}) + self.favorite_teams = self.ncaa_baseball_config.get('favorite_teams', []) self.cache_manager = CacheManager() self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.DEBUG) # Set logger level to DEBUG # Logo handling - self.logo_dir = self.ncaa_bb_config.get('logo_dir', os.path.join('assets', 'sports', 'ncaa_fbs_logos')) + self.logo_dir = self.ncaa_baseball_config.get('logo_dir', os.path.join('assets', 'sports', 'ncaa_fbs_logos')) if not os.path.exists(self.logo_dir): - self.logger.warning(f"NCAA BB logos directory not found: {self.logo_dir}") + self.logger.warning(f"NCAA Baseball logos directory not found: {self.logo_dir}") try: os.makedirs(self.logo_dir, exist_ok=True) - self.logger.info(f"Created NCAA BB logos directory: {self.logo_dir}") + self.logger.info(f"Created NCAA Baseball logos directory: {self.logo_dir}") except Exception as e: - self.logger.error(f"Failed to create NCAA BB logos directory: {e}") + self.logger.error(f"Failed to create NCAA Baseball logos directory: {e}") # Set up session with retry logic self.session = requests.Session() @@ -60,10 +60,10 @@ class BaseNCAABBMManager: if os.path.exists(logo_path): return Image.open(logo_path) else: - logger.warning(f"[NCAABB] Logo not found for team {team_abbr}") + logger.warning(f"[NCAABaseball] Logo not found for team {team_abbr}") return None except Exception as e: - logger.error(f"[NCAABB] Error loading logo for team {team_abbr}: {e}") + logger.error(f"[NCAABaseball] Error loading logo for team {team_abbr}: {e}") return None def _draw_base_indicators(self, draw: ImageDraw.Draw, bases_occupied: List[bool], center_x: int, y: int) -> None: @@ -88,7 +88,7 @@ class BaseNCAABBMManager: draw.ellipse([x, y, x + base_size, y + base_size], outline=(255, 255, 255), width=1) def _create_game_display(self, game_data: Dict[str, Any]) -> Image.Image: - """Create a display image for an NCAA BB game with team logos, score, and game state.""" + """Create a display image for an NCAA Baseball game with team logos, score, and game state.""" width = self.display_manager.matrix.width height = self.display_manager.matrix.height image = Image.new('RGB', (width, height), color=(0, 0, 0)) @@ -127,7 +127,7 @@ class BaseNCAABBMManager: try: tz = pytz.timezone(timezone_str) except pytz.exceptions.UnknownTimeZoneError: - logger.warning(f"[NCAABB] Unknown timezone: {timezone_str}, falling back to UTC") + logger.warning(f"[NCAABaseball] Unknown timezone: {timezone_str}, falling back to UTC") tz = pytz.UTC if game_time.tzinfo is None: game_time = game_time.replace(tzinfo=pytz.UTC) @@ -177,7 +177,7 @@ class BaseNCAABBMManager: try: tz = pytz.timezone(timezone_str) except pytz.exceptions.UnknownTimeZoneError: - logger.warning(f"[NCAABB] Unknown timezone: {timezone_str}, falling back to UTC") + logger.warning(f"[NCAABaseball] Unknown timezone: {timezone_str}, falling back to UTC") tz = pytz.UTC dt = datetime.fromisoformat(game_time.replace('Z', '+00:00')) @@ -187,17 +187,17 @@ class BaseNCAABBMManager: return local_dt.strftime("%I:%M %p") except Exception as e: - logger.error(f"[NCAABB] Error formatting game time: {e}") + logger.error(f"[NCAABaseball] Error formatting game time: {e}") return "TBD" - def _fetch_ncaa_bb_api_data(self) -> Dict[str, Any]: - """Fetch NCAA BB game data from the ESPN API.""" + def _fetch_ncaa_baseball_api_data(self) -> Dict[str, Any]: + """Fetch NCAA Baseball game data from the ESPN API.""" try: # Check if test mode is enabled - if self.ncaa_bb_config.get('test_mode', False): - self.logger.info("Using test mode data for NCAA BB") + if self.ncaa_baseball_config.get('test_mode', False): + self.logger.info("Using test mode data for NCAA Baseball") return { - 'test_game_ncaabb_1': { + 'test_game_ncaabaseball_1': { 'away_team': 'LSU', 'home_team': 'FLA', 'away_score': 5, @@ -230,7 +230,7 @@ class BaseNCAABBMManager: # Use NCAA Baseball API URL url = f"{ESPN_NCAABB_SCOREBOARD_URL}?dates={date}" - self.logger.info(f"[NCAABB] Fetching games from ESPN API for date: {date}") + self.logger.info(f"[NCAABaseball] Fetching games from ESPN API for date: {date}") response = self.session.get(url, headers=self.headers, timeout=10) response.raise_for_status() @@ -246,7 +246,7 @@ class BaseNCAABBMManager: away_team = next((c for c in competitors if c['homeAway'] == 'away'), None) if not home_team or not away_team: - self.logger.warning(f"[NCAABB] Could not find home or away team for event {game_id}") + self.logger.warning(f"[NCAABaseball] Could not find home or away team for event {game_id}") continue home_abbr = home_team['team'].get('abbreviation', 'N/A') @@ -255,11 +255,11 @@ class BaseNCAABBMManager: is_favorite_game = (home_abbr in self.favorite_teams or away_abbr in self.favorite_teams) if is_favorite_game: - self.logger.info(f"[NCAABB] Found favorite team game: {away_abbr} @ {home_abbr} (Status: {status}, State: {status_state})") - self.logger.debug(f"[NCAABB] Full status data: {event['status']}") - self.logger.debug(f"[NCAABB] Status type: {status}, State: {status_state}") - self.logger.debug(f"[NCAABB] Status detail: {event['status'].get('detail', '')}") - self.logger.debug(f"[NCAABB] Status shortDetail: {event['status'].get('shortDetail', '')}") + self.logger.info(f"[NCAABaseball] Found favorite team game: {away_abbr} @ {home_abbr} (Status: {status}, State: {status_state})") + self.logger.debug(f"[NCAABaseball] Full status data: {event['status']}") + self.logger.debug(f"[NCAABaseball] Status type: {status}, State: {status_state}") + self.logger.debug(f"[NCAABaseball] Status detail: {event['status'].get('detail', '')}") + self.logger.debug(f"[NCAABaseball] Status shortDetail: {event['status'].get('shortDetail', '')}") inning = 1 inning_half = 'top' @@ -273,21 +273,21 @@ class BaseNCAABBMManager: status_detail = event['status'].get('detail', '').lower() status_short = event['status'].get('shortDetail', '').lower() - if is_favorite_game: self.logger.debug(f"[NCAABB] Raw status detail: {event['status'].get('detail')}") - if is_favorite_game: self.logger.debug(f"[NCAABB] Raw status short: {event['status'].get('shortDetail')}") + if is_favorite_game: self.logger.debug(f"[NCAABaseball] Raw status detail: {event['status'].get('detail')}") + if is_favorite_game: self.logger.debug(f"[NCAABaseball] Raw status short: {event['status'].get('shortDetail')}") inning_half = 'top' if 'bottom' in status_detail or 'bot' in status_detail or 'bottom' in status_short or 'bot' in status_short: inning_half = 'bottom' - if is_favorite_game: self.logger.debug("[NCAABB] Detected bottom of inning") + if is_favorite_game: self.logger.debug("[NCAABaseball] Detected bottom of inning") elif 'top' in status_detail or 'mid' in status_detail or 'top' in status_short or 'mid' in status_short: inning_half = 'top' - if is_favorite_game: self.logger.debug("[NCAABB] Detected top of inning") + if is_favorite_game: self.logger.debug("[NCAABaseball] Detected top of inning") - if is_favorite_game: self.logger.debug(f"[NCAABB] Determined inning: {inning_half} {inning}") + if is_favorite_game: self.logger.debug(f"[NCAABaseball] Determined inning: {inning_half} {inning}") situation = event['competitions'][0].get('situation', {}) - if is_favorite_game: self.logger.debug(f"[NCAABB] Full situation data: {situation}") + if is_favorite_game: self.logger.debug(f"[NCAABaseball] Full situation data: {situation}") # --- Simplified Count Logic --- # Primarily rely on the direct count fields first @@ -298,7 +298,7 @@ class BaseNCAABBMManager: # Basic logging if is_favorite_game: - self.logger.debug(f"[NCAABB] Direct count: B={balls}, S={strikes}, O={outs}") + self.logger.debug(f"[NCAABaseball] Direct count: B={balls}, S={strikes}, O={outs}") # Keep base occupancy logic bases_occupied = [ @@ -306,7 +306,7 @@ class BaseNCAABBMManager: situation.get('onSecond', False), situation.get('onThird', False) ] - if is_favorite_game: self.logger.debug(f"[NCAABB] Bases occupied: {bases_occupied}") + if is_favorite_game: self.logger.debug(f"[NCAABaseball] Bases occupied: {bases_occupied}") all_games[game_id] = { 'away_team': away_abbr, @@ -328,35 +328,35 @@ class BaseNCAABBMManager: if game['home_team'] in self.favorite_teams or game['away_team'] in self.favorite_teams] if favorite_games: - self.logger.info(f"[NCAABB] Found {len(favorite_games)} games for favorite teams: {self.favorite_teams}") + self.logger.info(f"[NCAABaseball] Found {len(favorite_games)} games for favorite teams: {self.favorite_teams}") for game in favorite_games: - self.logger.info(f"[NCAABB] Favorite team game: {game['away_team']} @ {game['home_team']} (Status: {game['status']}, State: {game['status_state']})") + self.logger.info(f"[NCAABaseball] Favorite team game: {game['away_team']} @ {game['home_team']} (Status: {game['status']}, State: {game['status_state']})") return all_games except Exception as e: - self.logger.error(f"[NCAABB] Error fetching NCAA BB data from ESPN API: {e}", exc_info=True) + self.logger.error(f"[NCAABaseball] Error fetching NCAA Baseball data from ESPN API: {e}", exc_info=True) return {} -class NCAABBLiveManager(BaseNCAABBMManager): - """Manager for displaying live NCAA BB games.""" +class NCAABaseballLiveManager(BaseNCAABaseballManager): + """Manager for displaying live NCAA Baseball games.""" def __init__(self, config: Dict[str, Any], display_manager): super().__init__(config, display_manager) - self.logger.info("Initialized NCAA BB Live Manager") + self.logger.info("Initialized NCAA Baseball Live Manager") self.live_games = [] self.current_game = None self.current_game_index = 0 self.last_update = 0 - self.update_interval = self.ncaa_bb_config.get('live_update_interval', 20) + self.update_interval = self.ncaa_baseball_config.get('live_update_interval', 20) self.no_data_interval = 300 self.last_game_switch = 0 - self.game_display_duration = self.ncaa_bb_config.get('live_game_duration', 30) + self.game_display_duration = self.ncaa_baseball_config.get('live_game_duration', 30) self.last_display_update = 0 self.last_log_time = 0 self.log_interval = 300 self.last_count_log_time = 0 self.count_log_interval = 5 - self.test_mode = self.ncaa_bb_config.get('test_mode', False) + self.test_mode = self.ncaa_baseball_config.get('test_mode', False) if self.test_mode: self.current_game = { @@ -377,9 +377,9 @@ class NCAABBLiveManager(BaseNCAABBMManager): "start_time": datetime.now(timezone.utc).isoformat(), } self.live_games = [self.current_game] - self.logger.info("Initialized NCAABBLiveManager with test game: LSU vs FLA") + self.logger.info("Initialized NCAABaseballLiveManager with test game: LSU vs FLA") else: - self.logger.info("Initialized NCAABBLiveManager in live mode") + self.logger.info("Initialized NCAABaseballLiveManager in live mode") def update(self): """Update live game data.""" @@ -400,7 +400,7 @@ class NCAABBLiveManager(BaseNCAABBMManager): if self.current_game["inning"] % 2 == 0: self.current_game["home_score"] = str(int(self.current_game["home_score"]) + 1) else: self.current_game["away_score"] = str(int(self.current_game["away_score"]) + 1) else: - games = self._fetch_ncaa_bb_api_data() + games = self._fetch_ncaa_baseball_api_data() if games: new_live_games = [] for game in games.values(): @@ -411,7 +411,7 @@ class NCAABBLiveManager(BaseNCAABBMManager): game['away_score'] = int(game['away_score']) new_live_games.append(game) except (ValueError, TypeError): - self.logger.warning(f"[NCAABB] Invalid score format for game {game['away_team']} @ {game['home_team']}") + self.logger.warning(f"[NCAABaseball] Invalid score format for game {game['away_team']} @ {game['home_team']}") should_log = ( current_time - self.last_log_time >= self.log_interval or @@ -421,11 +421,11 @@ class NCAABBLiveManager(BaseNCAABBMManager): if should_log: if new_live_games: - logger.info(f"[NCAABB] Found {len(new_live_games)} live games") + logger.info(f"[NCAABaseball] Found {len(new_live_games)} live games") for game in new_live_games: - logger.info(f"[NCAABB] Live game: {game['away_team']} vs {game['home_team']} - {game['inning_half']}{game['inning']}, {game['balls']}-{game['strikes']}") + logger.info(f"[NCAABaseball] Live game: {game['away_team']} vs {game['home_team']} - {game['inning_half']}{game['inning']}, {game['balls']}-{game['strikes']}") else: - logger.info("[NCAABB] No live games found") + logger.info("[NCAABaseball] No live games found") self.last_log_time = current_time if new_live_games: @@ -463,7 +463,7 @@ class NCAABBLiveManager(BaseNCAABBMManager): self.last_display_update = current_time # Track last successful update that *would* have displayed def _create_live_game_display(self, game_data: Dict[str, Any]) -> Image.Image: - """Create a display image for a live NCAA BB game.""" + """Create a display image for a live NCAA Baseball game.""" width = self.display_manager.matrix.width height = self.display_manager.matrix.height image = Image.new('RGB', (width, height), color=(0, 0, 0)) @@ -543,8 +543,8 @@ class NCAABBLiveManager(BaseNCAABBMManager): strikes = game_data.get('strikes', 0) current_time = time.time() if (game_data['home_team'] in self.favorite_teams or game_data['away_team'] in self.favorite_teams) and current_time - self.last_count_log_time >= self.count_log_interval: - self.logger.debug(f"[NCAABB] Displaying count: {balls}-{strikes}") - self.logger.debug(f"[NCAABB] Raw count data: balls={game_data.get('balls')}, strikes={game_data.get('strikes')}") + self.logger.debug(f"[NCAABaseball] Displaying count: {balls}-{strikes}") + self.logger.debug(f"[NCAABaseball] Raw count data: balls={game_data.get('balls')}, strikes={game_data.get('strikes')}") self.last_count_log_time = current_time count_text = f"{balls}-{strikes}" @@ -589,24 +589,24 @@ class NCAABBLiveManager(BaseNCAABBMManager): self.display_manager.draw = ImageDraw.Draw(self.display_manager.image) self.display_manager.update_display() except Exception as e: - logger.error(f"[NCAABB] Error displaying live game: {e}", exc_info=True) + logger.error(f"[NCAABaseball] Error displaying live game: {e}", exc_info=True) -class NCAABBRecentManager(BaseNCAABBMManager): - """Manager for displaying recent NCAA BB games.""" +class NCAABaseballRecentManager(BaseNCAABaseballManager): + """Manager for displaying recent NCAA Baseball games.""" def __init__(self, config: Dict[str, Any], display_manager): super().__init__(config, display_manager) - self.logger.info("Initialized NCAA BB Recent Manager") + self.logger.info("Initialized NCAA Baseball Recent Manager") self.recent_games = [] self.current_game = None self.current_game_index = 0 self.last_update = 0 - self.update_interval = self.ncaa_bb_config.get('recent_update_interval', 3600) - self.recent_hours = self.ncaa_bb_config.get('recent_game_hours', 72) + self.update_interval = self.ncaa_baseball_config.get('recent_update_interval', 3600) + self.recent_hours = self.ncaa_baseball_config.get('recent_game_hours', 72) self.last_game_switch = 0 self.game_display_duration = 10 self.last_warning_time = 0 self.warning_cooldown = 300 - logger.info(f"Initialized NCAABBRecentManager with {len(self.favorite_teams)} favorite teams") + logger.info(f"Initialized NCAABaseballRecentManager with {len(self.favorite_teams)} favorite teams") def update(self): """Update recent games data.""" @@ -614,16 +614,16 @@ class NCAABBRecentManager(BaseNCAABBMManager): if current_time - self.last_update < self.update_interval: return try: - games = self._fetch_ncaa_bb_api_data() + games = self._fetch_ncaa_baseball_api_data() if not games: - logger.warning("[NCAABB] No games returned from API") + logger.warning("[NCAABaseball] No games returned from API") return new_recent_games = [] now = datetime.now(timezone.utc) recent_cutoff = now - timedelta(hours=self.recent_hours) - logger.info(f"[NCAABB] Time window: {recent_cutoff} to {now}") + logger.info(f"[NCAABaseball] Time window: {recent_cutoff} to {now}") for game_id, game in games.items(): game_time_str = game['start_time'].replace('Z', '+00:00') @@ -633,41 +633,41 @@ class NCAABBRecentManager(BaseNCAABBMManager): is_favorite_game = (game['home_team'] in self.favorite_teams or game['away_team'] in self.favorite_teams) if not is_favorite_game: continue - logger.info(f"[NCAABB] Checking favorite recent game: {game['away_team']} @ {game['home_team']}") - logger.info(f"[NCAABB] Game time (UTC): {game_time}") - logger.info(f"[NCAABB] Game status: {game['status']}, State: {game['status_state']}") + logger.info(f"[NCAABaseball] Checking favorite recent game: {game['away_team']} @ {game['home_team']}") + logger.info(f"[NCAABaseball] Game time (UTC): {game_time}") + logger.info(f"[NCAABaseball] Game status: {game['status']}, State: {game['status_state']}") is_final = game['status_state'] in ['post', 'final', 'completed'] is_within_time = recent_cutoff <= game_time <= now - logger.info(f"[NCAABB] Is final: {is_final}") - logger.info(f"[NCAABB] Is within time window: {is_within_time}") + logger.info(f"[NCAABaseball] Is final: {is_final}") + logger.info(f"[NCAABaseball] Is within time window: {is_within_time}") if is_final and is_within_time: new_recent_games.append(game) - logger.info(f"[NCAABB] Added favorite team game to recent list: {game['away_team']} @ {game['home_team']}") + logger.info(f"[NCAABaseball] Added favorite team game to recent list: {game['away_team']} @ {game['home_team']}") if new_recent_games: - logger.info(f"[NCAABB] Found {len(new_recent_games)} recent games for favorite teams: {self.favorite_teams}") + logger.info(f"[NCAABaseball] Found {len(new_recent_games)} recent games for favorite teams: {self.favorite_teams}") self.recent_games = sorted(new_recent_games, key=lambda g: g.get('start_time'), reverse=True) if not self.current_game or self.current_game.get('id') not in [g.get('id') for g in self.recent_games]: self.current_game_index = 0 self.current_game = self.recent_games[0] if self.recent_games else None else: - logger.info("[NCAABB] No recent games found for favorite teams") + logger.info("[NCAABaseball] No recent games found for favorite teams") self.recent_games = [] self.current_game = None self.last_update = current_time except Exception as e: - logger.error(f"[NCAABB] Error updating recent games: {e}", exc_info=True) + logger.error(f"[NCAABaseball] Error updating recent games: {e}", exc_info=True) def display(self, force_clear: bool = False): """Display recent games.""" if not self.recent_games: current_time = time.time() if current_time - self.last_warning_time > self.warning_cooldown: - logger.info("[NCAABB] No recent games to display") + logger.info("[NCAABaseball] No recent games to display") self.last_warning_time = current_time return try: @@ -684,26 +684,26 @@ class NCAABBRecentManager(BaseNCAABBMManager): self.display_manager.draw = ImageDraw.Draw(self.display_manager.image) self.display_manager.update_display() else: - logger.warning("[NCAABB] Current game is None, cannot display recent game.") + logger.warning("[NCAABaseball] Current game is None, cannot display recent game.") except Exception as e: - logger.error(f"[NCAABB] Error displaying recent game: {e}", exc_info=True) + logger.error(f"[NCAABaseball] Error displaying recent game: {e}", exc_info=True) -class NCAABBUpcomingManager(BaseNCAABBMManager): - """Manager for displaying upcoming NCAA BB games.""" +class NCAABaseballUpcomingManager(BaseNCAABaseballManager): + """Manager for displaying upcoming NCAA Baseball games.""" def __init__(self, config: Dict[str, Any], display_manager): super().__init__(config, display_manager) - self.logger.info("Initialized NCAA BB Upcoming Manager") + self.logger.info("Initialized NCAA Baseball Upcoming Manager") self.upcoming_games = [] self.current_game = None self.current_game_index = 0 self.last_update = 0 - self.update_interval = self.ncaa_bb_config.get('upcoming_update_interval', 3600) + self.update_interval = self.ncaa_baseball_config.get('upcoming_update_interval', 3600) self.last_warning_time = 0 self.warning_cooldown = 300 self.last_game_switch = 0 self.game_display_duration = 10 - logger.info(f"Initialized NCAABBUpcomingManager with {len(self.favorite_teams)} favorite teams") + logger.info(f"Initialized NCAABaseballUpcomingManager with {len(self.favorite_teams)} favorite teams") def update(self): """Update upcoming games data.""" @@ -711,13 +711,13 @@ class NCAABBUpcomingManager(BaseNCAABBMManager): if current_time - self.last_update < self.update_interval: return try: - games = self._fetch_ncaa_bb_api_data() + games = self._fetch_ncaa_baseball_api_data() if games: new_upcoming_games = [] now = datetime.now(timezone.utc) upcoming_cutoff = now + timedelta(hours=24) - logger.info(f"[NCAABB] Looking for games between {now} and {upcoming_cutoff}") + logger.info(f"[NCAABaseball] Looking for games between {now} and {upcoming_cutoff}") for game in games.values(): is_favorite_game = (game['home_team'] in self.favorite_teams or game['away_team'] in self.favorite_teams) @@ -726,40 +726,40 @@ class NCAABBUpcomingManager(BaseNCAABBMManager): game_time = datetime.fromisoformat(game['start_time'].replace('Z', '+00:00')) if game_time.tzinfo is None: game_time = game_time.replace(tzinfo=timezone.utc) - logger.info(f"[NCAABB] Checking favorite upcoming game: {game['away_team']} @ {game['home_team']} at {game_time}") - logger.info(f"[NCAABB] Game status: {game['status']}, State: {game['status_state']}") + logger.info(f"[NCAABaseball] Checking favorite upcoming game: {game['away_team']} @ {game['home_team']} at {game_time}") + logger.info(f"[NCAABaseball] Game status: {game['status']}, State: {game['status_state']}") is_within_time = now <= game_time <= upcoming_cutoff is_upcoming_state = game['status_state'] not in ['post', 'final', 'completed'] and game['status'] == 'status_scheduled' - logger.info(f"[NCAABB] Within time: {is_within_time}") - logger.info(f"[NCAABB] Is upcoming state: {is_upcoming_state}") + logger.info(f"[NCAABaseball] Within time: {is_within_time}") + logger.info(f"[NCAABaseball] Is upcoming state: {is_upcoming_state}") if is_within_time and is_upcoming_state: new_upcoming_games.append(game) - logger.info(f"[NCAABB] Added favorite team game to upcoming list: {game['away_team']} @ {game['home_team']}") + logger.info(f"[NCAABaseball] Added favorite team game to upcoming list: {game['away_team']} @ {game['home_team']}") if new_upcoming_games: - logger.info(f"[NCAABB] Found {len(new_upcoming_games)} upcoming games for favorite teams") + logger.info(f"[NCAABaseball] Found {len(new_upcoming_games)} upcoming games for favorite teams") self.upcoming_games = sorted(new_upcoming_games, key=lambda g: g.get('start_time')) if not self.current_game or self.current_game.get('id') not in [g.get('id') for g in self.upcoming_games]: self.current_game_index = 0 self.current_game = self.upcoming_games[0] if self.upcoming_games else None else: - logger.info("[NCAABB] No upcoming games found for favorite teams") + logger.info("[NCAABaseball] No upcoming games found for favorite teams") self.upcoming_games = [] self.current_game = None self.last_update = current_time except Exception as e: - logger.error(f"[NCAABB] Error updating upcoming games: {e}", exc_info=True) + logger.error(f"[NCAABaseball] Error updating upcoming games: {e}", exc_info=True) def display(self, force_clear: bool = False): """Display upcoming games.""" if not self.upcoming_games: current_time = time.time() if current_time - self.last_warning_time > self.warning_cooldown: - logger.info("[NCAABB] No upcoming games to display") + logger.info("[NCAABaseball] No upcoming games to display") self.last_warning_time = current_time return try: @@ -776,7 +776,7 @@ class NCAABBUpcomingManager(BaseNCAABBMManager): self.display_manager.draw = ImageDraw.Draw(self.display_manager.image) self.display_manager.update_display() else: - logger.warning("[NCAABB] Current game is None, cannot display upcoming game.") + logger.warning("[NCAABaseball] Current game is None, cannot display upcoming game.") except Exception as e: - logger.error(f"[NCAABB] Error displaying upcoming game: {e}", exc_info=True) \ No newline at end of file + logger.error(f"[NCAABaseball] Error displaying upcoming game: {e}", exc_info=True) \ No newline at end of file diff --git a/src/ncaa_mb_managers.py b/src/ncaam_basketball_managers.py similarity index 85% rename from src/ncaa_mb_managers.py rename to src/ncaam_basketball_managers.py index 143978ab..28579952 100644 --- a/src/ncaa_mb_managers.py +++ b/src/ncaam_basketball_managers.py @@ -20,7 +20,7 @@ logging.basicConfig( datefmt='%Y-%m-%d %H:%M:%S' ) -class BaseNCAAMBManager: +class BaseNCAAMBasketballManager: """Base class for NCAA MB managers with common functionality.""" # Class variables for warning tracking _no_data_warning_logged = False @@ -30,21 +30,21 @@ class BaseNCAAMBManager: _shared_data = None _last_shared_update = 0 cache_manager = CacheManager() # Make cache_manager a class attribute - logger = logging.getLogger('NCAAMB') # Make logger a class attribute + logger = logging.getLogger('NCAAMBasketball') # Make logger a class attribute def __init__(self, config: Dict[str, Any], display_manager: DisplayManager): self.display_manager = display_manager self.config = config - self.ncaam_config = config.get("ncaam_scoreboard", {}) - self.is_enabled = self.ncaam_config.get("enabled", False) - self.test_mode = self.ncaam_config.get("test_mode", False) - self.logo_dir = self.ncaam_config.get("logo_dir", "assets/sports/ncaam_logos") - self.update_interval = self.ncaam_config.get("update_interval_seconds", 300) + self.ncaam_basketball_config = config.get("ncaam_basketball_scoreboard", {}) + self.is_enabled = self.ncaam_basketball_config.get("enabled", False) + self.test_mode = self.ncaam_basketball_config.get("test_mode", False) + self.logo_dir = self.ncaam_basketball_config.get("logo_dir", "assets/sports/ncaam_logos") + self.update_interval = self.ncaam_basketball_config.get("update_interval_seconds", 300) self.last_update = 0 self.current_game = None self.fonts = self._load_fonts() - self.favorite_teams = self.ncaam_config.get("favorite_teams", []) - self.recent_hours = self.ncaam_config.get("recent_game_hours", 72) # Default 72 hours + self.favorite_teams = self.ncaam_basketball_config.get("favorite_teams", []) + self.recent_hours = self.ncaam_basketball_config.get("recent_game_hours", 72) # Default 72 hours # Set logging level to INFO to reduce noise self.logger.setLevel(logging.INFO) @@ -60,7 +60,7 @@ class BaseNCAAMBManager: # Cache for loaded logos self._logo_cache = {} - self.logger.info(f"Initialized NCAAMB manager with display dimensions: {self.display_width}x{self.display_height}") + self.logger.info(f"Initialized NCAAMBasketball manager with display dimensions: {self.display_width}x{self.display_height}") self.logger.info(f"Logo directory: {self.logo_dir}") def _should_log(self, message_type: str, cooldown: int = 300) -> bool: @@ -75,7 +75,7 @@ class BaseNCAAMBManager: def _load_test_data(self) -> Dict: """Load test data for development and testing.""" - self.logger.info("[NCAAMB] Loading test data") + self.logger.info("[NCAAMBasketball] Loading test data") # Create test data with current time now = datetime.now(timezone.utc) @@ -178,18 +178,18 @@ class BaseNCAAMBManager: fonts['time'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8) fonts['team'] = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8) fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6) - logging.info("[NCAAMB] Successfully loaded Press Start 2P font for all text elements") + logging.info("[NCAAMBasketball] Successfully loaded Press Start 2P font for all text elements") except IOError: - logging.warning("[NCAAMB] Press Start 2P font not found, trying 4x6 font.") + logging.warning("[NCAAMBasketball] Press Start 2P font not found, trying 4x6 font.") try: # Try to load the 4x6 font as a fallback fonts['score'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 12) fonts['time'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 8) fonts['team'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 8) fonts['status'] = ImageFont.truetype("assets/fonts/4x6-font.ttf", 9) - logging.info("[NCAAMB] Successfully loaded 4x6 font for all text elements") + logging.info("[NCAAMBasketball] Successfully loaded 4x6 font for all text elements") except IOError: - logging.warning("[NCAAMB] 4x6 font not found, using default PIL font.") + logging.warning("[NCAAMBasketball] 4x6 font not found, using default PIL font.") # Use default PIL font as a last resort fonts['score'] = ImageFont.load_default() fonts['time'] = ImageFont.load_default() @@ -260,10 +260,10 @@ class BaseNCAAMBManager: try: # Check cache first - cache_key = f"ncaam_{date_str}" if date_str else 'ncaam_today' # Prefix cache key + cache_key = f"ncaam_basketball_{date_str}" if date_str else 'ncaam_basketball_today' # Prefix cache key cached_data = cls.cache_manager.get_cached_data(cache_key, max_age=300) # 5 minutes cache if cached_data: - cls.logger.info(f"[NCAAMB] Using cached data for {cache_key}") + cls.logger.info(f"[NCAAMBasketball] Using cached data for {cache_key}") cls._shared_data = cached_data cls._last_shared_update = current_time return cached_data @@ -277,7 +277,7 @@ class BaseNCAAMBManager: response = requests.get(url, params=params) response.raise_for_status() data = response.json() - cls.logger.info(f"[NCAAMB] Successfully fetched data from ESPN API") + cls.logger.info(f"[NCAAMBasketball] Successfully fetched data from ESPN API") # Cache the response cls.cache_manager.save_cache(cache_key, data) @@ -298,11 +298,11 @@ class BaseNCAAMBManager: all_events = [] for fetch_date in dates_to_fetch: if fetch_date != today.strftime('%Y%m%d'): # Skip today as we already have it - date_cache_key = f"ncaam_{fetch_date}" # Prefix cache key + date_cache_key = f"ncaam_basketball_{fetch_date}" # Prefix cache key # Check cache for this date cached_date_data = cls.cache_manager.get_cached_data(date_cache_key, max_age=300) if cached_date_data: - cls.logger.info(f"[NCAAMB] Using cached data for date {fetch_date}") + cls.logger.info(f"[NCAAMBasketball] Using cached data for date {fetch_date}") if "events" in cached_date_data: all_events.extend(cached_date_data["events"]) continue @@ -313,26 +313,26 @@ class BaseNCAAMBManager: date_data = response.json() if date_data and "events" in date_data: all_events.extend(date_data["events"]) - cls.logger.info(f"[NCAAMB] Fetched {len(date_data['events'])} events for date {fetch_date}") + cls.logger.info(f"[NCAAMBasketball] Fetched {len(date_data['events'])} events for date {fetch_date}") # Cache the response cls.cache_manager.save_cache(date_cache_key, date_data) # Combine events from all dates if all_events: data["events"].extend(all_events) - cls.logger.info(f"[NCAAMB] Combined {len(data['events'])} total events from all dates") + cls.logger.info(f"[NCAAMBasketball] 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"[NCAAMB] Error fetching data from ESPN: {e}") + cls.logger.error(f"[NCAAMBasketball] Error fetching data from ESPN: {e}") return None def _fetch_data(self, date_str: str = None) -> Optional[Dict]: """Fetch data using shared data mechanism.""" # For live games, bypass the shared cache to ensure fresh data - if isinstance(self, NCAAMBLiveManager): + if isinstance(self, NCAAMBasketballLiveManager): try: url = ESPN_NCAAMB_SCOREBOARD_URL params = {} @@ -342,10 +342,10 @@ class BaseNCAAMBManager: response = requests.get(url, params=params) response.raise_for_status() data = response.json() - self.logger.info(f"[NCAAMB] Successfully fetched live game data from ESPN API") + self.logger.info(f"[NCAAMBasketball] Successfully fetched live game data from ESPN API") return data except requests.exceptions.RequestException as e: - self.logger.error(f"[NCAAMB] Error fetching live game data from ESPN: {e}") + self.logger.error(f"[NCAAMBasketball] Error fetching live game data from ESPN: {e}") return None else: # For non-live games, use the shared cache @@ -365,9 +365,9 @@ class BaseNCAAMBManager: # Parse game date/time try: start_time_utc = datetime.fromisoformat(game_date_str.replace("Z", "+00:00")) - self.logger.debug(f"[NCAAMB] Parsed game time: {start_time_utc}") + self.logger.debug(f"[NCAAMBasketball] Parsed game time: {start_time_utc}") except ValueError: - logging.warning(f"[NCAAMB] Could not parse game date: {game_date_str}") + logging.warning(f"[NCAAMBasketball] Could not parse game date: {game_date_str}") start_time_utc = None home_team = next(c for c in competitors if c.get("homeAway") == "home") @@ -387,7 +387,7 @@ class BaseNCAAMBManager: if start_time_utc: cutoff_time = datetime.now(timezone.utc) - timedelta(hours=self.recent_hours) is_within_window = start_time_utc > cutoff_time - self.logger.debug(f"[NCAAMB] Game time: {start_time_utc}, Cutoff time: {cutoff_time}, Within window: {is_within_window}") + self.logger.debug(f"[NCAAMBasketball] Game time: {start_time_utc}, Cutoff time: {cutoff_time}, Within window: {is_within_window}") details = { "start_time_utc": start_time_utc, @@ -410,12 +410,12 @@ class BaseNCAAMBManager: } # Log game details for debugging - self.logger.debug(f"[NCAAMB] Extracted game details: {details['away_abbr']} vs {details['home_abbr']}") - self.logger.debug(f"[NCAAMB] Game status: is_final={details['is_final']}, is_within_window={details['is_within_window']}") + self.logger.debug(f"[NCAAMBasketball] Extracted game details: {details['away_abbr']} vs {details['home_abbr']}") + self.logger.debug(f"[NCAAMBasketball] Game status: is_final={details['is_final']}, is_within_window={details['is_within_window']}") return details except Exception as e: - logging.error(f"[NCAAMB] Error extracting game details: {e}") + logging.error(f"[NCAAMBasketball] Error extracting game details: {e}") return None def _draw_scorebug_layout(self, game: Dict, force_clear: bool = False) -> None: @@ -546,30 +546,30 @@ class BaseNCAAMBManager: self.logger.error(f"Error displaying game: {e}", exc_info=True) def display(self, force_clear: bool = False) -> None: - """Common display method for all NCAAMB managers""" + """Common display method for all NCAAMBasketball managers""" if not self.current_game: current_time = time.time() if not hasattr(self, '_last_warning_time'): self._last_warning_time = 0 if current_time - self._last_warning_time > 300: # 5 minutes cooldown - self.logger.warning("[NCAAMB] No game data available to display") + self.logger.warning("[NCAAMBasketball] No game data available to display") self._last_warning_time = current_time return self._draw_scorebug_layout(self.current_game, force_clear) -class NCAAMBLiveManager(BaseNCAAMBManager): +class NCAAMBasketballLiveManager(BaseNCAAMBasketballManager): """Manager for live NCAA MB games.""" def __init__(self, config: Dict[str, Any], display_manager: DisplayManager): super().__init__(config, display_manager) - self.update_interval = self.ncaam_config.get("live_update_interval", 15) # 15 seconds for live games + self.update_interval = self.ncaam_basketball_config.get("live_update_interval", 15) # 15 seconds for live games self.no_data_interval = 300 # 5 minutes when no live games self.last_update = 0 - self.logger.info("Initialized NCAAMB Live Manager") + self.logger.info("Initialized NCAAMBasketball Live Manager") self.live_games = [] # List to store all live games self.current_game_index = 0 # Index to track which game to show self.last_game_switch = 0 # Track when we last switched games - self.game_display_duration = self.ncaam_config.get("live_game_duration", 20) # Display each live game for 20 seconds + self.game_display_duration = self.ncaam_basketball_config.get("live_game_duration", 20) # Display each live game for 20 seconds self.last_display_update = 0 # Track when we last updated the display self.last_log_time = 0 self.log_interval = 300 # Only log status every 5 minutes @@ -584,11 +584,11 @@ class NCAAMBLiveManager(BaseNCAAMBManager): self.current_game = self._extract_game_details(live_test_event) if self.current_game: self.live_games = [self.current_game] - self.logger.info(f"[NCAAMB] Initialized NCAAMBLiveManager with test game: {self.current_game['away_abbr']} vs {self.current_game['home_abbr']}") + self.logger.info(f"[NCAAMBasketball] Initialized NCAAMBasketballLiveManager with test game: {self.current_game['away_abbr']} vs {self.current_game['home_abbr']}") else: - self.logger.warning("[NCAAMB] Could not find live test game data to initialize.") + self.logger.warning("[NCAAMBasketball] Could not find live test game data to initialize.") else: - self.logger.info("[NCAAMB] Initialized NCAAMBLiveManager in live mode") + self.logger.info("[NCAAMBasketball] Initialized NCAAMBasketballLiveManager in live mode") def update(self): """Update live game data.""" @@ -663,14 +663,14 @@ class NCAAMBLiveManager(BaseNCAAMBManager): if should_log: if new_live_games: - self.logger.info(f"[NCAAMB] Found {len(new_live_games)} live games") + self.logger.info(f"[NCAAMBasketball] Found {len(new_live_games)} live games") for game in new_live_games: status_str = f"H{game['period']}" if game['period'] <=2 else f"OT{game['period']-2 if game['period'] > 3 else ''}" - self.logger.info(f"[NCAAMB] Live game: {game['away_abbr']} vs {game['home_abbr']} - {status_str}, {game['clock']}") + self.logger.info(f"[NCAAMBasketball] Live game: {game['away_abbr']} vs {game['home_abbr']} - {status_str}, {game['clock']}") if has_favorite_team: - self.logger.info("[NCAAMB] Found live game(s) for favorite team(s)") + self.logger.info("[NCAAMBasketball] Found live game(s) for favorite team(s)") else: - self.logger.info("[NCAAMB] No live games found") + self.logger.info("[NCAAMBasketball] No live games found") self.last_log_time = current_time if new_live_games: @@ -723,7 +723,7 @@ class NCAAMBLiveManager(BaseNCAAMBManager): return super().display(force_clear) # Call parent class's display method -class NCAAMBRecentManager(BaseNCAAMBManager): +class NCAAMBasketballRecentManager(BaseNCAAMBasketballManager): """Manager for recently completed NCAA MB games.""" def __init__(self, config: Dict[str, Any], display_manager: DisplayManager): super().__init__(config, display_manager) @@ -731,14 +731,14 @@ class NCAAMBRecentManager(BaseNCAAMBManager): self.current_game_index = 0 self.last_update = 0 self.update_interval = 3600 # 1 hour for recent games - self.recent_hours = self.ncaam_config.get("recent_game_hours", 48) + self.recent_hours = self.ncaam_basketball_config.get("recent_game_hours", 48) self.last_game_switch = 0 - self.game_display_duration = self.ncaam_config.get("recent_game_duration", 15) # Configurable duration + self.game_display_duration = self.ncaam_basketball_config.get("recent_game_duration", 15) # Configurable duration self.last_log_time = 0 self.log_interval = 300 # Only log status every 5 minutes self.last_warning_time = 0 self.warning_cooldown = 300 # Only show warning every 5 minutes - self.logger.info(f"Initialized NCAAMBRecentManager with {len(self.favorite_teams)} favorite teams") + self.logger.info(f"Initialized NCAAMBasketballRecentManager with {len(self.favorite_teams)} favorite teams") def update(self): """Update recent games data.""" @@ -751,7 +751,7 @@ class NCAAMBRecentManager(BaseNCAAMBManager): data = self._fetch_data() if not data or 'events' not in data: if self._should_log("no_events", 600): # Log less frequently for no events - self.logger.warning("[NCAAMB] No events found in ESPN API response for recent games") + self.logger.warning("[NCAAMBasketball] No events found in ESPN API response for recent games") self.recent_games = [] self.current_game = None self.last_update = current_time @@ -785,9 +785,9 @@ class NCAAMBRecentManager(BaseNCAAMBManager): if should_log: if new_team_games: - self.logger.info(f"[NCAAMB] Found {len(new_team_games)} recent games for favorite teams") + self.logger.info(f"[NCAAMBasketball] Found {len(new_team_games)} recent games for favorite teams") elif self.favorite_teams: # Only log "none found" if favorites are configured - self.logger.info("[NCAAMB] No recent games found for favorite teams") + self.logger.info("[NCAAMBasketball] No recent games found for favorite teams") self.last_log_time = current_time if new_team_games: @@ -806,7 +806,7 @@ class NCAAMBRecentManager(BaseNCAAMBManager): self.last_update = current_time except Exception as e: - self.logger.error(f"[NCAAMB] Error updating recent games: {e}", exc_info=True) + self.logger.error(f"[NCAAMBasketball] Error updating recent games: {e}", exc_info=True) self.recent_games = [] # Clear games on error self.current_game = None self.last_update = current_time # Still update time to prevent fast retry loops @@ -818,9 +818,9 @@ class NCAAMBRecentManager(BaseNCAAMBManager): if current_time - self.last_warning_time > self.warning_cooldown: # Only log if favorite teams are configured if self.favorite_teams: - self.logger.info("[NCAAMB] No recent games for favorite teams to display") + self.logger.info("[NCAAMBasketball] No recent games for favorite teams to display") else: - self.logger.info("[NCAAMB] No recent games to display") + self.logger.info("[NCAAMBasketball] No recent games to display") self.last_warning_time = current_time # Explicitly clear display if there's nothing to show img = Image.new('RGB', (self.display_width, self.display_height), (0, 0, 0)) @@ -849,13 +849,13 @@ class NCAAMBRecentManager(BaseNCAAMBManager): # Update display self.display_manager.update_display() else: - self.logger.warning("[NCAAMB] Current game is None in RecentManager display, despite having recent_games list.") + self.logger.warning("[NCAAMBasketball] Current game is None in RecentManager display, despite having recent_games list.") except Exception as e: - self.logger.error(f"[NCAAMB] Error displaying recent game: {e}", exc_info=True) + self.logger.error(f"[NCAAMBasketball] Error displaying recent game: {e}", exc_info=True) -class NCAAMBUpcomingManager(BaseNCAAMBManager): +class NCAAMBasketballUpcomingManager(BaseNCAAMBasketballManager): """Manager for upcoming NCAA MB games.""" def __init__(self, config: Dict[str, Any], display_manager: DisplayManager): super().__init__(config, display_manager) @@ -866,8 +866,8 @@ class NCAAMBUpcomingManager(BaseNCAAMBManager): self.last_warning_time = 0 self.warning_cooldown = 300 # Only show warning every 5 minutes self.last_game_switch = 0 - self.game_display_duration = self.ncaam_config.get("upcoming_game_duration", 15) # Configurable duration - self.logger.info(f"Initialized NCAAMBUpcomingManager with {len(self.favorite_teams)} favorite teams") + self.game_display_duration = self.ncaam_basketball_config.get("upcoming_game_duration", 15) # Configurable duration + self.logger.info(f"Initialized NCAAMBasketballUpcomingManager with {len(self.favorite_teams)} favorite teams") def update(self): """Update upcoming games data.""" @@ -880,7 +880,7 @@ class NCAAMBUpcomingManager(BaseNCAAMBManager): data = self._fetch_data() if not data or 'events' not in data: if self._should_log("no_events_upcoming", 600): - self.logger.warning("[NCAAMB] No events found in ESPN API response for upcoming games") + self.logger.warning("[NCAAMBasketball] No events found in ESPN API response for upcoming games") self.upcoming_games = [] self.current_game = None self.last_update = current_time @@ -888,7 +888,7 @@ class NCAAMBUpcomingManager(BaseNCAAMBManager): events = data['events'] if self._should_log("fetch_success_upcoming", 300): - self.logger.info(f"[NCAAMB] Successfully fetched {len(events)} events from ESPN API for upcoming check") + self.logger.info(f"[NCAAMBasketball] Successfully fetched {len(events)} events from ESPN API for upcoming check") # Process games new_upcoming_games = [] @@ -910,9 +910,9 @@ class NCAAMBUpcomingManager(BaseNCAAMBManager): if self._should_log("team_games_upcoming", 300): if team_games: - self.logger.info(f"[NCAAMB] Found {len(team_games)} upcoming games for favorite teams") + self.logger.info(f"[NCAAMBasketball] Found {len(team_games)} upcoming games for favorite teams") elif self.favorite_teams: # Only log "none found" if favorites configured - self.logger.info("[NCAAMB] No upcoming games found for favorite teams") + self.logger.info("[NCAAMBasketball] No upcoming games found for favorite teams") if team_games: @@ -930,7 +930,7 @@ class NCAAMBUpcomingManager(BaseNCAAMBManager): self.last_update = current_time except Exception as e: - self.logger.error(f"[NCAAMB] Error updating upcoming games: {e}", exc_info=True) + self.logger.error(f"[NCAAMBasketball] Error updating upcoming games: {e}", exc_info=True) self.upcoming_games = [] # Clear games on error self.current_game = None self.last_update = current_time # Still update time @@ -941,9 +941,9 @@ class NCAAMBUpcomingManager(BaseNCAAMBManager): current_time = time.time() if current_time - self.last_warning_time > self.warning_cooldown: if self.favorite_teams: - self.logger.info("[NCAAMB] No upcoming games for favorite teams to display") + self.logger.info("[NCAAMBasketball] No upcoming games for favorite teams to display") else: - self.logger.info("[NCAAMB] No upcoming games to display") + self.logger.info("[NCAAMBasketball] No upcoming games to display") self.last_warning_time = current_time # Explicitly clear display if there's nothing to show img = Image.new('RGB', (self.display_width, self.display_height), (0, 0, 0)) @@ -973,8 +973,8 @@ class NCAAMBUpcomingManager(BaseNCAAMBManager): # Update display self.display_manager.update_display() else: - self.logger.warning("[NCAAMB] Current game is None in UpcomingManager display, despite having upcoming_games list.") + self.logger.warning("[NCAAMBasketball] Current game is None in UpcomingManager display, despite having upcoming_games list.") except Exception as e: - self.logger.error(f"[NCAAMB] Error displaying upcoming game: {e}", exc_info=True) \ No newline at end of file + self.logger.error(f"[NCAAMBasketball] Error displaying upcoming game: {e}", exc_info=True) \ No newline at end of file