refactor ncaa sports names

This commit is contained in:
ChuckBuilds
2025-05-25 16:12:02 -05:00
parent 734f03aa4f
commit 6d91c6f716
4 changed files with 297 additions and 183 deletions

View File

@@ -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:

View File

@@ -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)
logger.error(f"[NCAABaseball] Error displaying upcoming game: {e}", exc_info=True)

View File

@@ -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)
self.logger.error(f"[NCAAMBasketball] Error displaying upcoming game: {e}", exc_info=True)