From b4d5aef876c391e7d39a71c0efbcf9b013103a7f Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Sat, 9 Aug 2025 10:44:58 -0500 Subject: [PATCH] milb logging and manual cache clearing --- clear_cache.py | 131 ++++++++++++++++++++++++++++++++++++++ src/display_controller.py | 8 ++- src/milb_manager.py | 24 +++++++ src/soccer_managers.py | 6 ++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 clear_cache.py diff --git a/clear_cache.py b/clear_cache.py new file mode 100644 index 00000000..1c959b67 --- /dev/null +++ b/clear_cache.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +""" +Cache clearing utility for LEDMatrix +This script allows manual clearing of specific cache keys or all cache data. +""" + +import os +import sys +import json +import argparse +from pathlib import Path + +# Add the src directory to the path so we can import our modules +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) + +from cache_manager import CacheManager + +def list_cache_keys(cache_dir): + """List all available cache keys.""" + if not os.path.exists(cache_dir): + print(f"Cache directory does not exist: {cache_dir}") + return [] + + cache_files = [] + for file in os.listdir(cache_dir): + if file.endswith('.json'): + cache_files.append(file[:-5]) # Remove .json extension + + return cache_files + +def clear_specific_cache(cache_manager, key): + """Clear a specific cache key.""" + try: + cache_manager.clear_cache(key) + print(f"✓ Cleared cache key: {key}") + return True + except Exception as e: + print(f"✗ Error clearing cache key '{key}': {e}") + return False + +def clear_all_cache(cache_manager): + """Clear all cache data.""" + try: + cache_manager.clear_cache() + print("✓ Cleared all cache data") + return True + except Exception as e: + print(f"✗ Error clearing all cache: {e}") + return False + +def show_cache_info(cache_manager, key=None): + """Show information about cache entries.""" + if key: + try: + data = cache_manager.get(key) + if data is not None: + print(f"Cache key '{key}' exists with data type: {type(data)}") + if isinstance(data, dict): + print(f" Keys: {list(data.keys())}") + if 'games' in data: + print(f" Number of games: {len(data['games']) if isinstance(data['games'], dict) else 'N/A'}") + elif isinstance(data, list): + print(f" Number of items: {len(data)}") + else: + print(f" Data: {str(data)[:100]}...") + else: + print(f"Cache key '{key}' does not exist or is expired") + except Exception as e: + print(f"Error checking cache key '{key}': {e}") + else: + # Show all cache keys + cache_dir = cache_manager.cache_dir + keys = list_cache_keys(cache_dir) + if keys: + print("Available cache keys:") + for key in sorted(keys): + print(f" - {key}") + else: + print("No cache keys found") + +def main(): + parser = argparse.ArgumentParser(description='Clear LEDMatrix cache data') + parser.add_argument('--list', '-l', action='store_true', + help='List all available cache keys') + parser.add_argument('--clear-all', '-a', action='store_true', + help='Clear all cache data') + parser.add_argument('--clear', '-c', type=str, metavar='KEY', + help='Clear a specific cache key') + parser.add_argument('--info', '-i', type=str, metavar='KEY', + help='Show information about a specific cache key') + parser.add_argument('--cache-dir', type=str, default='cache', + help='Cache directory path (default: cache)') + + args = parser.parse_args() + + # Initialize cache manager + cache_manager = CacheManager(cache_dir=args.cache_dir) + + if args.list: + show_cache_info(cache_manager) + elif args.clear_all: + print("Clearing all cache data...") + clear_all_cache(cache_manager) + elif args.clear: + print(f"Clearing cache key: {args.clear}") + clear_specific_cache(cache_manager, args.clear) + elif args.info: + show_cache_info(cache_manager, args.info) + else: + # Default: show available options + print("LEDMatrix Cache Utility") + print("=" * 30) + print() + print("Available commands:") + print(" --list, -l List all cache keys") + print(" --clear-all, -a Clear all cache data") + print(" --clear KEY, -c Clear specific cache key") + print(" --info KEY, -i Show info about cache key") + print() + print("Examples:") + print(" python clear_cache.py --list") + print(" python clear_cache.py --clear milb_live_api_data") + print(" python clear_cache.py --clear-all") + print(" python clear_cache.py --info milb_upcoming_api_data") + print() + + # Show current cache status + show_cache_info(cache_manager) + +if __name__ == "__main__": + main() diff --git a/src/display_controller.py b/src/display_controller.py index 6a8cbd19..2a2b98b4 100644 --- a/src/display_controller.py +++ b/src/display_controller.py @@ -1104,7 +1104,13 @@ class DisplayController: logger.debug(f"[DisplayController] Calling MiLB live display with {len(self.milb_live.live_games)} live games") self.milb_live.display(force_clear=self.force_clear) elif self.current_display_mode == 'milb_live' and self.milb_live: - logger.debug(f"[DisplayController] MiLB live manager exists but has {len(self.milb_live.live_games)} live games, skipping display") + logger.debug(f"[DisplayController] MiLB live manager exists but has {len(self.milb_live.live_games)} live games, switching to next mode") + # Switch to next mode since there are no live games + self.current_mode_index = (self.current_mode_index + 1) % len(self.available_modes) + self.current_display_mode = self.available_modes[self.current_mode_index] + self.force_clear = True + self.last_switch = current_time + logger.info(f"[DisplayController] Switched from milb_live (no games) to {self.current_display_mode}") 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: diff --git a/src/milb_manager.py b/src/milb_manager.py index 3f974062..3909ba40 100644 --- a/src/milb_manager.py +++ b/src/milb_manager.py @@ -534,6 +534,9 @@ class BaseMiLBManager: if not self.favorite_teams or is_favorite_game: status_obj = game['status'] status_state = status_obj.get('abstractGameState', 'Final') + + # Debug: Log the original status information + self.logger.debug(f"[MiLB] Status mapping for {away_abbr} @ {home_abbr}: original abstractGameState='{status_state}', full status_obj={status_obj}") mapped_status = 'unknown' mapped_status_state = 'unknown' @@ -737,8 +740,29 @@ class MiLBLiveManager(BaseMiLBManager): # Find all live games involving favorite teams new_live_games = [] for game in games.values(): + # Debug: Log the status for all games to understand what's happening + self.logger.debug(f"[MiLB] Game status check: {game['away_team']} @ {game['home_team']} - status_state='{game['status_state']}', status='{game['status']}', abstractGameState='{game.get('abstractGameState', 'N/A')}'") + # Only process games that are actually in progress if game['status_state'] == 'in' and game['status'] == 'status_in_progress': + # Additional check: Verify the game is from today or very recent + game_date_str = game.get('start_time', '') + if game_date_str: + try: + # Parse the game date (assuming it's in ISO format) + game_date = datetime.fromisoformat(game_date_str.replace('Z', '+00:00')) + current_utc = datetime.now(timezone.utc) + hours_diff = (current_utc - game_date).total_seconds() / 3600 + + # If game is more than 6 hours old, it's probably not actually live + if hours_diff > 6: + self.logger.warning(f"[MiLB] Skipping potentially stale live game: {game['away_team']} @ {game['home_team']} - game date: {game_date_str}, hours old: {hours_diff:.1f}") + continue + else: + self.logger.debug(f"[MiLB] Game time check passed: {game['away_team']} @ {game['home_team']} - hours old: {hours_diff:.1f}") + except Exception as e: + self.logger.warning(f"[MiLB] Could not parse game date {game_date_str}: {e}") + self.logger.debug(f"[MiLB] Found live game: {game['away_team']} @ {game['home_team']}") if not self.favorite_teams or ( game['home_team'] in self.favorite_teams or diff --git a/src/soccer_managers.py b/src/soccer_managers.py index 3f190634..4f55b108 100644 --- a/src/soccer_managers.py +++ b/src/soccer_managers.py @@ -97,6 +97,12 @@ class BaseSoccerManager: self.config_manager = ConfigManager(config) + def _get_timezone(self): + try: + return pytz.timezone(self.config_manager.get_timezone()) + except pytz.UnknownTimeZoneError: + return pytz.utc + def _fetch_odds(self, game: Dict) -> None: """Fetch odds for a game and attach it to the game dictionary.""" # Check if odds should be shown for this sport