mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-12 21:43:00 +00:00
Create Basketball Base Class and Consolidate Basketball Managers (#97)
* Create basketball Base class * Migrate NBA * Add NCAA Mens Basketball * Add NCAA Women's Basketball * Add WNBA --------- Co-authored-by: Alex Resnick <adr8282@gmail.com>
This commit is contained in:
0
assets/sports/wnba_logos/.keep
Normal file
0
assets/sports/wnba_logos/.keep
Normal file
BIN
assets/sports/wnba_logos/LV.png
Normal file
BIN
assets/sports/wnba_logos/LV.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
assets/sports/wnba_logos/PHX.png
Normal file
BIN
assets/sports/wnba_logos/PHX.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@@ -267,6 +267,7 @@
|
|||||||
"recent_games_to_show": 1,
|
"recent_games_to_show": 1,
|
||||||
"upcoming_games_to_show": 1,
|
"upcoming_games_to_show": 1,
|
||||||
"show_favorite_teams_only": true,
|
"show_favorite_teams_only": true,
|
||||||
|
"show_all_live": false,
|
||||||
"favorite_teams": [
|
"favorite_teams": [
|
||||||
"DAL"
|
"DAL"
|
||||||
],
|
],
|
||||||
@@ -285,6 +286,40 @@
|
|||||||
"nba_upcoming": true
|
"nba_upcoming": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wnba_scoreboard": {
|
||||||
|
"enabled": false,
|
||||||
|
"live_priority": true,
|
||||||
|
"live_game_duration": 20,
|
||||||
|
"show_odds": true,
|
||||||
|
"test_mode": false,
|
||||||
|
"update_interval_seconds": 3600,
|
||||||
|
"live_update_interval": 30,
|
||||||
|
"live_odds_update_interval": 3600,
|
||||||
|
"odds_update_interval": 3600,
|
||||||
|
"recent_update_interval": 3600,
|
||||||
|
"upcoming_update_interval": 3600,
|
||||||
|
"recent_games_to_show": 1,
|
||||||
|
"upcoming_games_to_show": 1,
|
||||||
|
"show_favorite_teams_only": true,
|
||||||
|
"show_all_live": false,
|
||||||
|
"favorite_teams": [
|
||||||
|
"CHI"
|
||||||
|
],
|
||||||
|
"logo_dir": "assets/sports/wnba_logos",
|
||||||
|
"show_records": true,
|
||||||
|
"background_service": {
|
||||||
|
"enabled": true,
|
||||||
|
"max_workers": 3,
|
||||||
|
"request_timeout": 30,
|
||||||
|
"max_retries": 3,
|
||||||
|
"priority": 2
|
||||||
|
},
|
||||||
|
"display_modes": {
|
||||||
|
"wnba_live": true,
|
||||||
|
"wnba_recent": true,
|
||||||
|
"wnba_upcoming": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"nfl_scoreboard": {
|
"nfl_scoreboard": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"live_priority": true,
|
"live_priority": true,
|
||||||
@@ -388,6 +423,7 @@
|
|||||||
"recent_games_to_show": 1,
|
"recent_games_to_show": 1,
|
||||||
"upcoming_games_to_show": 1,
|
"upcoming_games_to_show": 1,
|
||||||
"show_favorite_teams_only": true,
|
"show_favorite_teams_only": true,
|
||||||
|
"show_all_live": false,
|
||||||
"favorite_teams": [
|
"favorite_teams": [
|
||||||
"UGA",
|
"UGA",
|
||||||
"AUB"
|
"AUB"
|
||||||
@@ -400,6 +436,30 @@
|
|||||||
"ncaam_basketball_upcoming": true
|
"ncaam_basketball_upcoming": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ncaaw_basketball_scoreboard": {
|
||||||
|
"enabled": false,
|
||||||
|
"live_priority": true,
|
||||||
|
"live_game_duration": 20,
|
||||||
|
"show_odds": true,
|
||||||
|
"test_mode": false,
|
||||||
|
"update_interval_seconds": 3600,
|
||||||
|
"live_update_interval": 30,
|
||||||
|
"recent_games_to_show": 1,
|
||||||
|
"upcoming_games_to_show": 1,
|
||||||
|
"show_favorite_teams_only": true,
|
||||||
|
"show_all_live": false,
|
||||||
|
"favorite_teams": [
|
||||||
|
"UGA",
|
||||||
|
"AUB"
|
||||||
|
],
|
||||||
|
"logo_dir": "assets/sports/ncaa_logos",
|
||||||
|
"show_records": true,
|
||||||
|
"display_modes": {
|
||||||
|
"ncaaw_basketball_live": true,
|
||||||
|
"ncaaw_basketball_recent": true,
|
||||||
|
"ncaaw_basketball_upcoming": true
|
||||||
|
}
|
||||||
|
},
|
||||||
"ncaam_hockey_scoreboard": {
|
"ncaam_hockey_scoreboard": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"live_priority": true,
|
"live_priority": true,
|
||||||
|
|||||||
309
src/base_classes/basketball.py
Normal file
309
src/base_classes/basketball.py
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
from src.base_classes.data_sources import ESPNDataSource
|
||||||
|
from src.base_classes.sports import SportsCore, SportsLive
|
||||||
|
from src.cache_manager import CacheManager
|
||||||
|
from src.display_manager import DisplayManager
|
||||||
|
|
||||||
|
|
||||||
|
class Basketball(SportsCore):
|
||||||
|
"""Base class for basketball sports with common functionality."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
logger: logging.Logger,
|
||||||
|
sport_key: str,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager, logger, sport_key)
|
||||||
|
self.data_source = ESPNDataSource(logger)
|
||||||
|
self.sport = "basketball"
|
||||||
|
|
||||||
|
def _extract_game_details(self, game_event: Dict) -> Optional[Dict]:
|
||||||
|
"""Extract relevant game details from ESPN NCAA FB API response."""
|
||||||
|
# --- THIS METHOD MAY NEED ADJUSTMENTS FOR NCAA FB API DIFFERENCES ---
|
||||||
|
details, home_team, away_team, status, situation = (
|
||||||
|
self._extract_game_details_common(game_event)
|
||||||
|
)
|
||||||
|
if details is None or home_team is None or away_team is None or status is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
# Format period/quarter
|
||||||
|
period = status.get("period", 0)
|
||||||
|
period_text = ""
|
||||||
|
if status["type"]["state"] == "in":
|
||||||
|
if period == 0:
|
||||||
|
period_text = "Start" # Before kickoff
|
||||||
|
elif period >= 1 and period <= 4:
|
||||||
|
period_text = f"Q{period}" # OT starts after Q4
|
||||||
|
elif period > 4:
|
||||||
|
period_text = f"OT{period - 4}" # OT starts after Q4
|
||||||
|
elif status["type"]["state"] == "halftime" or status["type"]["name"] == "STATUS_HALFTIME": # Check explicit halftime state
|
||||||
|
period_text = "HALF"
|
||||||
|
elif status["type"]["state"] == "post":
|
||||||
|
if period > 4 : period_text = "Final/OT"
|
||||||
|
else: period_text = "Final"
|
||||||
|
elif status["type"]["state"] == "pre":
|
||||||
|
period_text = details.get("game_time", "") # Show time for upcoming
|
||||||
|
|
||||||
|
details.update({
|
||||||
|
"period": period,
|
||||||
|
"period_text": period_text, # Formatted quarter/status
|
||||||
|
"clock": status.get("displayClock", "0:00"),
|
||||||
|
})
|
||||||
|
|
||||||
|
# Basic validation (can be expanded)
|
||||||
|
if not details["home_abbr"] or not details["away_abbr"]:
|
||||||
|
self.logger.warning(
|
||||||
|
f"Missing team abbreviation in event: {details['id']}"
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.logger.debug(
|
||||||
|
f"Extracted: {details['away_abbr']}@{details['home_abbr']}, Status: {status['type']['name']}, Live: {details['is_live']}, Final: {details['is_final']}, Upcoming: {details['is_upcoming']}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return details
|
||||||
|
except Exception as e:
|
||||||
|
# Log the problematic event structure if possible
|
||||||
|
self.logger.error(
|
||||||
|
f"Error extracting game details: {e} from event: {game_event.get('id')}",
|
||||||
|
exc_info=True,
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class BasketballLive(Basketball, SportsLive):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
logger: logging.Logger,
|
||||||
|
sport_key: str,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager, logger, sport_key)
|
||||||
|
|
||||||
|
def _test_mode_update(self):
|
||||||
|
if self.current_game and self.current_game["is_live"]:
|
||||||
|
# For testing, we'll just update the clock to show it's working
|
||||||
|
minutes = int(self.current_game["clock"].split(":")[0])
|
||||||
|
seconds = int(self.current_game["clock"].split(":")[1])
|
||||||
|
seconds -= 1
|
||||||
|
if seconds < 0:
|
||||||
|
seconds = 59
|
||||||
|
minutes -= 1
|
||||||
|
if minutes < 0:
|
||||||
|
minutes = 19
|
||||||
|
if self.current_game["period"] < 3:
|
||||||
|
self.current_game["period"] += 1
|
||||||
|
else:
|
||||||
|
self.current_game["period"] = 1
|
||||||
|
self.current_game["clock"] = f"{minutes:02d}:{seconds:02d}"
|
||||||
|
# Always update display in test mode
|
||||||
|
|
||||||
|
def _draw_scorebug_layout(self, game: Dict, force_clear: bool = False) -> None:
|
||||||
|
"""Draw the detailed scorebug layout for a live Basketball game.""" # Updated docstring
|
||||||
|
try:
|
||||||
|
main_img = Image.new(
|
||||||
|
"RGBA", (self.display_width, self.display_height), (0, 0, 0, 255)
|
||||||
|
)
|
||||||
|
overlay = Image.new(
|
||||||
|
"RGBA", (self.display_width, self.display_height), (0, 0, 0, 0)
|
||||||
|
)
|
||||||
|
draw_overlay = ImageDraw.Draw(
|
||||||
|
overlay
|
||||||
|
) # Draw text elements on overlay first
|
||||||
|
home_logo = self._load_and_resize_logo(
|
||||||
|
game["home_id"],
|
||||||
|
game["home_abbr"],
|
||||||
|
game["home_logo_path"],
|
||||||
|
game.get("home_logo_url"),
|
||||||
|
)
|
||||||
|
away_logo = self._load_and_resize_logo(
|
||||||
|
game["away_id"],
|
||||||
|
game["away_abbr"],
|
||||||
|
game["away_logo_path"],
|
||||||
|
game.get("away_logo_url"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if not home_logo or not away_logo:
|
||||||
|
self.logger.error(
|
||||||
|
f"Failed to load logos for live game: {game.get('id')}"
|
||||||
|
) # Changed log prefix
|
||||||
|
# Draw placeholder text if logos fail
|
||||||
|
draw_final = ImageDraw.Draw(main_img.convert("RGB"))
|
||||||
|
self._draw_text_with_outline(
|
||||||
|
draw_final, "Logo Error", (5, 5), self.fonts["status"]
|
||||||
|
)
|
||||||
|
self.display_manager.image.paste(main_img.convert("RGB"), (0, 0))
|
||||||
|
self.display_manager.update_display()
|
||||||
|
return
|
||||||
|
|
||||||
|
center_y = self.display_height // 2
|
||||||
|
|
||||||
|
# Draw logos (shifted slightly more inward than NHL perhaps)
|
||||||
|
home_x = (
|
||||||
|
self.display_width - home_logo.width + 10
|
||||||
|
) # adjusted from 18 # Adjust position as needed
|
||||||
|
home_y = center_y - (home_logo.height // 2)
|
||||||
|
main_img.paste(home_logo, (home_x, home_y), home_logo)
|
||||||
|
|
||||||
|
away_x = -10 # adjusted from 18 # Adjust position as needed
|
||||||
|
away_y = center_y - (away_logo.height // 2)
|
||||||
|
main_img.paste(away_logo, (away_x, away_y), away_logo)
|
||||||
|
|
||||||
|
# --- Draw Text Elements on Overlay ---
|
||||||
|
# Note: Rankings are now handled in the records/rankings section below
|
||||||
|
|
||||||
|
# Period/Quarter and Clock (Top center)
|
||||||
|
period_clock_text = (
|
||||||
|
f"{game.get('period_text', '')} {game.get('clock', '')}".strip()
|
||||||
|
)
|
||||||
|
|
||||||
|
status_width = draw_overlay.textlength(
|
||||||
|
period_clock_text, font=self.fonts["time"]
|
||||||
|
)
|
||||||
|
status_x = (self.display_width - status_width) // 2
|
||||||
|
status_y = 1 # Position at top
|
||||||
|
self._draw_text_with_outline(
|
||||||
|
draw_overlay,
|
||||||
|
period_clock_text,
|
||||||
|
(status_x, status_y),
|
||||||
|
self.fonts["time"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Scores (centered, slightly above bottom)
|
||||||
|
home_score = str(game.get("home_score", "0"))
|
||||||
|
away_score = str(game.get("away_score", "0"))
|
||||||
|
score_text = f"{away_score}-{home_score}"
|
||||||
|
score_width = draw_overlay.textlength(score_text, font=self.fonts["score"])
|
||||||
|
score_x = (self.display_width - score_width) // 2
|
||||||
|
score_y = (
|
||||||
|
self.display_height // 2
|
||||||
|
) - 3 # centered #from 14 # Position score higher
|
||||||
|
self._draw_text_with_outline(
|
||||||
|
draw_overlay, score_text, (score_x, score_y), self.fonts["score"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw odds if available
|
||||||
|
if "odds" in game and game["odds"]:
|
||||||
|
self._draw_dynamic_odds(
|
||||||
|
draw_overlay, game["odds"], self.display_width, self.display_height
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw records or rankings if enabled
|
||||||
|
if self.show_records or self.show_ranking:
|
||||||
|
try:
|
||||||
|
record_font = ImageFont.truetype("assets/fonts/4x6-font.ttf", 6)
|
||||||
|
self.logger.debug(f"Loaded 6px record font successfully")
|
||||||
|
except IOError:
|
||||||
|
record_font = ImageFont.load_default()
|
||||||
|
self.logger.warning(
|
||||||
|
f"Failed to load 6px font, using default font (size: {record_font.size})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get team abbreviations
|
||||||
|
away_abbr = game.get("away_abbr", "")
|
||||||
|
home_abbr = game.get("home_abbr", "")
|
||||||
|
|
||||||
|
record_bbox = draw_overlay.textbbox((0, 0), "0-0", font=record_font)
|
||||||
|
record_height = record_bbox[3] - record_bbox[1]
|
||||||
|
record_y = self.display_height - record_height - 1
|
||||||
|
self.logger.debug(
|
||||||
|
f"Record positioning: height={record_height}, record_y={record_y}, display_height={self.display_height}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display away team info
|
||||||
|
if away_abbr:
|
||||||
|
if self.show_ranking and self.show_records:
|
||||||
|
# When both rankings and records are enabled, rankings replace records completely
|
||||||
|
away_rank = self._team_rankings_cache.get(away_abbr, 0)
|
||||||
|
if away_rank > 0:
|
||||||
|
away_text = f"#{away_rank}"
|
||||||
|
else:
|
||||||
|
# Show nothing for unranked teams when rankings are prioritized
|
||||||
|
away_text = ""
|
||||||
|
elif self.show_ranking:
|
||||||
|
# Show ranking only if available
|
||||||
|
away_rank = self._team_rankings_cache.get(away_abbr, 0)
|
||||||
|
if away_rank > 0:
|
||||||
|
away_text = f"#{away_rank}"
|
||||||
|
else:
|
||||||
|
away_text = ""
|
||||||
|
elif self.show_records:
|
||||||
|
# Show record only when rankings are disabled
|
||||||
|
away_text = game.get("away_record", "")
|
||||||
|
else:
|
||||||
|
away_text = ""
|
||||||
|
|
||||||
|
if away_text:
|
||||||
|
away_record_x = 3
|
||||||
|
self.logger.debug(
|
||||||
|
f"Drawing away ranking '{away_text}' at ({away_record_x}, {record_y}) with font size {record_font.size if hasattr(record_font, 'size') else 'unknown'}"
|
||||||
|
)
|
||||||
|
self._draw_text_with_outline(
|
||||||
|
draw_overlay,
|
||||||
|
away_text,
|
||||||
|
(away_record_x, record_y),
|
||||||
|
record_font,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Display home team info
|
||||||
|
if home_abbr:
|
||||||
|
if self.show_ranking and self.show_records:
|
||||||
|
# When both rankings and records are enabled, rankings replace records completely
|
||||||
|
home_rank = self._team_rankings_cache.get(home_abbr, 0)
|
||||||
|
if home_rank > 0:
|
||||||
|
home_text = f"#{home_rank}"
|
||||||
|
else:
|
||||||
|
# Show nothing for unranked teams when rankings are prioritized
|
||||||
|
home_text = ""
|
||||||
|
elif self.show_ranking:
|
||||||
|
# Show ranking only if available
|
||||||
|
home_rank = self._team_rankings_cache.get(home_abbr, 0)
|
||||||
|
if home_rank > 0:
|
||||||
|
home_text = f"#{home_rank}"
|
||||||
|
else:
|
||||||
|
home_text = ""
|
||||||
|
elif self.show_records:
|
||||||
|
# Show record only when rankings are disabled
|
||||||
|
home_text = game.get("home_record", "")
|
||||||
|
else:
|
||||||
|
home_text = ""
|
||||||
|
|
||||||
|
if home_text:
|
||||||
|
home_record_bbox = draw_overlay.textbbox(
|
||||||
|
(0, 0), home_text, font=record_font
|
||||||
|
)
|
||||||
|
home_record_width = home_record_bbox[2] - home_record_bbox[0]
|
||||||
|
home_record_x = self.display_width - home_record_width - 3
|
||||||
|
self.logger.debug(
|
||||||
|
f"Drawing home ranking '{home_text}' at ({home_record_x}, {record_y}) with font size {record_font.size if hasattr(record_font, 'size') else 'unknown'}"
|
||||||
|
)
|
||||||
|
self._draw_text_with_outline(
|
||||||
|
draw_overlay,
|
||||||
|
home_text,
|
||||||
|
(home_record_x, record_y),
|
||||||
|
record_font,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Composite the text overlay onto the main image
|
||||||
|
main_img = Image.alpha_composite(main_img, overlay)
|
||||||
|
main_img = main_img.convert("RGB") # Convert for display
|
||||||
|
|
||||||
|
# Display the final image
|
||||||
|
self.display_manager.image.paste(main_img, (0, 0))
|
||||||
|
self.display_manager.update_display() # Update display here for live
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(
|
||||||
|
f"Error displaying live Hockey game: {e}", exc_info=True
|
||||||
|
) # Changed log prefix
|
||||||
@@ -419,6 +419,7 @@ class SportsCore(ABC):
|
|||||||
if not home_team or not away_team:
|
if not home_team or not away_team:
|
||||||
self.logger.warning(f"Could not find home or away team in event: {game_event.get('id')}")
|
self.logger.warning(f"Could not find home or away team in event: {game_event.get('id')}")
|
||||||
return None, None, None, None, None
|
return None, None, None, None, None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
home_abbr = home_team["team"]["abbreviation"]
|
home_abbr = home_team["team"]["abbreviation"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from src.odds_ticker_manager import OddsTickerManager
|
|||||||
from src.leaderboard_manager import LeaderboardManager
|
from src.leaderboard_manager import LeaderboardManager
|
||||||
from src.nhl_managers import NHLLiveManager, NHLRecentManager, NHLUpcomingManager
|
from src.nhl_managers import NHLLiveManager, NHLRecentManager, NHLUpcomingManager
|
||||||
from src.nba_managers import NBALiveManager, NBARecentManager, NBAUpcomingManager
|
from src.nba_managers import NBALiveManager, NBARecentManager, NBAUpcomingManager
|
||||||
|
from src.wnba_managers import WNBALiveManager, WNBARecentManager, WNBAUpcomingManager
|
||||||
from src.mlb_manager import MLBLiveManager, MLBRecentManager, MLBUpcomingManager
|
from src.mlb_manager import MLBLiveManager, MLBRecentManager, MLBUpcomingManager
|
||||||
from src.milb_manager import MiLBLiveManager, MiLBRecentManager, MiLBUpcomingManager
|
from src.milb_manager import MiLBLiveManager, MiLBRecentManager, MiLBUpcomingManager
|
||||||
from src.soccer_managers import SoccerLiveManager, SoccerRecentManager, SoccerUpcomingManager
|
from src.soccer_managers import SoccerLiveManager, SoccerRecentManager, SoccerUpcomingManager
|
||||||
@@ -30,6 +31,7 @@ from src.nfl_managers import NFLLiveManager, NFLRecentManager, NFLUpcomingManage
|
|||||||
from src.ncaa_fb_managers import NCAAFBLiveManager, NCAAFBRecentManager, NCAAFBUpcomingManager
|
from src.ncaa_fb_managers import NCAAFBLiveManager, NCAAFBRecentManager, NCAAFBUpcomingManager
|
||||||
from src.ncaa_baseball_managers import NCAABaseballLiveManager, NCAABaseballRecentManager, NCAABaseballUpcomingManager
|
from src.ncaa_baseball_managers import NCAABaseballLiveManager, NCAABaseballRecentManager, NCAABaseballUpcomingManager
|
||||||
from src.ncaam_basketball_managers import NCAAMBasketballLiveManager, NCAAMBasketballRecentManager, NCAAMBasketballUpcomingManager
|
from src.ncaam_basketball_managers import NCAAMBasketballLiveManager, NCAAMBasketballRecentManager, NCAAMBasketballUpcomingManager
|
||||||
|
from src.ncaaw_basketball_managers import NCAAWBasketballLiveManager, NCAAWBasketballRecentManager, NCAAWBasketballUpcomingManager
|
||||||
from src.ncaam_hockey_managers import NCAAMHockeyLiveManager, NCAAMHockeyRecentManager, NCAAMHockeyUpcomingManager
|
from src.ncaam_hockey_managers import NCAAMHockeyLiveManager, NCAAMHockeyRecentManager, NCAAMHockeyUpcomingManager
|
||||||
from src.ncaaw_hockey_managers import NCAAWHockeyLiveManager, NCAAWHockeyRecentManager, NCAAWHockeyUpcomingManager
|
from src.ncaaw_hockey_managers import NCAAWHockeyLiveManager, NCAAWHockeyRecentManager, NCAAWHockeyUpcomingManager
|
||||||
from src.youtube_display import YouTubeDisplay
|
from src.youtube_display import YouTubeDisplay
|
||||||
@@ -135,6 +137,21 @@ class DisplayController:
|
|||||||
self.nba_upcoming = None
|
self.nba_upcoming = None
|
||||||
logger.info("NBA managers initialized in %.3f seconds", time.time() - nba_time)
|
logger.info("NBA managers initialized in %.3f seconds", time.time() - nba_time)
|
||||||
|
|
||||||
|
# Initialize WNBA managers if enabled
|
||||||
|
wnba_time = time.time()
|
||||||
|
wnba_enabled = self.config.get('wnba_scoreboard', {}).get('enabled', False)
|
||||||
|
wnba_display_modes = self.config.get('wnba_scoreboard', {}).get('display_modes', {})
|
||||||
|
|
||||||
|
if wnba_enabled:
|
||||||
|
self.wnba_live = WNBALiveManager(self.config, self.display_manager, self.cache_manager) if wnba_display_modes.get('wnba_live', True) else None
|
||||||
|
self.wnba_recent = WNBARecentManager(self.config, self.display_manager, self.cache_manager) if wnba_display_modes.get('wnba_recent', True) else None
|
||||||
|
self.wnba_upcoming = WNBAUpcomingManager(self.config, self.display_manager, self.cache_manager) if wnba_display_modes.get('wnba_upcoming', True) else None
|
||||||
|
else:
|
||||||
|
self.wnba_live = None
|
||||||
|
self.wnba_recent = None
|
||||||
|
self.wnba_upcoming = None
|
||||||
|
logger.info("WNBA managers initialized in %.3f seconds", time.time() - wnba_time)
|
||||||
|
|
||||||
# Initialize MLB managers if enabled
|
# Initialize MLB managers if enabled
|
||||||
mlb_time = time.time()
|
mlb_time = time.time()
|
||||||
mlb_enabled = self.config.get('mlb_scoreboard', {}).get('enabled', False)
|
mlb_enabled = self.config.get('mlb_scoreboard', {}).get('enabled', False)
|
||||||
@@ -242,6 +259,21 @@ class DisplayController:
|
|||||||
self.ncaam_basketball_upcoming = None
|
self.ncaam_basketball_upcoming = None
|
||||||
logger.info("NCAA Men's Basketball managers initialized in %.3f seconds", time.time() - ncaam_basketball_time)
|
logger.info("NCAA Men's Basketball managers initialized in %.3f seconds", time.time() - ncaam_basketball_time)
|
||||||
|
|
||||||
|
# Initialize NCAA Womens's Basketball managers if enabled
|
||||||
|
ncaaw_basketball_time = time.time()
|
||||||
|
ncaaw_basketball_enabled = self.config.get('ncaaw_basketball_scoreboard', {}).get('enabled', False)
|
||||||
|
ncaaw_basketball_display_modes = self.config.get('ncaaw_basketball_scoreboard', {}).get('display_modes', {})
|
||||||
|
|
||||||
|
if ncaaw_basketball_enabled:
|
||||||
|
self.ncaaw_basketball_live = NCAAWBasketballLiveManager(self.config, self.display_manager, self.cache_manager) if ncaaw_basketball_display_modes.get('ncaaw_basketball_live', True) else None
|
||||||
|
self.ncaaw_basketball_recent = NCAAWBasketballRecentManager(self.config, self.display_manager, self.cache_manager) if ncaaw_basketball_display_modes.get('ncaaw_basketball_recent', True) else None
|
||||||
|
self.ncaaw_basketball_upcoming = NCAAWBasketballUpcomingManager(self.config, self.display_manager, self.cache_manager) if ncaaw_basketball_display_modes.get('ncaaw_basketball_upcoming', True) else None
|
||||||
|
else:
|
||||||
|
self.ncaaw_basketball_live = None
|
||||||
|
self.ncaaw_basketball_recent = None
|
||||||
|
self.ncaaw_basketball_upcoming = None
|
||||||
|
logger.info("NCAA Womens's Basketball managers initialized in %.3f seconds", time.time() - ncaaw_basketball_time)
|
||||||
|
|
||||||
# Initialize NCAA Men's Hockey managers if enabled
|
# Initialize NCAA Men's Hockey managers if enabled
|
||||||
ncaam_hockey_time = time.time()
|
ncaam_hockey_time = time.time()
|
||||||
ncaam_hockey_enabled = self.config.get('ncaam_hockey_scoreboard', {}).get('enabled', False)
|
ncaam_hockey_enabled = self.config.get('ncaam_hockey_scoreboard', {}).get('enabled', False)
|
||||||
@@ -281,6 +313,7 @@ class DisplayController:
|
|||||||
# Read live_priority flags for all sports
|
# Read live_priority flags for all sports
|
||||||
self.nhl_live_priority = self.config.get('nhl_scoreboard', {}).get('live_priority', True)
|
self.nhl_live_priority = self.config.get('nhl_scoreboard', {}).get('live_priority', True)
|
||||||
self.nba_live_priority = self.config.get('nba_scoreboard', {}).get('live_priority', True)
|
self.nba_live_priority = self.config.get('nba_scoreboard', {}).get('live_priority', True)
|
||||||
|
self.wnba_live_priority = self.config.get('wnba_scoreboard', {}).get('live_priority', True)
|
||||||
self.mlb_live_priority = self.config.get('mlb_scoreboard', {}).get('live_priority', True)
|
self.mlb_live_priority = self.config.get('mlb_scoreboard', {}).get('live_priority', True)
|
||||||
self.milb_live_priority = self.config.get('milb_scoreboard', {}).get('live_priority', True)
|
self.milb_live_priority = self.config.get('milb_scoreboard', {}).get('live_priority', True)
|
||||||
self.soccer_live_priority = self.config.get('soccer_scoreboard', {}).get('live_priority', True)
|
self.soccer_live_priority = self.config.get('soccer_scoreboard', {}).get('live_priority', True)
|
||||||
@@ -288,6 +321,7 @@ class DisplayController:
|
|||||||
self.ncaa_fb_live_priority = self.config.get('ncaa_fb_scoreboard', {}).get('live_priority', True)
|
self.ncaa_fb_live_priority = self.config.get('ncaa_fb_scoreboard', {}).get('live_priority', True)
|
||||||
self.ncaa_baseball_live_priority = self.config.get('ncaa_baseball_scoreboard', {}).get('live_priority', True)
|
self.ncaa_baseball_live_priority = self.config.get('ncaa_baseball_scoreboard', {}).get('live_priority', True)
|
||||||
self.ncaam_basketball_live_priority = self.config.get('ncaam_basketball_scoreboard', {}).get('live_priority', True)
|
self.ncaam_basketball_live_priority = self.config.get('ncaam_basketball_scoreboard', {}).get('live_priority', True)
|
||||||
|
self.ncaaw_basketball_live_priority = self.config.get('ncaaw_basketball_scoreboard', {}).get('live_priority', True)
|
||||||
self.ncaam_hockey_live_priority = self.config.get('ncaam_hockey_scoreboard', {}).get('live_priority', True)
|
self.ncaam_hockey_live_priority = self.config.get('ncaam_hockey_scoreboard', {}).get('live_priority', True)
|
||||||
self.ncaaw_hockey_live_priority = self.config.get('ncaaw_hockey_scoreboard', {}).get('live_priority', True)
|
self.ncaaw_hockey_live_priority = self.config.get('ncaaw_hockey_scoreboard', {}).get('live_priority', True)
|
||||||
|
|
||||||
@@ -315,6 +349,9 @@ class DisplayController:
|
|||||||
if nba_enabled:
|
if nba_enabled:
|
||||||
if self.nba_recent: self.available_modes.append('nba_recent')
|
if self.nba_recent: self.available_modes.append('nba_recent')
|
||||||
if self.nba_upcoming: self.available_modes.append('nba_upcoming')
|
if self.nba_upcoming: self.available_modes.append('nba_upcoming')
|
||||||
|
if wnba_enabled:
|
||||||
|
if self.wnba_recent: self.available_modes.append('wnba_recent')
|
||||||
|
if self.wnba_upcoming: self.available_modes.append('wnba_upcoming')
|
||||||
if mlb_enabled:
|
if mlb_enabled:
|
||||||
if self.mlb_recent: self.available_modes.append('mlb_recent')
|
if self.mlb_recent: self.available_modes.append('mlb_recent')
|
||||||
if self.mlb_upcoming: self.available_modes.append('mlb_upcoming')
|
if self.mlb_upcoming: self.available_modes.append('mlb_upcoming')
|
||||||
@@ -336,6 +373,9 @@ class DisplayController:
|
|||||||
if ncaam_basketball_enabled:
|
if ncaam_basketball_enabled:
|
||||||
if self.ncaam_basketball_recent: self.available_modes.append('ncaam_basketball_recent')
|
if self.ncaam_basketball_recent: self.available_modes.append('ncaam_basketball_recent')
|
||||||
if self.ncaam_basketball_upcoming: self.available_modes.append('ncaam_basketball_upcoming')
|
if self.ncaam_basketball_upcoming: self.available_modes.append('ncaam_basketball_upcoming')
|
||||||
|
if ncaaw_basketball_enabled:
|
||||||
|
if self.ncaaw_basketball_recent: self.available_modes.append('ncaaw_basketball_recent')
|
||||||
|
if self.ncaaw_basketball_upcoming: self.available_modes.append('ncaaw_basketball_upcoming')
|
||||||
if ncaam_hockey_enabled:
|
if ncaam_hockey_enabled:
|
||||||
if self.ncaam_hockey_recent: self.available_modes.append('ncaam_hockey_recent')
|
if self.ncaam_hockey_recent: self.available_modes.append('ncaam_hockey_recent')
|
||||||
if self.ncaam_hockey_upcoming: self.available_modes.append('ncaam_hockey_upcoming')
|
if self.ncaam_hockey_upcoming: self.available_modes.append('ncaam_hockey_upcoming')
|
||||||
@@ -366,6 +406,11 @@ class DisplayController:
|
|||||||
self.nba_favorite_teams = self.config.get('nba_scoreboard', {}).get('favorite_teams', [])
|
self.nba_favorite_teams = self.config.get('nba_scoreboard', {}).get('favorite_teams', [])
|
||||||
self.in_nba_rotation = False
|
self.in_nba_rotation = False
|
||||||
|
|
||||||
|
self.wnba_current_team_index = 0
|
||||||
|
self.wnba_showing_recent = True
|
||||||
|
self.wnba_favorite_teams = self.config.get('wnba_scoreboard', {}).get('favorite_teams', [])
|
||||||
|
self.in_wnba_rotation = False
|
||||||
|
|
||||||
self.soccer_current_team_index = 0 # Soccer rotation state
|
self.soccer_current_team_index = 0 # Soccer rotation state
|
||||||
self.soccer_showing_recent = True
|
self.soccer_showing_recent = True
|
||||||
self.soccer_favorite_teams = self.config.get('soccer_scoreboard', {}).get('favorite_teams', [])
|
self.soccer_favorite_teams = self.config.get('soccer_scoreboard', {}).get('favorite_teams', [])
|
||||||
@@ -395,6 +440,12 @@ class DisplayController:
|
|||||||
self.ncaam_basketball_favorite_teams = self.config.get('ncaam_basketball_scoreboard', {}).get('favorite_teams', [])
|
self.ncaam_basketball_favorite_teams = self.config.get('ncaam_basketball_scoreboard', {}).get('favorite_teams', [])
|
||||||
self.in_ncaam_basketball_rotation = False
|
self.in_ncaam_basketball_rotation = False
|
||||||
|
|
||||||
|
# Add NCAA Womens's Basketball rotation state
|
||||||
|
self.ncaaw_basketball_current_team_index = 0
|
||||||
|
self.ncaaw_basketball_showing_recent = True
|
||||||
|
self.ncaaw_basketball_favorite_teams = self.config.get('ncaaw_basketball_scoreboard', {}).get('favorite_teams', [])
|
||||||
|
self.in_ncaaw_basketball_rotation = False
|
||||||
|
|
||||||
# Update display durations to include all modes
|
# Update display durations to include all modes
|
||||||
self.display_durations = self.config['display'].get('display_durations', {})
|
self.display_durations = self.config['display'].get('display_durations', {})
|
||||||
# Backward-compatibility: map legacy weather keys to current keys if provided in config
|
# Backward-compatibility: map legacy weather keys to current keys if provided in config
|
||||||
@@ -423,6 +474,9 @@ class DisplayController:
|
|||||||
'nba_live': 30,
|
'nba_live': 30,
|
||||||
'nba_recent': 20,
|
'nba_recent': 20,
|
||||||
'nba_upcoming': 20,
|
'nba_upcoming': 20,
|
||||||
|
'wnba_live': 30,
|
||||||
|
'wnba_recent': 20,
|
||||||
|
'wnba_upcoming': 20,
|
||||||
'mlb_live': 30,
|
'mlb_live': 30,
|
||||||
'mlb_recent': 20,
|
'mlb_recent': 20,
|
||||||
'mlb_upcoming': 20,
|
'mlb_upcoming': 20,
|
||||||
@@ -445,6 +499,9 @@ class DisplayController:
|
|||||||
'ncaam_basketball_live': 30, # Added NCAA Men's Basketball durations
|
'ncaam_basketball_live': 30, # Added NCAA Men's Basketball durations
|
||||||
'ncaam_basketball_recent': 15,
|
'ncaam_basketball_recent': 15,
|
||||||
'ncaam_basketball_upcoming': 15,
|
'ncaam_basketball_upcoming': 15,
|
||||||
|
'ncaaw_basketball_live': 30, # Added NCAA Womens's Basketball durations
|
||||||
|
'ncaaw_basketball_recent': 15,
|
||||||
|
'ncaaw_basketball_upcoming': 15,
|
||||||
'ncaam_hockey_live': 30, # Added NCAA Men's Hockey durations
|
'ncaam_hockey_live': 30, # Added NCAA Men's Hockey durations
|
||||||
'ncaam_hockey_recent': 15,
|
'ncaam_hockey_recent': 15,
|
||||||
'ncaam_hockey_upcoming': 15,
|
'ncaam_hockey_upcoming': 15,
|
||||||
@@ -462,6 +519,8 @@ class DisplayController:
|
|||||||
logger.info(f"NHL Favorite teams: {self.nhl_favorite_teams}")
|
logger.info(f"NHL Favorite teams: {self.nhl_favorite_teams}")
|
||||||
if nba_enabled:
|
if nba_enabled:
|
||||||
logger.info(f"NBA Favorite teams: {self.nba_favorite_teams}")
|
logger.info(f"NBA Favorite teams: {self.nba_favorite_teams}")
|
||||||
|
if wnba_enabled:
|
||||||
|
logger.info(f"WNBA Favorite teams: {self.wnba_favorite_teams}")
|
||||||
if mlb_enabled:
|
if mlb_enabled:
|
||||||
logger.info(f"MLB Favorite teams: {self.mlb_favorite_teams}")
|
logger.info(f"MLB Favorite teams: {self.mlb_favorite_teams}")
|
||||||
if milb_enabled:
|
if milb_enabled:
|
||||||
@@ -476,6 +535,8 @@ class DisplayController:
|
|||||||
logger.info(f"NCAA Baseball Favorite teams: {self.ncaa_baseball_favorite_teams}")
|
logger.info(f"NCAA Baseball Favorite teams: {self.ncaa_baseball_favorite_teams}")
|
||||||
if ncaam_basketball_enabled: # Check if NCAA Men's Basketball is enabled
|
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"NCAA Men's Basketball Favorite teams: {self.ncaam_basketball_favorite_teams}")
|
||||||
|
if ncaaw_basketball_enabled: # Check if NCAA Womens's Basketball is enabled
|
||||||
|
logger.info(f"NCAA Womens's Basketball Favorite teams: {self.ncaaw_basketball_favorite_teams}")
|
||||||
|
|
||||||
logger.info(f"Available display modes: {self.available_modes}")
|
logger.info(f"Available display modes: {self.available_modes}")
|
||||||
logger.info(f"Initial display mode: {self.current_display_mode}")
|
logger.info(f"Initial display mode: {self.current_display_mode}")
|
||||||
@@ -674,6 +735,10 @@ class DisplayController:
|
|||||||
if self.nba_live: self.nba_live.update()
|
if self.nba_live: self.nba_live.update()
|
||||||
if self.nba_recent: self.nba_recent.update()
|
if self.nba_recent: self.nba_recent.update()
|
||||||
if self.nba_upcoming: self.nba_upcoming.update()
|
if self.nba_upcoming: self.nba_upcoming.update()
|
||||||
|
elif current_sport == 'wnba':
|
||||||
|
if self.wnba_live: self.wnba_live.update()
|
||||||
|
if self.wnba_recent: self.wnba_recent.update()
|
||||||
|
if self.wnba_upcoming: self.wnba_upcoming.update()
|
||||||
elif current_sport == 'mlb':
|
elif current_sport == 'mlb':
|
||||||
if self.mlb_live: self.mlb_live.update()
|
if self.mlb_live: self.mlb_live.update()
|
||||||
if self.mlb_recent: self.mlb_recent.update()
|
if self.mlb_recent: self.mlb_recent.update()
|
||||||
@@ -702,6 +767,10 @@ class DisplayController:
|
|||||||
if self.ncaam_basketball_live: self.ncaam_basketball_live.update()
|
if self.ncaam_basketball_live: self.ncaam_basketball_live.update()
|
||||||
if self.ncaam_basketball_recent: self.ncaam_basketball_recent.update()
|
if self.ncaam_basketball_recent: self.ncaam_basketball_recent.update()
|
||||||
if self.ncaam_basketball_upcoming: self.ncaam_basketball_upcoming.update()
|
if self.ncaam_basketball_upcoming: self.ncaam_basketball_upcoming.update()
|
||||||
|
elif current_sport == 'ncaaw_basketball':
|
||||||
|
if self.ncaaw_basketball_live: self.ncaaw_basketball_live.update()
|
||||||
|
if self.ncaaw_basketball_recent: self.ncaaw_basketball_recent.update()
|
||||||
|
if self.ncaaw_basketball_upcoming: self.ncaaw_basketball_upcoming.update()
|
||||||
elif current_sport == 'ncaam_hockey':
|
elif current_sport == 'ncaam_hockey':
|
||||||
if self.ncaam_hockey_live: self.ncaam_hockey_live.update()
|
if self.ncaam_hockey_live: self.ncaam_hockey_live.update()
|
||||||
if self.ncaam_hockey_recent: self.ncaam_hockey_recent.update()
|
if self.ncaam_hockey_recent: self.ncaam_hockey_recent.update()
|
||||||
@@ -721,6 +790,10 @@ class DisplayController:
|
|||||||
if self.nba_recent: self.nba_recent.update()
|
if self.nba_recent: self.nba_recent.update()
|
||||||
if self.nba_upcoming: self.nba_upcoming.update()
|
if self.nba_upcoming: self.nba_upcoming.update()
|
||||||
|
|
||||||
|
if self.wnba_live: self.wnba_live.update()
|
||||||
|
if self.wnba_recent: self.wnba_recent.update()
|
||||||
|
if self.wnba_upcoming: self.wnba_upcoming.update()
|
||||||
|
|
||||||
if self.mlb_live: self.mlb_live.update()
|
if self.mlb_live: self.mlb_live.update()
|
||||||
if self.mlb_recent: self.mlb_recent.update()
|
if self.mlb_recent: self.mlb_recent.update()
|
||||||
if self.mlb_upcoming: self.mlb_upcoming.update()
|
if self.mlb_upcoming: self.mlb_upcoming.update()
|
||||||
@@ -749,6 +822,10 @@ class DisplayController:
|
|||||||
if self.ncaam_basketball_recent: self.ncaam_basketball_recent.update()
|
if self.ncaam_basketball_recent: self.ncaam_basketball_recent.update()
|
||||||
if self.ncaam_basketball_upcoming: self.ncaam_basketball_upcoming.update()
|
if self.ncaam_basketball_upcoming: self.ncaam_basketball_upcoming.update()
|
||||||
|
|
||||||
|
if self.ncaaw_basketball_live: self.ncaaw_basketball_live.update()
|
||||||
|
if self.ncaaw_basketball_recent: self.ncaaw_basketball_recent.update()
|
||||||
|
if self.ncaaw_basketball_upcoming: self.ncaaw_basketball_upcoming.update()
|
||||||
|
|
||||||
if self.ncaam_hockey_live: self.ncaam_hockey_live.update()
|
if self.ncaam_hockey_live: self.ncaam_hockey_live.update()
|
||||||
if self.ncaam_hockey_recent: self.ncaam_hockey_recent.update()
|
if self.ncaam_hockey_recent: self.ncaam_hockey_recent.update()
|
||||||
if self.ncaam_hockey_upcoming: self.ncaam_hockey_upcoming.update()
|
if self.ncaam_hockey_upcoming: self.ncaam_hockey_upcoming.update()
|
||||||
@@ -770,6 +847,8 @@ class DisplayController:
|
|||||||
live_checks['nhl'] = self.nhl_live and self.nhl_live.live_games
|
live_checks['nhl'] = self.nhl_live and self.nhl_live.live_games
|
||||||
if 'nba_scoreboard' in self.config and self.config['nba_scoreboard'].get('enabled', False):
|
if 'nba_scoreboard' in self.config and self.config['nba_scoreboard'].get('enabled', False):
|
||||||
live_checks['nba'] = self.nba_live and self.nba_live.live_games
|
live_checks['nba'] = self.nba_live and self.nba_live.live_games
|
||||||
|
if 'wnba_scoreboard' in self.config and self.config['wnba_scoreboard'].get('enabled', False):
|
||||||
|
live_checks['wnba'] = self.wnba_live and self.wnba_live.live_games
|
||||||
if 'mlb' in self.config and self.config['mlb'].get('enabled', False):
|
if 'mlb' in self.config and self.config['mlb'].get('enabled', False):
|
||||||
live_checks['mlb'] = self.mlb_live and self.mlb_live.live_games
|
live_checks['mlb'] = self.mlb_live and self.mlb_live.live_games
|
||||||
if 'milb' in self.config and self.config['milb'].get('enabled', False):
|
if 'milb' in self.config and self.config['milb'].get('enabled', False):
|
||||||
@@ -784,6 +863,8 @@ class DisplayController:
|
|||||||
live_checks['ncaa_baseball'] = self.ncaa_baseball_live and self.ncaa_baseball_live.live_games
|
live_checks['ncaa_baseball'] = self.ncaa_baseball_live and self.ncaa_baseball_live.live_games
|
||||||
if 'ncaam_basketball_scoreboard' in self.config and self.config['ncaam_basketball_scoreboard'].get('enabled', False):
|
if 'ncaam_basketball_scoreboard' in self.config and self.config['ncaam_basketball_scoreboard'].get('enabled', False):
|
||||||
live_checks['ncaam_basketball'] = self.ncaam_basketball_live and self.ncaam_basketball_live.live_games
|
live_checks['ncaam_basketball'] = self.ncaam_basketball_live and self.ncaam_basketball_live.live_games
|
||||||
|
if 'ncaaw_basketball_scoreboard' in self.config and self.config['ncaaw_basketball_scoreboard'].get('enabled', False):
|
||||||
|
live_checks['ncaaw_basketball'] = self.ncaaw_basketball_live and self.ncaaw_basketball_live.live_games
|
||||||
if 'ncaam_hockey_scoreboard' in self.config and self.config['ncaam_hockey_scoreboard'].get('enabled', False):
|
if 'ncaam_hockey_scoreboard' in self.config and self.config['ncaam_hockey_scoreboard'].get('enabled', False):
|
||||||
live_checks['ncaam_hockey'] = self.ncaam_hockey_live and self.ncaam_hockey_live.live_games
|
live_checks['ncaam_hockey'] = self.ncaam_hockey_live and self.ncaam_hockey_live.live_games
|
||||||
if 'ncaaw_hockey_scoreboard' in self.config and self.config['ncaaw_hockey_scoreboard'].get('enabled', False):
|
if 'ncaaw_hockey_scoreboard' in self.config and self.config['ncaaw_hockey_scoreboard'].get('enabled', False):
|
||||||
@@ -818,6 +899,9 @@ class DisplayController:
|
|||||||
elif sport == 'nba':
|
elif sport == 'nba':
|
||||||
manager_recent = self.nba_recent
|
manager_recent = self.nba_recent
|
||||||
manager_upcoming = self.nba_upcoming
|
manager_upcoming = self.nba_upcoming
|
||||||
|
elif sport == 'wnba':
|
||||||
|
manager_recent = self.wnba_recent
|
||||||
|
manager_upcoming = self.wnba_upcoming
|
||||||
elif sport == 'mlb':
|
elif sport == 'mlb':
|
||||||
manager_recent = self.mlb_recent
|
manager_recent = self.mlb_recent
|
||||||
manager_upcoming = self.mlb_upcoming
|
manager_upcoming = self.mlb_upcoming
|
||||||
@@ -872,6 +956,10 @@ class DisplayController:
|
|||||||
favorite_teams = self.nba_favorite_teams
|
favorite_teams = self.nba_favorite_teams
|
||||||
manager_recent = self.nba_recent
|
manager_recent = self.nba_recent
|
||||||
manager_upcoming = self.nba_upcoming
|
manager_upcoming = self.nba_upcoming
|
||||||
|
elif sport == 'wnba':
|
||||||
|
favorite_teams = self.wnba_favorite_teams
|
||||||
|
manager_recent = self.wnba_recent
|
||||||
|
manager_upcoming = self.wnba_upcoming
|
||||||
elif sport == 'mlb':
|
elif sport == 'mlb':
|
||||||
favorite_teams = self.mlb_favorite_teams
|
favorite_teams = self.mlb_favorite_teams
|
||||||
manager_recent = self.mlb_recent
|
manager_recent = self.mlb_recent
|
||||||
@@ -895,73 +983,6 @@ class DisplayController:
|
|||||||
|
|
||||||
return bool(favorite_teams and (manager_recent or manager_upcoming))
|
return bool(favorite_teams and (manager_recent or manager_upcoming))
|
||||||
|
|
||||||
def _rotate_team_games(self, sport: str = 'nhl') -> None:
|
|
||||||
"""Rotate through games for favorite teams. (No longer used directly in loop)"""
|
|
||||||
# This logic is now mostly handled within each manager's display/update
|
|
||||||
# Keeping the structure in case direct rotation is needed later.
|
|
||||||
if not self._has_team_games(sport):
|
|
||||||
return
|
|
||||||
|
|
||||||
if sport == 'nhl':
|
|
||||||
if not self.nhl_favorite_teams: return
|
|
||||||
current_team = self.nhl_favorite_teams[self.nhl_current_team_index]
|
|
||||||
# ... (rest of NHL rotation logic - now less relevant)
|
|
||||||
elif sport == 'nba':
|
|
||||||
if not self.nba_favorite_teams: return
|
|
||||||
current_team = self.nba_favorite_teams[self.nba_current_team_index]
|
|
||||||
# ... (rest of NBA rotation logic)
|
|
||||||
elif sport == 'mlb':
|
|
||||||
if not self.mlb_favorite_teams: return
|
|
||||||
current_team = self.mlb_favorite_teams[self.mlb_current_team_index]
|
|
||||||
# ... (rest of MLB rotation logic)
|
|
||||||
elif sport == 'milb':
|
|
||||||
if not self.config.get('milb_scoreboard', {}).get('favorite_teams', []): return
|
|
||||||
current_team = self.config['milb_scoreboard']['favorite_teams'][self.milb_current_team_index]
|
|
||||||
# ... (rest of MiLB rotation logic)
|
|
||||||
elif sport == 'soccer':
|
|
||||||
if not self.soccer_favorite_teams: return
|
|
||||||
current_team = self.soccer_favorite_teams[self.soccer_current_team_index]
|
|
||||||
# Try to find games for current team (recent first)
|
|
||||||
found_games = self._get_team_games(current_team, 'soccer', self.soccer_showing_recent)
|
|
||||||
if not found_games:
|
|
||||||
# Try opposite type (upcoming/recent)
|
|
||||||
self.soccer_showing_recent = not self.soccer_showing_recent
|
|
||||||
found_games = self._get_team_games(current_team, 'soccer', self.soccer_showing_recent)
|
|
||||||
|
|
||||||
if not found_games:
|
|
||||||
# Move to next team if no games found for current one
|
|
||||||
self.soccer_current_team_index = (self.soccer_current_team_index + 1) % len(self.soccer_favorite_teams)
|
|
||||||
self.soccer_showing_recent = True # Reset to recent for the new team
|
|
||||||
# Maybe try finding game for the *new* team immediately? Optional.
|
|
||||||
elif sport == 'nfl':
|
|
||||||
if not self.nfl_favorite_teams: return
|
|
||||||
current_team = self.nfl_favorite_teams[self.nfl_current_team_index]
|
|
||||||
# Try to find games for current team (recent first)
|
|
||||||
found_games = self._get_team_games(current_team, 'nfl', self.nfl_showing_recent)
|
|
||||||
if not found_games:
|
|
||||||
# Try opposite type (upcoming/recent)
|
|
||||||
self.nfl_showing_recent = not self.nfl_showing_recent
|
|
||||||
found_games = self._get_team_games(current_team, 'nfl', self.nfl_showing_recent)
|
|
||||||
|
|
||||||
if not found_games:
|
|
||||||
# Move to next team if no games found for current one
|
|
||||||
self.nfl_current_team_index = (self.nfl_current_team_index + 1) % len(self.nfl_favorite_teams)
|
|
||||||
self.nfl_showing_recent = True # Reset to recent for the new team
|
|
||||||
elif sport == 'ncaa_fb': # Add NCAA FB case
|
|
||||||
if not self.ncaa_fb_favorite_teams: return
|
|
||||||
current_team = self.ncaa_fb_favorite_teams[self.ncaa_fb_current_team_index]
|
|
||||||
# Try to find games for current team (recent first)
|
|
||||||
found_games = self._get_team_games(current_team, 'ncaa_fb', self.ncaa_fb_showing_recent)
|
|
||||||
if not found_games:
|
|
||||||
# Try opposite type (upcoming/recent)
|
|
||||||
self.ncaa_fb_showing_recent = not self.ncaa_fb_showing_recent
|
|
||||||
found_games = self._get_team_games(current_team, 'ncaa_fb', self.ncaa_fb_showing_recent)
|
|
||||||
|
|
||||||
if not found_games:
|
|
||||||
# Move to next team if no games found for current one
|
|
||||||
self.ncaa_fb_current_team_index = (self.ncaa_fb_current_team_index + 1) % len(self.ncaa_fb_favorite_teams)
|
|
||||||
self.ncaa_fb_showing_recent = True # Reset to recent for the new team
|
|
||||||
|
|
||||||
# --- SCHEDULING METHODS ---
|
# --- SCHEDULING METHODS ---
|
||||||
def _load_schedule_config(self):
|
def _load_schedule_config(self):
|
||||||
"""Load schedule configuration once at startup."""
|
"""Load schedule configuration once at startup."""
|
||||||
@@ -1031,6 +1052,7 @@ class DisplayController:
|
|||||||
# Check if each sport is enabled before processing
|
# Check if each sport is enabled before processing
|
||||||
nhl_enabled = self.config.get('nhl_scoreboard', {}).get('enabled', False)
|
nhl_enabled = self.config.get('nhl_scoreboard', {}).get('enabled', False)
|
||||||
nba_enabled = self.config.get('nba_scoreboard', {}).get('enabled', False)
|
nba_enabled = self.config.get('nba_scoreboard', {}).get('enabled', False)
|
||||||
|
wnba_enabled = self.config.get('wnba_scoreboard', {}).get('enabled', False)
|
||||||
mlb_enabled = self.config.get('mlb_scoreboard', {}).get('enabled', False)
|
mlb_enabled = self.config.get('mlb_scoreboard', {}).get('enabled', False)
|
||||||
milb_enabled = self.config.get('milb_scoreboard', {}).get('enabled', False)
|
milb_enabled = self.config.get('milb_scoreboard', {}).get('enabled', False)
|
||||||
soccer_enabled = self.config.get('soccer_scoreboard', {}).get('enabled', False)
|
soccer_enabled = self.config.get('soccer_scoreboard', {}).get('enabled', False)
|
||||||
@@ -1038,11 +1060,13 @@ class DisplayController:
|
|||||||
ncaa_fb_enabled = self.config.get('ncaa_fb_scoreboard', {}).get('enabled', False)
|
ncaa_fb_enabled = self.config.get('ncaa_fb_scoreboard', {}).get('enabled', False)
|
||||||
ncaa_baseball_enabled = self.config.get('ncaa_baseball_scoreboard', {}).get('enabled', False)
|
ncaa_baseball_enabled = self.config.get('ncaa_baseball_scoreboard', {}).get('enabled', False)
|
||||||
ncaam_basketball_enabled = self.config.get('ncaam_basketball_scoreboard', {}).get('enabled', False)
|
ncaam_basketball_enabled = self.config.get('ncaam_basketball_scoreboard', {}).get('enabled', False)
|
||||||
|
ncaaw_basketball_enabled = self.config.get('ncaaw_basketball_scoreboard', {}).get('enabled', False)
|
||||||
ncaam_hockey_enabled = self.config.get('ncaam_hockey_scoreboard', {}).get('enabled', False)
|
ncaam_hockey_enabled = self.config.get('ncaam_hockey_scoreboard', {}).get('enabled', False)
|
||||||
ncaaw_hockey_enabled = self.config.get('ncaaw_hockey_scoreboard', {}).get('enabled', False)
|
ncaaw_hockey_enabled = self.config.get('ncaaw_hockey_scoreboard', {}).get('enabled', False)
|
||||||
|
|
||||||
update_mode('nhl_live', getattr(self, 'nhl_live', None), self.nhl_live_priority, nhl_enabled)
|
update_mode('nhl_live', getattr(self, 'nhl_live', None), self.nhl_live_priority, nhl_enabled)
|
||||||
update_mode('nba_live', getattr(self, 'nba_live', None), self.nba_live_priority, nba_enabled)
|
update_mode('nba_live', getattr(self, 'nba_live', None), self.nba_live_priority, nba_enabled)
|
||||||
|
update_mode('wnba_live', getattr(self, 'wnba_live', None), self.wnba_live_priority, wnba_enabled)
|
||||||
update_mode('mlb_live', getattr(self, 'mlb_live', None), self.mlb_live_priority, mlb_enabled)
|
update_mode('mlb_live', getattr(self, 'mlb_live', None), self.mlb_live_priority, mlb_enabled)
|
||||||
update_mode('milb_live', getattr(self, 'milb_live', None), self.milb_live_priority, milb_enabled)
|
update_mode('milb_live', getattr(self, 'milb_live', None), self.milb_live_priority, milb_enabled)
|
||||||
update_mode('soccer_live', getattr(self, 'soccer_live', None), self.soccer_live_priority, soccer_enabled)
|
update_mode('soccer_live', getattr(self, 'soccer_live', None), self.soccer_live_priority, soccer_enabled)
|
||||||
@@ -1050,6 +1074,7 @@ class DisplayController:
|
|||||||
update_mode('ncaa_fb_live', getattr(self, 'ncaa_fb_live', None), self.ncaa_fb_live_priority, ncaa_fb_enabled)
|
update_mode('ncaa_fb_live', getattr(self, 'ncaa_fb_live', None), self.ncaa_fb_live_priority, ncaa_fb_enabled)
|
||||||
update_mode('ncaa_baseball_live', getattr(self, 'ncaa_baseball_live', None), self.ncaa_baseball_live_priority, ncaa_baseball_enabled)
|
update_mode('ncaa_baseball_live', getattr(self, 'ncaa_baseball_live', None), self.ncaa_baseball_live_priority, ncaa_baseball_enabled)
|
||||||
update_mode('ncaam_basketball_live', getattr(self, 'ncaam_basketball_live', None), self.ncaam_basketball_live_priority, ncaam_basketball_enabled)
|
update_mode('ncaam_basketball_live', getattr(self, 'ncaam_basketball_live', None), self.ncaam_basketball_live_priority, ncaam_basketball_enabled)
|
||||||
|
update_mode('ncaaw_basketball_live', getattr(self, 'ncaaw_basketball_live', None), self.ncaaw_basketball_live_priority, ncaaw_basketball_enabled)
|
||||||
update_mode('ncaam_hockey_live', getattr(self, 'ncaam_hockey_live', None), self.ncaam_hockey_live_priority, ncaam_hockey_enabled)
|
update_mode('ncaam_hockey_live', getattr(self, 'ncaam_hockey_live', None), self.ncaam_hockey_live_priority, ncaam_hockey_enabled)
|
||||||
update_mode('ncaaw_hockey_live', getattr(self, 'ncaaw_hockey_live', None), self.ncaaw_hockey_live_priority, ncaaw_hockey_enabled)
|
update_mode('ncaaw_hockey_live', getattr(self, 'ncaaw_hockey_live', None), self.ncaaw_hockey_live_priority, ncaaw_hockey_enabled)
|
||||||
|
|
||||||
@@ -1094,6 +1119,7 @@ class DisplayController:
|
|||||||
for sport, attr, priority in [
|
for sport, attr, priority in [
|
||||||
('nhl', 'nhl_live', self.nhl_live_priority),
|
('nhl', 'nhl_live', self.nhl_live_priority),
|
||||||
('nba', 'nba_live', self.nba_live_priority),
|
('nba', 'nba_live', self.nba_live_priority),
|
||||||
|
('wnba', 'wnba_live', self.wnba_live_priority),
|
||||||
('mlb', 'mlb_live', self.mlb_live_priority),
|
('mlb', 'mlb_live', self.mlb_live_priority),
|
||||||
('milb', 'milb_live', self.milb_live_priority),
|
('milb', 'milb_live', self.milb_live_priority),
|
||||||
('soccer', 'soccer_live', self.soccer_live_priority),
|
('soccer', 'soccer_live', self.soccer_live_priority),
|
||||||
@@ -1101,6 +1127,7 @@ class DisplayController:
|
|||||||
('ncaa_fb', 'ncaa_fb_live', self.ncaa_fb_live_priority),
|
('ncaa_fb', 'ncaa_fb_live', self.ncaa_fb_live_priority),
|
||||||
('ncaa_baseball', 'ncaa_baseball_live', self.ncaa_baseball_live_priority),
|
('ncaa_baseball', 'ncaa_baseball_live', self.ncaa_baseball_live_priority),
|
||||||
('ncaam_basketball', 'ncaam_basketball_live', self.ncaam_basketball_live_priority),
|
('ncaam_basketball', 'ncaam_basketball_live', self.ncaam_basketball_live_priority),
|
||||||
|
('ncaaw_basketball', 'ncaaw_basketball_live', self.ncaaw_basketball_live_priority),
|
||||||
('ncaam_hockey', 'ncaam_hockey_live', self.ncaam_hockey_live_priority),
|
('ncaam_hockey', 'ncaam_hockey_live', self.ncaam_hockey_live_priority),
|
||||||
('ncaaw_hockey', 'ncaaw_hockey_live', self.ncaaw_hockey_live_priority)
|
('ncaaw_hockey', 'ncaaw_hockey_live', self.ncaaw_hockey_live_priority)
|
||||||
]:
|
]:
|
||||||
@@ -1264,6 +1291,10 @@ class DisplayController:
|
|||||||
manager_to_display = self.nba_recent
|
manager_to_display = self.nba_recent
|
||||||
elif self.current_display_mode == 'nba_upcoming' and self.nba_upcoming:
|
elif self.current_display_mode == 'nba_upcoming' and self.nba_upcoming:
|
||||||
manager_to_display = self.nba_upcoming
|
manager_to_display = self.nba_upcoming
|
||||||
|
elif self.current_display_mode == 'wnba_recent' and self.wnba_recent:
|
||||||
|
manager_to_display = self.wnba_recent
|
||||||
|
elif self.current_display_mode == 'wnba_upcoming' and self.wnba_upcoming:
|
||||||
|
manager_to_display = self.wnba_upcoming
|
||||||
elif self.current_display_mode == 'nfl_recent' and self.nfl_recent:
|
elif self.current_display_mode == 'nfl_recent' and self.nfl_recent:
|
||||||
manager_to_display = self.nfl_recent
|
manager_to_display = self.nfl_recent
|
||||||
elif self.current_display_mode == 'nfl_upcoming' and self.nfl_upcoming:
|
elif self.current_display_mode == 'nfl_upcoming' and self.nfl_upcoming:
|
||||||
@@ -1280,6 +1311,10 @@ class DisplayController:
|
|||||||
manager_to_display = self.ncaam_basketball_recent
|
manager_to_display = self.ncaam_basketball_recent
|
||||||
elif self.current_display_mode == 'ncaam_basketball_upcoming' and self.ncaam_basketball_upcoming:
|
elif self.current_display_mode == 'ncaam_basketball_upcoming' and self.ncaam_basketball_upcoming:
|
||||||
manager_to_display = self.ncaam_basketball_upcoming
|
manager_to_display = self.ncaam_basketball_upcoming
|
||||||
|
elif self.current_display_mode == 'ncaaw_basketball_recent' and self.ncaaw_basketball_recent:
|
||||||
|
manager_to_display = self.ncaaw_basketball_recent
|
||||||
|
elif self.current_display_mode == 'ncaaw_basketball_upcoming' and self.ncaaw_basketball_upcoming:
|
||||||
|
manager_to_display = self.ncaaw_basketball_upcoming
|
||||||
elif self.current_display_mode == 'mlb_recent' and self.mlb_recent:
|
elif self.current_display_mode == 'mlb_recent' and self.mlb_recent:
|
||||||
manager_to_display = self.mlb_recent
|
manager_to_display = self.mlb_recent
|
||||||
elif self.current_display_mode == 'mlb_upcoming' and self.mlb_upcoming:
|
elif self.current_display_mode == 'mlb_upcoming' and self.mlb_upcoming:
|
||||||
@@ -1298,6 +1333,8 @@ class DisplayController:
|
|||||||
manager_to_display = self.nhl_live
|
manager_to_display = self.nhl_live
|
||||||
elif self.current_display_mode == 'nba_live' and self.nba_live:
|
elif self.current_display_mode == 'nba_live' and self.nba_live:
|
||||||
manager_to_display = self.nba_live
|
manager_to_display = self.nba_live
|
||||||
|
elif self.current_display_mode == 'wnba_live' and self.wnba_live:
|
||||||
|
manager_to_display = self.wnba_live
|
||||||
elif self.current_display_mode == 'nfl_live' and self.nfl_live:
|
elif self.current_display_mode == 'nfl_live' and self.nfl_live:
|
||||||
manager_to_display = self.nfl_live
|
manager_to_display = self.nfl_live
|
||||||
elif self.current_display_mode == 'ncaa_fb_live' and self.ncaa_fb_live:
|
elif self.current_display_mode == 'ncaa_fb_live' and self.ncaa_fb_live:
|
||||||
@@ -1306,6 +1343,8 @@ class DisplayController:
|
|||||||
manager_to_display = self.ncaa_baseball_live
|
manager_to_display = self.ncaa_baseball_live
|
||||||
elif self.current_display_mode == 'ncaam_basketball_live' and self.ncaam_basketball_live:
|
elif self.current_display_mode == 'ncaam_basketball_live' and self.ncaam_basketball_live:
|
||||||
manager_to_display = self.ncaam_basketball_live
|
manager_to_display = self.ncaam_basketball_live
|
||||||
|
elif self.current_display_mode == 'ncaaw_basketball_live' and self.ncaaw_basketball_live:
|
||||||
|
manager_to_display = self.ncaaw_basketball_live
|
||||||
elif self.current_display_mode == 'ncaam_hockey_live' and self.ncaam_hockey_live:
|
elif self.current_display_mode == 'ncaam_hockey_live' and self.ncaam_hockey_live:
|
||||||
manager_to_display = self.ncaam_hockey_live
|
manager_to_display = self.ncaam_hockey_live
|
||||||
elif self.current_display_mode == 'ncaam_hockey_recent' and self.ncaam_hockey_recent:
|
elif self.current_display_mode == 'ncaam_hockey_recent' and self.ncaam_hockey_recent:
|
||||||
@@ -1383,6 +1422,10 @@ class DisplayController:
|
|||||||
self.ncaam_basketball_recent.display(force_clear=self.force_clear)
|
self.ncaam_basketball_recent.display(force_clear=self.force_clear)
|
||||||
elif self.current_display_mode == 'ncaam_basketball_upcoming' and self.ncaam_basketball_upcoming:
|
elif self.current_display_mode == 'ncaam_basketball_upcoming' and self.ncaam_basketball_upcoming:
|
||||||
self.ncaam_basketball_upcoming.display(force_clear=self.force_clear)
|
self.ncaam_basketball_upcoming.display(force_clear=self.force_clear)
|
||||||
|
elif self.current_display_mode == 'ncaaw_basketball_recent' and self.ncaaw_basketball_recent:
|
||||||
|
self.ncaaw_basketball_recent.display(force_clear=self.force_clear)
|
||||||
|
elif self.current_display_mode == 'ncaaw_basketball_upcoming' and self.ncaaw_basketball_upcoming:
|
||||||
|
self.ncaaw_basketball_upcoming.display(force_clear=self.force_clear)
|
||||||
elif self.current_display_mode == 'ncaa_baseball_recent' and self.ncaa_baseball_recent:
|
elif self.current_display_mode == 'ncaa_baseball_recent' and self.ncaa_baseball_recent:
|
||||||
self.ncaa_baseball_recent.display(force_clear=self.force_clear)
|
self.ncaa_baseball_recent.display(force_clear=self.force_clear)
|
||||||
elif self.current_display_mode == 'ncaa_baseball_upcoming' and self.ncaa_baseball_upcoming:
|
elif self.current_display_mode == 'ncaa_baseball_upcoming' and self.ncaa_baseball_upcoming:
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class LogoDownloader:
|
|||||||
LOGO_DIRECTORIES = {
|
LOGO_DIRECTORIES = {
|
||||||
'nfl': 'assets/sports/nfl_logos',
|
'nfl': 'assets/sports/nfl_logos',
|
||||||
'nba': 'assets/sports/nba_logos',
|
'nba': 'assets/sports/nba_logos',
|
||||||
|
'wnba': 'assets/sports/wnba_logos',
|
||||||
'mlb': 'assets/sports/mlb_logos',
|
'mlb': 'assets/sports/mlb_logos',
|
||||||
'nhl': 'assets/sports/nhl_logos',
|
'nhl': 'assets/sports/nhl_logos',
|
||||||
# NCAA sports use same directory
|
# NCAA sports use same directory
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
274
src/ncaaw_basketball_managers.py
Normal file
274
src/ncaaw_basketball_managers.py
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from src.base_classes.basketball import Basketball, BasketballLive
|
||||||
|
from src.base_classes.sports import SportsRecent, SportsUpcoming
|
||||||
|
from src.cache_manager import CacheManager
|
||||||
|
from src.display_manager import DisplayManager
|
||||||
|
|
||||||
|
# Import the API counter function from web interface
|
||||||
|
try:
|
||||||
|
from web_interface_v2 import increment_api_counter
|
||||||
|
except ImportError:
|
||||||
|
# Fallback if web interface is not available
|
||||||
|
def increment_api_counter(kind: str, count: int = 1):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
ESPN_NCAAWB_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/basketball/womens-college-basketball/scoreboard"
|
||||||
|
|
||||||
|
|
||||||
|
class BaseNCAAWBasketballManager(Basketball):
|
||||||
|
"""Base class for NCAA WB managers with common functionality."""
|
||||||
|
|
||||||
|
# Class variables for warning tracking
|
||||||
|
_no_data_warning_logged = False
|
||||||
|
_last_warning_time = 0
|
||||||
|
_warning_cooldown = 60 # Only log warnings once per minute
|
||||||
|
_last_log_times = {}
|
||||||
|
_shared_data = None
|
||||||
|
_last_shared_update = 0
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
self.logger = logging.getLogger("NCAAWB") # Changed logger name
|
||||||
|
super().__init__(
|
||||||
|
config=config,
|
||||||
|
display_manager=display_manager,
|
||||||
|
cache_manager=cache_manager,
|
||||||
|
logger=self.logger,
|
||||||
|
sport_key="ncaaw_basketball",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check display modes to determine what data to fetch
|
||||||
|
display_modes = self.mode_config.get("display_modes", {})
|
||||||
|
self.recent_enabled = display_modes.get("ncaaw_basketball_recent", False)
|
||||||
|
self.upcoming_enabled = display_modes.get("ncaaw_basketball_upcoming", False)
|
||||||
|
self.live_enabled = display_modes.get("ncaaw_basketball_live", False)
|
||||||
|
|
||||||
|
self.logger.info(
|
||||||
|
f"Initialized NCAA Womens Basketball manager with display dimensions: {self.display_width}x{self.display_height}"
|
||||||
|
)
|
||||||
|
self.logger.info(f"Logo directory: {self.logo_dir}")
|
||||||
|
self.logger.info(
|
||||||
|
f"Display modes - Recent: {self.recent_enabled}, Upcoming: {self.upcoming_enabled}, Live: {self.live_enabled}"
|
||||||
|
)
|
||||||
|
self.league = "womens-college-basketball"
|
||||||
|
|
||||||
|
def _fetch_ncaaw_basketball_api_data(
|
||||||
|
self, use_cache: bool = True
|
||||||
|
) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
Fetches the full season schedule for NCAA Womens Basketball using background threading.
|
||||||
|
Returns cached data immediately if available, otherwise starts background fetch.
|
||||||
|
"""
|
||||||
|
now = datetime.now(pytz.utc)
|
||||||
|
season_year = now.year
|
||||||
|
cache_key = f"{self.sport_key}_schedule_{season_year}"
|
||||||
|
|
||||||
|
# Check cache first
|
||||||
|
if use_cache:
|
||||||
|
cached_data = self.cache_manager.get(cache_key)
|
||||||
|
if cached_data:
|
||||||
|
# Validate cached data structure
|
||||||
|
if isinstance(cached_data, dict) and "events" in cached_data:
|
||||||
|
self.logger.info(f"Using cached schedule for {season_year}")
|
||||||
|
return cached_data
|
||||||
|
elif isinstance(cached_data, list):
|
||||||
|
# Handle old cache format (list of events)
|
||||||
|
self.logger.info(
|
||||||
|
f"Using cached schedule for {season_year} (legacy format)"
|
||||||
|
)
|
||||||
|
return {"events": cached_data}
|
||||||
|
else:
|
||||||
|
self.logger.warning(
|
||||||
|
f"Invalid cached data format for {season_year}: {type(cached_data)}"
|
||||||
|
)
|
||||||
|
# Clear invalid cache
|
||||||
|
self.cache_manager.clear_cache(cache_key)
|
||||||
|
|
||||||
|
# If background service is disabled, fall back to synchronous fetch
|
||||||
|
if not self.background_enabled or not self.background_service:
|
||||||
|
return self._fetch_ncaaw_basketball_api_data_sync(use_cache)
|
||||||
|
|
||||||
|
# Start background fetch
|
||||||
|
self.logger.info(
|
||||||
|
f"Starting background fetch for {season_year} season schedule..."
|
||||||
|
)
|
||||||
|
|
||||||
|
def fetch_callback(result):
|
||||||
|
"""Callback when background fetch completes."""
|
||||||
|
if result.success:
|
||||||
|
self.logger.info(
|
||||||
|
f"Background fetch completed for {season_year}: {len(result.data.get('events'))} events"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.logger.error(
|
||||||
|
f"Background fetch failed for {season_year}: {result.error}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clean up request tracking
|
||||||
|
if season_year in self.background_fetch_requests:
|
||||||
|
del self.background_fetch_requests[season_year]
|
||||||
|
|
||||||
|
# Get background service configuration
|
||||||
|
background_config = self.mode_config.get("background_service", {})
|
||||||
|
timeout = background_config.get("request_timeout", 30)
|
||||||
|
max_retries = background_config.get("max_retries", 3)
|
||||||
|
priority = background_config.get("priority", 2)
|
||||||
|
|
||||||
|
# Submit background fetch request
|
||||||
|
request_id = self.background_service.submit_fetch_request(
|
||||||
|
sport="ncaa_womens_basketball",
|
||||||
|
year=season_year,
|
||||||
|
url=ESPN_NCAAWB_SCOREBOARD_URL,
|
||||||
|
cache_key=cache_key,
|
||||||
|
params={"dates": season_year, "limit": 1000},
|
||||||
|
headers=self.headers,
|
||||||
|
timeout=timeout,
|
||||||
|
max_retries=max_retries,
|
||||||
|
priority=priority,
|
||||||
|
callback=fetch_callback,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Track the request
|
||||||
|
self.background_fetch_requests[season_year] = request_id
|
||||||
|
|
||||||
|
# For immediate response, try to get partial data
|
||||||
|
partial_data = self._get_weeks_data()
|
||||||
|
if partial_data:
|
||||||
|
return partial_data
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _fetch_ncaaw_basketball_api_data_sync(
|
||||||
|
self, use_cache: bool = True
|
||||||
|
) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
Synchronous fallback for fetching NFL data when background service is disabled.
|
||||||
|
"""
|
||||||
|
now = datetime.now(pytz.utc)
|
||||||
|
current_year = now.year
|
||||||
|
cache_key = f"ncaa_womens_basketball_schedule_{current_year}"
|
||||||
|
|
||||||
|
self.logger.info(
|
||||||
|
f"Fetching full {current_year} season schedule from ESPN API (sync mode)..."
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
response = self.session.get(
|
||||||
|
ESPN_NCAAWB_SCOREBOARD_URL,
|
||||||
|
params={"dates": current_year, "limit": 1000},
|
||||||
|
headers=self.headers,
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
events = data.get("events", [])
|
||||||
|
|
||||||
|
if use_cache:
|
||||||
|
self.cache_manager.set(cache_key, events)
|
||||||
|
|
||||||
|
self.logger.info(
|
||||||
|
f"Successfully fetched {len(events)} events for the {current_year} season."
|
||||||
|
)
|
||||||
|
return {"events": events}
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
self.logger.error(f"API error fetching full schedule: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _fetch_data(self) -> Optional[Dict]:
|
||||||
|
"""Fetch data using shared data mechanism or direct fetch for live."""
|
||||||
|
if isinstance(self, NCAAWBasketballLiveManager):
|
||||||
|
# Live games should fetch only current games, not entire season
|
||||||
|
return self._fetch_todays_games()
|
||||||
|
else:
|
||||||
|
# Recent and Upcoming managers should use cached season data
|
||||||
|
return self._fetch_ncaaw_basketball_api_data(use_cache=True)
|
||||||
|
|
||||||
|
|
||||||
|
class NCAAWBasketballLiveManager(BaseNCAAWBasketballManager, BasketballLive):
|
||||||
|
"""Manager for live NCAA WB games."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager)
|
||||||
|
self.logger = logging.getLogger(
|
||||||
|
"NCAAWBasketballLiveManager"
|
||||||
|
) # Changed logger name
|
||||||
|
|
||||||
|
if self.test_mode:
|
||||||
|
# More detailed test game for NCAA WB
|
||||||
|
self.current_game = {
|
||||||
|
"id": "test001",
|
||||||
|
"home_abbr": "AUB",
|
||||||
|
"home_id": "123",
|
||||||
|
"away_abbr": "GT",
|
||||||
|
"away_id": "asdf",
|
||||||
|
"home_score": "21",
|
||||||
|
"away_score": "17",
|
||||||
|
"period": 3,
|
||||||
|
"period_text": "Q3",
|
||||||
|
"clock": "5:24",
|
||||||
|
"home_logo_path": Path(self.logo_dir, "AUB.png"),
|
||||||
|
"away_logo_path": Path(self.logo_dir, "GT.png"),
|
||||||
|
"is_live": True,
|
||||||
|
"is_final": False,
|
||||||
|
"is_upcoming": False,
|
||||||
|
"is_halftime": False,
|
||||||
|
}
|
||||||
|
self.live_games = [self.current_game]
|
||||||
|
self.logger.info(
|
||||||
|
"Initialized NCAAWBasketballLiveManager with test game: GT vs AUB"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.logger.info(" Initialized NCAAWBasketballLiveManager in live mode")
|
||||||
|
|
||||||
|
|
||||||
|
class NCAAWBasketballRecentManager(BaseNCAAWBasketballManager, SportsRecent):
|
||||||
|
"""Manager for recently completed NCAA WB games."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager)
|
||||||
|
self.logger = logging.getLogger(
|
||||||
|
"NCAAWBasketballRecentManager"
|
||||||
|
) # Changed logger name
|
||||||
|
self.logger.info(
|
||||||
|
f"Initialized NCAAWBasketballRecentManager with {len(self.favorite_teams)} favorite teams"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NCAAWBasketballUpcomingManager(BaseNCAAWBasketballManager, SportsUpcoming):
|
||||||
|
"""Manager for upcoming NCAA WB games."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager)
|
||||||
|
self.logger = logging.getLogger(
|
||||||
|
"NCAAWBasketballUpcomingManager"
|
||||||
|
) # Changed logger name
|
||||||
|
self.logger.info(
|
||||||
|
f"Initialized NCAAWBasketballUpcomingManager with {len(self.favorite_teams)} favorite teams"
|
||||||
|
)
|
||||||
@@ -28,9 +28,6 @@ class BaseNFLManager(Football): # Renamed class
|
|||||||
self.logger = logging.getLogger('NFL') # Changed logger name
|
self.logger = logging.getLogger('NFL') # Changed logger name
|
||||||
super().__init__(config=config, display_manager=display_manager, cache_manager=cache_manager, logger=self.logger, sport_key="nfl")
|
super().__init__(config=config, display_manager=display_manager, cache_manager=cache_manager, logger=self.logger, sport_key="nfl")
|
||||||
|
|
||||||
# Configuration is already set in base class
|
|
||||||
# self.logo_dir and self.update_interval are already configured
|
|
||||||
|
|
||||||
# Check display modes to determine what data to fetch
|
# Check display modes to determine what data to fetch
|
||||||
display_modes = self.mode_config.get("display_modes", {})
|
display_modes = self.mode_config.get("display_modes", {})
|
||||||
self.recent_enabled = display_modes.get("nfl_recent", False)
|
self.recent_enabled = display_modes.get("nfl_recent", False)
|
||||||
|
|||||||
304
src/wnba_managers.py
Normal file
304
src/wnba_managers.py
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from src.base_classes.basketball import Basketball, BasketballLive
|
||||||
|
from src.base_classes.sports import SportsRecent, SportsUpcoming
|
||||||
|
from src.cache_manager import CacheManager
|
||||||
|
from src.display_manager import DisplayManager
|
||||||
|
|
||||||
|
# Import the API counter function from web interface
|
||||||
|
try:
|
||||||
|
from web_interface_v2 import increment_api_counter
|
||||||
|
except ImportError:
|
||||||
|
# Fallback if web interface is not available
|
||||||
|
def increment_api_counter(kind: str, count: int = 1):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
ESPN_WNBA_SCOREBOARD_URL = (
|
||||||
|
"https://site.api.espn.com/apis/site/v2/sports/basketball/wnba/scoreboard"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseWNBAManager(Basketball):
|
||||||
|
"""Base class for WNBA managers with common functionality."""
|
||||||
|
|
||||||
|
# Class variables for warning tracking
|
||||||
|
_no_data_warning_logged = False
|
||||||
|
_last_warning_time = 0
|
||||||
|
_warning_cooldown = 60 # Only log warnings once per minute
|
||||||
|
_last_log_times = {}
|
||||||
|
_shared_data = None
|
||||||
|
_last_shared_update = 0
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
self.logger = logging.getLogger("WNBA") # Changed logger name
|
||||||
|
super().__init__(
|
||||||
|
config=config,
|
||||||
|
display_manager=display_manager,
|
||||||
|
cache_manager=cache_manager,
|
||||||
|
logger=self.logger,
|
||||||
|
sport_key="wnba",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check display modes to determine what data to fetch
|
||||||
|
display_modes = self.mode_config.get("display_modes", {})
|
||||||
|
self.recent_enabled = display_modes.get("wnba_recent", False)
|
||||||
|
self.upcoming_enabled = display_modes.get("wnba_upcoming", False)
|
||||||
|
self.live_enabled = display_modes.get("wnba_live", False)
|
||||||
|
|
||||||
|
self.logger.info(
|
||||||
|
f"Initialized WNBA manager with display dimensions: {self.display_width}x{self.display_height}"
|
||||||
|
)
|
||||||
|
self.logger.info(f"Logo directory: {self.logo_dir}")
|
||||||
|
self.logger.info(
|
||||||
|
f"Display modes - Recent: {self.recent_enabled}, Upcoming: {self.upcoming_enabled}, Live: {self.live_enabled}"
|
||||||
|
)
|
||||||
|
self.league = "wnba"
|
||||||
|
|
||||||
|
def _fetch_wnba_api_data(self, use_cache: bool = True) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
Fetches the full season schedule for WNBA using background threading.
|
||||||
|
Returns cached data immediately if available, otherwise starts background fetch.
|
||||||
|
"""
|
||||||
|
now = datetime.now(pytz.utc)
|
||||||
|
season_year = now.year
|
||||||
|
if now.month < 2:
|
||||||
|
season_year = now.year - 1
|
||||||
|
datestring = f"{season_year}0401-{season_year+1}1101"
|
||||||
|
cache_key = f"{self.sport_key}_schedule_{season_year}"
|
||||||
|
|
||||||
|
# Check cache first
|
||||||
|
if use_cache:
|
||||||
|
cached_data = self.cache_manager.get(cache_key)
|
||||||
|
if cached_data:
|
||||||
|
# Validate cached data structure
|
||||||
|
if isinstance(cached_data, dict) and "events" in cached_data:
|
||||||
|
self.logger.info(f"Using cached schedule for {season_year}")
|
||||||
|
return cached_data
|
||||||
|
elif isinstance(cached_data, list):
|
||||||
|
# Handle old cache format (list of events)
|
||||||
|
self.logger.info(
|
||||||
|
f"Using cached schedule for {season_year} (legacy format)"
|
||||||
|
)
|
||||||
|
return {"events": cached_data}
|
||||||
|
else:
|
||||||
|
self.logger.warning(
|
||||||
|
f"Invalid cached data format for {season_year}: {type(cached_data)}"
|
||||||
|
)
|
||||||
|
# Clear invalid cache
|
||||||
|
self.cache_manager.clear_cache(cache_key)
|
||||||
|
|
||||||
|
# If background service is disabled, fall back to synchronous fetch
|
||||||
|
if not self.background_enabled or not self.background_service:
|
||||||
|
return self._fetch_wnba_api_data_sync(use_cache)
|
||||||
|
|
||||||
|
# Start background fetch
|
||||||
|
self.logger.info(
|
||||||
|
f"Starting background fetch for {season_year} season schedule..."
|
||||||
|
)
|
||||||
|
|
||||||
|
def fetch_callback(result):
|
||||||
|
"""Callback when background fetch completes."""
|
||||||
|
if result.success:
|
||||||
|
self.logger.info(
|
||||||
|
f"Background fetch completed for {season_year}: {len(result.data.get('events'))} events"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.logger.error(
|
||||||
|
f"Background fetch failed for {season_year}: {result.error}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clean up request tracking
|
||||||
|
if season_year in self.background_fetch_requests:
|
||||||
|
del self.background_fetch_requests[season_year]
|
||||||
|
|
||||||
|
# Get background service configuration
|
||||||
|
background_config = self.mode_config.get("background_service", {})
|
||||||
|
timeout = background_config.get("request_timeout", 30)
|
||||||
|
max_retries = background_config.get("max_retries", 3)
|
||||||
|
priority = background_config.get("priority", 2)
|
||||||
|
|
||||||
|
# Submit background fetch request
|
||||||
|
request_id = self.background_service.submit_fetch_request(
|
||||||
|
sport="nba",
|
||||||
|
year=season_year,
|
||||||
|
url=ESPN_WNBA_SCOREBOARD_URL,
|
||||||
|
cache_key=cache_key,
|
||||||
|
params={"dates": datestring, "limit": 1000},
|
||||||
|
headers=self.headers,
|
||||||
|
timeout=timeout,
|
||||||
|
max_retries=max_retries,
|
||||||
|
priority=priority,
|
||||||
|
callback=fetch_callback,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Track the request
|
||||||
|
self.background_fetch_requests[season_year] = request_id
|
||||||
|
|
||||||
|
# For immediate response, try to get partial data
|
||||||
|
partial_data = self._get_weeks_data()
|
||||||
|
if partial_data:
|
||||||
|
return partial_data
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _fetch_wnba_api_data_sync(self, use_cache: bool = True) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
Synchronous fallback for fetching WNBA data when background service is disabled.
|
||||||
|
"""
|
||||||
|
now = datetime.now(pytz.utc)
|
||||||
|
current_year = now.year
|
||||||
|
cache_key = f"nba_schedule_{current_year}"
|
||||||
|
|
||||||
|
self.logger.info(
|
||||||
|
f"Fetching full {current_year} season schedule from ESPN API (sync mode)..."
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
response = self.session.get(
|
||||||
|
ESPN_WNBA_SCOREBOARD_URL,
|
||||||
|
params={"dates": current_year, "limit": 1000},
|
||||||
|
headers=self.headers,
|
||||||
|
timeout=15,
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
events = data.get("events", [])
|
||||||
|
|
||||||
|
if use_cache:
|
||||||
|
self.cache_manager.set(cache_key, events)
|
||||||
|
|
||||||
|
self.logger.info(
|
||||||
|
f"Successfully fetched {len(events)} events for the {current_year} season."
|
||||||
|
)
|
||||||
|
return {"events": events}
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
self.logger.error(f"API error fetching full schedule: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _fetch_data(self) -> Optional[Dict]:
|
||||||
|
"""Fetch data using shared data mechanism or direct fetch for live."""
|
||||||
|
if isinstance(self, WNBALiveManager):
|
||||||
|
# Live games should fetch only current games, not entire season
|
||||||
|
return self._fetch_todays_games()
|
||||||
|
else:
|
||||||
|
# Recent and Upcoming managers should use cached season data
|
||||||
|
return self._fetch_wnba_api_data(use_cache=True)
|
||||||
|
|
||||||
|
|
||||||
|
class WNBALiveManager(BaseWNBAManager, BasketballLive):
|
||||||
|
"""Manager for live NBA games."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager)
|
||||||
|
self.logger = logging.getLogger("WNBALiveManager") # Changed logger name
|
||||||
|
|
||||||
|
if self.test_mode:
|
||||||
|
# More detailed test game for NBA
|
||||||
|
self.current_game = {
|
||||||
|
"id": "test001",
|
||||||
|
"home_abbr": "CHI",
|
||||||
|
"home_id": "123",
|
||||||
|
"away_abbr": "ATL",
|
||||||
|
"away_id": "asdf",
|
||||||
|
"home_score": "21",
|
||||||
|
"away_score": "17",
|
||||||
|
"period": 3,
|
||||||
|
"period_text": "Q3",
|
||||||
|
"clock": "5:24",
|
||||||
|
"home_logo_path": Path(self.logo_dir, "CHI.png"),
|
||||||
|
"away_logo_path": Path(self.logo_dir, "ATL.png"),
|
||||||
|
"is_live": True,
|
||||||
|
"is_final": False,
|
||||||
|
"is_upcoming": False,
|
||||||
|
"is_halftime": False,
|
||||||
|
}
|
||||||
|
self.live_games = [self.current_game]
|
||||||
|
self.logger.info("Initialized WNBALiveManager with test game: BUF vs KC")
|
||||||
|
else:
|
||||||
|
self.logger.info(" Initialized WNBALiveManager in live mode")
|
||||||
|
|
||||||
|
|
||||||
|
class WNBARecentManager(BaseWNBAManager, SportsRecent):
|
||||||
|
"""Manager for recently completed WNBA games."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager)
|
||||||
|
self.logger = logging.getLogger("WNBARecentManager") # Changed logger name
|
||||||
|
self.logger.info(
|
||||||
|
f"Initialized WNBARecentManager with {len(self.favorite_teams)} favorite teams"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WNBAUpcomingManager(BaseWNBAManager, SportsUpcoming):
|
||||||
|
"""Manager for upcoming WNBA games."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config: Dict[str, Any],
|
||||||
|
display_manager: DisplayManager,
|
||||||
|
cache_manager: CacheManager,
|
||||||
|
):
|
||||||
|
super().__init__(config, display_manager, cache_manager)
|
||||||
|
self.logger = logging.getLogger("WNBAUpcomingManager") # Changed logger name
|
||||||
|
self.logger.info(
|
||||||
|
f"Initialized WNBAUpcomingManager with {len(self.favorite_teams)} favorite teams"
|
||||||
|
)
|
||||||
|
|
||||||
|
"""Display upcoming games."""
|
||||||
|
if not self.upcoming_games:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
current_time = time.time()
|
||||||
|
|
||||||
|
# Check if it's time to switch games
|
||||||
|
if (
|
||||||
|
len(self.upcoming_games) > 1
|
||||||
|
and current_time - self.last_game_switch >= self.game_display_duration
|
||||||
|
):
|
||||||
|
# Move to next game
|
||||||
|
self.current_game_index = (self.current_game_index + 1) % len(
|
||||||
|
self.upcoming_games
|
||||||
|
)
|
||||||
|
self.current_game = self.upcoming_games[self.current_game_index]
|
||||||
|
self.last_game_switch = current_time
|
||||||
|
force_clear = True
|
||||||
|
|
||||||
|
# Log team switching
|
||||||
|
if self.current_game:
|
||||||
|
away_abbr = self.current_game.get("away_abbr", "UNK")
|
||||||
|
home_abbr = self.current_game.get("home_abbr", "UNK")
|
||||||
|
self.logger.info(
|
||||||
|
f"[NBA Upcoming] Showing {away_abbr} vs {home_abbr}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Draw the scorebug layout
|
||||||
|
self._draw_scorebug_layout(self.current_game, force_clear)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(
|
||||||
|
f"[NBA] Error displaying upcoming game: {e}", exc_info=True
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user