mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-11 05:13:01 +00:00
* Fix leaderboard scrolling performance after PR #39 merge - Restore leaderboard background updates that were accidentally removed - Fix duration method call from get_dynamic_duration() back to get_duration() - Restore proper fallback duration (600s instead of 60s) for leaderboard - Add back sports manager updates that feed data to leaderboard - Fix leaderboard defer_update priority to prevent scrolling lag These changes restore the leaderboard's dynamic duration calculation and ensure it gets proper background updates for smooth scrolling. * Apply PR #60 leaderboard performance optimizations - Change scroll_delay from 0.05s to 0.01s (100fps instead of 20fps) - Remove conditional scrolling logic - scroll every frame for smooth animation - Add FPS tracking and logging for performance monitoring - Restore high-framerate scrolling that was working before PR #39 merge These changes restore the smooth leaderboard scrolling performance that was achieved in PR #60 but was lost during the PR #39 merge. * Fix critical bugs identified in PR #39 review - Fix record filtering logic bug: change away_record == set to away_record in set - Fix incorrect sport specification: change 'nfl' to 'ncaa_fb' for NCAA Football data requests - These bugs were causing incorrect data display and wrong sport data fetching Addresses issues found by cursor bot in PR #39 review: - Record filtering was always evaluating to False - NCAA Football was fetching NFL data instead of college football data * Enhance cache clearing implementation from PR #39 - Add detailed logging to cache clearing process for better visibility - Log cache clearing statistics (memory entries and file count) - Improve startup logging to show cache clearing and data refetch process - Addresses legoguy1000's comment about preventing stale data issues This enhances the cache clearing implementation that was added in PR #39 to help prevent legacy cache issues and stale data problems. * continuing on base_classes - added baseball and api extractor since we don't use ESPN api for all sports * tests * fix missing duration * ensure milb, mlb, ncaa bb are all using new baseball base class properly * cursor rule to help with PR creation * fix image call * fix _scoreboard suffix on milb, MLB
This commit is contained in:
165
src/base_classes/baseball.py
Normal file
165
src/base_classes/baseball.py
Normal file
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
Baseball Base Classes
|
||||
|
||||
This module provides baseball-specific base classes that extend the core sports functionality
|
||||
with baseball-specific logic for innings, outs, bases, strikes, balls, etc.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional, List
|
||||
from src.base_classes.sports import SportsCore
|
||||
from src.base_classes.api_extractors import ESPNBaseballExtractor
|
||||
from src.base_classes.data_sources import ESPNDataSource, MLBAPIDataSource
|
||||
import logging
|
||||
|
||||
class Baseball(SportsCore):
|
||||
"""Base class for baseball sports with common functionality."""
|
||||
|
||||
# Baseball sport configuration (moved from sport_configs.py)
|
||||
SPORT_CONFIG = {
|
||||
'update_cadence': 'daily',
|
||||
'season_length': 162,
|
||||
'games_per_week': 6,
|
||||
'api_endpoints': ['scoreboard', 'standings', 'stats'],
|
||||
'sport_specific_fields': ['inning', 'outs', 'bases', 'strikes', 'balls', 'pitcher', 'batter'],
|
||||
'update_interval_seconds': 30,
|
||||
'logo_dir': 'assets/sports/mlb_logos',
|
||||
'show_records': True,
|
||||
'show_ranking': True,
|
||||
'show_odds': True,
|
||||
'data_source_type': 'espn', # Can be overridden for MLB API
|
||||
'api_base_url': 'https://site.api.espn.com/apis/site/v2/sports/baseball'
|
||||
}
|
||||
|
||||
def __init__(self, config: Dict[str, Any], display_manager, cache_manager, logger: logging.Logger, sport_key: str):
|
||||
super().__init__(config, display_manager, cache_manager, logger, sport_key)
|
||||
|
||||
# Initialize baseball-specific architecture components
|
||||
self.sport_config = self.get_sport_config()
|
||||
self.api_extractor = ESPNBaseballExtractor(logger)
|
||||
|
||||
# Choose data source based on sport (MLB uses MLB API, others use ESPN)
|
||||
if sport_key == 'mlb':
|
||||
self.data_source = MLBAPIDataSource(logger)
|
||||
else:
|
||||
self.data_source = ESPNDataSource(logger)
|
||||
|
||||
# Baseball-specific configuration
|
||||
self.show_innings = self.mode_config.get("show_innings", True)
|
||||
self.show_outs = self.mode_config.get("show_outs", True)
|
||||
self.show_bases = self.mode_config.get("show_bases", True)
|
||||
self.show_count = self.mode_config.get("show_count", True)
|
||||
self.show_pitcher_batter = self.mode_config.get("show_pitcher_batter", False)
|
||||
|
||||
def get_sport_config(self) -> Dict[str, Any]:
|
||||
"""Get baseball sport configuration."""
|
||||
return self.SPORT_CONFIG.copy()
|
||||
|
||||
def _get_baseball_display_text(self, game: Dict) -> str:
|
||||
"""Get baseball-specific display text."""
|
||||
try:
|
||||
display_parts = []
|
||||
|
||||
# Inning information
|
||||
if self.show_innings:
|
||||
inning = game.get('inning', '')
|
||||
if inning:
|
||||
display_parts.append(f"Inning: {inning}")
|
||||
|
||||
# Outs information
|
||||
if self.show_outs:
|
||||
outs = game.get('outs', 0)
|
||||
if outs is not None:
|
||||
display_parts.append(f"Outs: {outs}")
|
||||
|
||||
# Bases information
|
||||
if self.show_bases:
|
||||
bases = game.get('bases', '')
|
||||
if bases:
|
||||
display_parts.append(f"Bases: {bases}")
|
||||
|
||||
# Count information
|
||||
if self.show_count:
|
||||
strikes = game.get('strikes', 0)
|
||||
balls = game.get('balls', 0)
|
||||
if strikes is not None and balls is not None:
|
||||
display_parts.append(f"Count: {balls}-{strikes}")
|
||||
|
||||
# Pitcher/Batter information
|
||||
if self.show_pitcher_batter:
|
||||
pitcher = game.get('pitcher', '')
|
||||
batter = game.get('batter', '')
|
||||
if pitcher:
|
||||
display_parts.append(f"Pitcher: {pitcher}")
|
||||
if batter:
|
||||
display_parts.append(f"Batter: {batter}")
|
||||
|
||||
return " | ".join(display_parts) if display_parts else ""
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting baseball display text: {e}")
|
||||
return ""
|
||||
|
||||
def _is_baseball_game_live(self, game: Dict) -> bool:
|
||||
"""Check if a baseball game is currently live."""
|
||||
try:
|
||||
# Check if game is marked as live
|
||||
is_live = game.get('is_live', False)
|
||||
if is_live:
|
||||
return True
|
||||
|
||||
# Check inning to determine if game is active
|
||||
inning = game.get('inning', '')
|
||||
if inning and inning != 'Final':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error checking if baseball game is live: {e}")
|
||||
return False
|
||||
|
||||
def _get_baseball_game_status(self, game: Dict) -> str:
|
||||
"""Get baseball-specific game status."""
|
||||
try:
|
||||
status = game.get('status_text', '')
|
||||
inning = game.get('inning', '')
|
||||
|
||||
if self._is_baseball_game_live(game):
|
||||
if inning:
|
||||
return f"Live - {inning}"
|
||||
else:
|
||||
return "Live"
|
||||
elif game.get('is_final', False):
|
||||
return "Final"
|
||||
elif game.get('is_upcoming', False):
|
||||
return "Upcoming"
|
||||
else:
|
||||
return status
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting baseball game status: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
class BaseballLive(Baseball):
|
||||
"""Base class for live baseball games."""
|
||||
|
||||
def __init__(self, config: Dict[str, Any], display_manager, cache_manager, logger: logging.Logger, sport_key: str):
|
||||
super().__init__(config, display_manager, cache_manager, logger, sport_key)
|
||||
self.logger.info(f"{sport_key.upper()} Live Manager initialized")
|
||||
|
||||
def _should_show_baseball_game(self, game: Dict) -> bool:
|
||||
"""Determine if a baseball game should be shown."""
|
||||
try:
|
||||
# Only show live games
|
||||
if not self._is_baseball_game_live(game):
|
||||
return False
|
||||
|
||||
# Check if game meets display criteria
|
||||
return self._should_show_game(game)
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error checking if baseball game should be shown: {e}")
|
||||
return False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user