seach logic will search for each team in a smarter search loop

This commit is contained in:
Chuck
2025-07-21 18:07:04 -05:00
parent e21bf2b3dd
commit e611715d54
4 changed files with 119 additions and 30 deletions

View File

@@ -177,7 +177,7 @@
"live_odds_update_interval": 3600, "live_odds_update_interval": 3600,
"odds_update_interval": 3600, "odds_update_interval": 3600,
"fetch_past_games": 1, "fetch_past_games": 1,
"fetch_future_games": 1, "fetch_future_games": 5,
"favorite_teams": ["TB", "DAL"], "favorite_teams": ["TB", "DAL"],
"logo_dir": "assets/sports/nfl_logos", "logo_dir": "assets/sports/nfl_logos",
"show_records": true, "show_records": true,
@@ -196,7 +196,7 @@
"live_odds_update_interval": 3600, "live_odds_update_interval": 3600,
"odds_update_interval": 3600, "odds_update_interval": 3600,
"fetch_past_games": 1, "fetch_past_games": 1,
"fetch_future_games": 1, "fetch_future_games": 5,
"favorite_teams": ["UGA", "AUB"], "favorite_teams": ["UGA", "AUB"],
"logo_dir": "assets/sports/ncaa_fbs_logos", "logo_dir": "assets/sports/ncaa_fbs_logos",
"show_records": true, "show_records": true,

View File

@@ -370,22 +370,16 @@ class BaseNBAManager:
"""Fetch odds for a specific game if conditions are met.""" """Fetch odds for a specific game if conditions are met."""
self.logger.debug(f"Checking odds for game: {game.get('id', 'N/A')}") self.logger.debug(f"Checking odds for game: {game.get('id', 'N/A')}")
# Ensure the API key is set in the secrets config
if not self.config_manager.get_secret("the_odds_api_key"):
if self._should_log('no_api_key', cooldown=3600): # Log once per hour
self.logger.warning("Odds API key not found. Skipping odds fetch.")
return
# Check if odds should be shown for this sport # Check if odds should be shown for this sport
if not self.show_odds: if not self.show_odds:
self.logger.debug("Odds display is disabled for NBA.") self.logger.debug("Odds display is disabled for NBA.")
return return
# Fetch odds using OddsManager # Fetch odds using OddsManager (ESPN API)
try: try:
# Determine update interval based on game state # Determine update interval based on game state
is_live = game.get('is_live', False) is_live = game.get('status', '').lower() == 'in'
update_interval = self.nba_config.get("live_odds_update_interval", 3600) if is_live \ update_interval = self.nba_config.get("live_odds_update_interval", 60) if is_live \
else self.nba_config.get("odds_update_interval", 3600) else self.nba_config.get("odds_update_interval", 3600)
odds_data = self.odds_manager.get_odds( odds_data = self.odds_manager.get_odds(

View File

@@ -132,22 +132,24 @@ class BaseNCAAFBManager: # Renamed class
except pytz.UnknownTimeZoneError: except pytz.UnknownTimeZoneError:
return pytz.utc return pytz.utc
def _should_log(self, warning_type: str, cooldown: int = 60) -> bool:
"""Check if we should log a warning based on cooldown period."""
current_time = time.time()
if current_time - self._last_warning_time > cooldown:
self._last_warning_time = current_time
return True
return False
def _fetch_odds(self, game: Dict) -> None: def _fetch_odds(self, game: Dict) -> None:
"""Fetch odds for a specific game if conditions are met.""" """Fetch odds for a specific game if conditions are met."""
self.logger.debug(f"Checking odds for game: {game.get('id', 'N/A')}") self.logger.debug(f"Checking odds for game: {game.get('id', 'N/A')}")
# Ensure the API key is set in the secrets config
if not self.config_manager.get_secret("the_odds_api_key"):
if self._should_log('no_api_key', cooldown=3600): # Log once per hour
self.logger.warning("Odds API key not found. Skipping odds fetch.")
return
# Check if odds should be shown for this sport # Check if odds should be shown for this sport
if not self.show_odds: if not self.show_odds:
self.logger.debug("Odds display is disabled for NCAAFB.") self.logger.debug("Odds display is disabled for NCAAFB.")
return return
# Fetch odds using OddsManager # Fetch odds using OddsManager (ESPN API)
try: try:
# Determine update interval based on game state # Determine update interval based on game state
is_live = game.get('status', '').lower() == 'in' is_live = game.get('status', '').lower() == 'in'
@@ -156,7 +158,7 @@ class BaseNCAAFBManager: # Renamed class
odds_data = self.odds_manager.get_odds( odds_data = self.odds_manager.get_odds(
sport="football", sport="football",
league="college-football", league="ncaa_fb",
event_id=game['id'], event_id=game['id'],
update_interval_seconds=update_interval update_interval_seconds=update_interval
) )
@@ -198,6 +200,15 @@ class BaseNCAAFBManager: # Renamed class
actual_past_games = fetch_past_games if need_past_games else 0 actual_past_games = fetch_past_games if need_past_games else 0
actual_future_games = fetch_future_games if need_future_games else 0 actual_future_games = fetch_future_games if need_future_games else 0
# For upcoming games, we need to find games for each favorite team
if need_future_games and self.favorite_teams:
# Calculate how many games we need to find for favorite teams
games_needed_per_team = actual_future_games
total_favorite_games_needed = len(self.favorite_teams) * games_needed_per_team
BaseNCAAFBManager.logger.info(f"[NCAAFB] Need to find {games_needed_per_team} games for each of {len(self.favorite_teams)} favorite teams ({total_favorite_games_needed} total)")
else:
total_favorite_games_needed = actual_future_games
BaseNCAAFBManager.logger.info(f"[NCAAFB] Fetching data - Past games: {actual_past_games}, Future games: {actual_future_games}") BaseNCAAFBManager.logger.info(f"[NCAAFB] Fetching data - Past games: {actual_past_games}, Future games: {actual_future_games}")
# Smart game-based fetching with range caching # Smart game-based fetching with range caching
@@ -206,6 +217,9 @@ class BaseNCAAFBManager: # Renamed class
past_events = [] past_events = []
future_events = [] future_events = []
# Track games found for each favorite team
favorite_team_games = {team: [] for team in self.favorite_teams} if self.favorite_teams else {}
# Check for cached search ranges # Check for cached search ranges
range_cache_key = f"search_ranges_ncaafb_{actual_past_games}_{actual_future_games}" range_cache_key = f"search_ranges_ncaafb_{actual_past_games}_{actual_future_games}"
cached_ranges = BaseNCAAFBManager.cache_manager.get(range_cache_key, max_age=86400) # Cache for 24 hours cached_ranges = BaseNCAAFBManager.cache_manager.get(range_cache_key, max_age=86400) # Cache for 24 hours
@@ -222,7 +236,9 @@ class BaseNCAAFBManager: # Renamed class
days_to_check = max(past_days_needed, future_days_needed) days_to_check = max(past_days_needed, future_days_needed)
max_days_to_check = 365 # Limit to 1 year to prevent infinite loops max_days_to_check = 365 # Limit to 1 year to prevent infinite loops
while (len(past_events) < actual_past_games or len(future_events) < actual_future_games) and days_to_check <= max_days_to_check: while (len(past_events) < actual_past_games or
(need_future_games and self.favorite_teams and
not all(len(games) >= actual_future_games for games in favorite_team_games.values()))) and days_to_check <= max_days_to_check:
# Check dates in both directions # Check dates in both directions
dates_to_check = [] dates_to_check = []
@@ -290,6 +306,24 @@ class BaseNCAAFBManager: # Renamed class
past_events.append(event) past_events.append(event)
else: else:
future_events.append(event) future_events.append(event)
# Track games for favorite teams
if self.favorite_teams and need_future_games:
competition = event.get('competitions', [{}])[0]
competitors = competition.get('competitors', [])
home_team = next((c for c in competitors if c.get('homeAway') == 'home'), None)
away_team = next((c for c in competitors if c.get('homeAway') == 'away'), None)
if home_team and away_team:
home_abbr = home_team['team']['abbreviation']
away_abbr = away_team['team']['abbreviation']
# Check if this game involves a favorite team
for team in self.favorite_teams:
if team in [home_abbr, away_abbr]:
if len(favorite_team_games[team]) < actual_future_games:
favorite_team_games[team].append(event)
BaseNCAAFBManager.logger.debug(f"[NCAAFB] Found game for {team}: {away_abbr}@{home_abbr}")
except Exception as e: except Exception as e:
BaseNCAAFBManager.logger.warning(f"[NCAAFB] Could not parse event date: {e}") BaseNCAAFBManager.logger.warning(f"[NCAAFB] Could not parse event date: {e}")
continue continue
@@ -313,7 +347,17 @@ class BaseNCAAFBManager: # Renamed class
# Take the specified number of games # Take the specified number of games
selected_past_events = past_events[-actual_past_games:] if past_events else [] selected_past_events = past_events[-actual_past_games:] if past_events else []
selected_future_events = future_events[:actual_future_games] if future_events else []
# For future games, use favorite team games if available
if self.favorite_teams and need_future_games:
selected_future_events = []
for team in self.favorite_teams:
team_games = favorite_team_games.get(team, [])
selected_future_events.extend(team_games[:actual_future_games])
BaseNCAAFBManager.logger.info(f"[NCAAFB] Selected {len(selected_past_events)} past games and {len(selected_future_events)} favorite team future games")
else:
selected_future_events = future_events[:actual_future_games] if future_events else []
BaseNCAAFBManager.logger.info(f"[NCAAFB] Selected {len(selected_past_events)} past games and {len(selected_future_events)} future games after checking {days_to_check} days")
# Combine selected events # Combine selected events
selected_events = selected_past_events + selected_future_events selected_events = selected_past_events + selected_future_events
@@ -1229,6 +1273,13 @@ class NCAAFBUpcomingManager(BaseNCAAFBManager): # Renamed class
for game in processed_games: for game in processed_games:
self.logger.debug(f"[NCAAFB Upcoming] Game: {game['away_abbr']}@{game['home_abbr']} - Upcoming: {game['is_upcoming']}") self.logger.debug(f"[NCAAFB Upcoming] Game: {game['away_abbr']}@{game['home_abbr']} - Upcoming: {game['is_upcoming']}")
# Log all unique teams found for debugging
all_teams = set()
for game in processed_games:
all_teams.add(game['away_abbr'])
all_teams.add(game['home_abbr'])
self.logger.debug(f"[NCAAFB Upcoming] All teams found in API: {sorted(all_teams)}")
# Filter for favorite teams # Filter for favorite teams
if self.favorite_teams: if self.favorite_teams:
team_games = [game for game in processed_games team_games = [game for game in processed_games

View File

@@ -132,22 +132,24 @@ class BaseNFLManager: # Renamed class
except pytz.UnknownTimeZoneError: except pytz.UnknownTimeZoneError:
return pytz.utc return pytz.utc
def _should_log(self, warning_type: str, cooldown: int = 60) -> bool:
"""Check if we should log a warning based on cooldown period."""
current_time = time.time()
if current_time - self._last_warning_time > cooldown:
self._last_warning_time = current_time
return True
return False
def _fetch_odds(self, game: Dict) -> None: def _fetch_odds(self, game: Dict) -> None:
"""Fetch odds for a specific game if conditions are met.""" """Fetch odds for a specific game if conditions are met."""
self.logger.debug(f"Checking odds for game: {game.get('id', 'N/A')}") self.logger.debug(f"Checking odds for game: {game.get('id', 'N/A')}")
# Ensure the API key is set in the secrets config
if not self.config_manager.get_secret("the_odds_api_key"):
if self._should_log('no_api_key', cooldown=3600): # Log once per hour
self.logger.warning("Odds API key not found. Skipping odds fetch.")
return
# Check if odds should be shown for this sport # Check if odds should be shown for this sport
if not self.show_odds: if not self.show_odds:
self.logger.debug("Odds display is disabled for NFL.") self.logger.debug("Odds display is disabled for NFL.")
return return
# Fetch odds using OddsManager # Fetch odds using OddsManager (ESPN API)
try: try:
# Determine update interval based on game state # Determine update interval based on game state
is_live = game.get('status', '').lower() == 'in' is_live = game.get('status', '').lower() == 'in'
@@ -198,6 +200,15 @@ class BaseNFLManager: # Renamed class
actual_past_games = fetch_past_games if need_past_games else 0 actual_past_games = fetch_past_games if need_past_games else 0
actual_future_games = fetch_future_games if need_future_games else 0 actual_future_games = fetch_future_games if need_future_games else 0
# For upcoming games, we need to find games for each favorite team
if need_future_games and self.favorite_teams:
# Calculate how many games we need to find for favorite teams
games_needed_per_team = actual_future_games
total_favorite_games_needed = len(self.favorite_teams) * games_needed_per_team
BaseNFLManager.logger.info(f"[NFL] Need to find {games_needed_per_team} games for each of {len(self.favorite_teams)} favorite teams ({total_favorite_games_needed} total)")
else:
total_favorite_games_needed = actual_future_games
BaseNFLManager.logger.info(f"[NFL] Fetching data - Past games: {actual_past_games}, Future games: {actual_future_games}") BaseNFLManager.logger.info(f"[NFL] Fetching data - Past games: {actual_past_games}, Future games: {actual_future_games}")
# Smart game-based fetching with range caching # Smart game-based fetching with range caching
@@ -206,6 +217,9 @@ class BaseNFLManager: # Renamed class
past_events = [] past_events = []
future_events = [] future_events = []
# Track games found for each favorite team
favorite_team_games = {team: [] for team in self.favorite_teams} if self.favorite_teams else {}
# Check for cached search ranges # Check for cached search ranges
range_cache_key = f"search_ranges_nfl_{actual_past_games}_{actual_future_games}" range_cache_key = f"search_ranges_nfl_{actual_past_games}_{actual_future_games}"
cached_ranges = BaseNFLManager.cache_manager.get(range_cache_key, max_age=86400) # Cache for 24 hours cached_ranges = BaseNFLManager.cache_manager.get(range_cache_key, max_age=86400) # Cache for 24 hours
@@ -222,7 +236,9 @@ class BaseNFLManager: # Renamed class
days_to_check = max(past_days_needed, future_days_needed) days_to_check = max(past_days_needed, future_days_needed)
max_days_to_check = 365 # Limit to 1 year to prevent infinite loops max_days_to_check = 365 # Limit to 1 year to prevent infinite loops
while (len(past_events) < actual_past_games or len(future_events) < actual_future_games) and days_to_check <= max_days_to_check: while (len(past_events) < actual_past_games or
(need_future_games and self.favorite_teams and
not all(len(games) >= actual_future_games for games in favorite_team_games.values()))) and days_to_check <= max_days_to_check:
# Check dates in both directions # Check dates in both directions
dates_to_check = [] dates_to_check = []
@@ -290,6 +306,24 @@ class BaseNFLManager: # Renamed class
past_events.append(event) past_events.append(event)
else: else:
future_events.append(event) future_events.append(event)
# Track games for favorite teams
if self.favorite_teams and need_future_games:
competition = event.get('competitions', [{}])[0]
competitors = competition.get('competitors', [])
home_team = next((c for c in competitors if c.get('homeAway') == 'home'), None)
away_team = next((c for c in competitors if c.get('homeAway') == 'away'), None)
if home_team and away_team:
home_abbr = home_team['team']['abbreviation']
away_abbr = away_team['team']['abbreviation']
# Check if this game involves a favorite team
for team in self.favorite_teams:
if team in [home_abbr, away_abbr]:
if len(favorite_team_games[team]) < actual_future_games:
favorite_team_games[team].append(event)
BaseNFLManager.logger.debug(f"[NFL] Found game for {team}: {away_abbr}@{home_abbr}")
except Exception as e: except Exception as e:
BaseNFLManager.logger.warning(f"[NFL] Could not parse event date: {e}") BaseNFLManager.logger.warning(f"[NFL] Could not parse event date: {e}")
continue continue
@@ -313,7 +347,17 @@ class BaseNFLManager: # Renamed class
# Take the specified number of games # Take the specified number of games
selected_past_events = past_events[-actual_past_games:] if past_events else [] selected_past_events = past_events[-actual_past_games:] if past_events else []
selected_future_events = future_events[:actual_future_games] if future_events else []
# For future games, use favorite team games if available
if self.favorite_teams and need_future_games:
selected_future_events = []
for team in self.favorite_teams:
team_games = favorite_team_games.get(team, [])
selected_future_events.extend(team_games[:actual_future_games])
BaseNFLManager.logger.info(f"[NFL] Selected {len(selected_past_events)} past games and {len(selected_future_events)} favorite team future games")
else:
selected_future_events = future_events[:actual_future_games] if future_events else []
BaseNFLManager.logger.info(f"[NFL] Selected {len(selected_past_events)} past games and {len(selected_future_events)} future games after checking {days_to_check} days")
# Combine selected events # Combine selected events
selected_events = selected_past_events + selected_future_events selected_events = selected_past_events + selected_future_events