mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-11 21:33:00 +00:00
milb upcoming game debug logging
This commit is contained in:
25
README.md
25
README.md
@@ -1033,6 +1033,31 @@ The LEDMatrix system includes a comprehensive scoreboard display system with thr
|
|||||||
- Automatic game switching
|
- Automatic game switching
|
||||||
- Built-in caching to reduce API calls
|
- Built-in caching to reduce API calls
|
||||||
- Test mode for development
|
- Test mode for development
|
||||||
|
## API Usage Tracking
|
||||||
|
|
||||||
|
The LEDMatrix system includes a built-in API usage counter that tracks API calls made by various managers in a 24-hour rolling window. This feature helps monitor API usage and ensure compliance with rate limits.
|
||||||
|
|
||||||
|
### API Counter Features
|
||||||
|
- **Real-time Tracking**: Counts API calls for weather, stocks, sports, and news data
|
||||||
|
- **24-hour Window**: Rolling window that resets every 24 hours
|
||||||
|
- **Web Interface Integration**: View current usage in the Overview tab of the web interface
|
||||||
|
- **Forecast Display**: Shows predicted API usage based on current configuration
|
||||||
|
- **Automatic Reset**: Counters automatically reset when the 24-hour window expires
|
||||||
|
|
||||||
|
### Tracked API Calls
|
||||||
|
- **Weather**: OpenWeatherMap API calls (geocoding + weather data)
|
||||||
|
- **Stocks**: Yahoo Finance API calls for stock and crypto data
|
||||||
|
- **Sports**: ESPN API calls for various sports leagues (NHL, NBA, MLB, NFL, etc.)
|
||||||
|
- **News**: RSS feed and news API calls
|
||||||
|
|
||||||
|
### Accessing API Metrics
|
||||||
|
1. Open the web interface in your browser
|
||||||
|
2. Navigate to the **Overview** tab
|
||||||
|
3. Scroll down to the "API Calls (24h window)" section
|
||||||
|
4. Click "Refresh API Metrics" to update the display
|
||||||
|
|
||||||
|
The counter shows both actual usage and forecasted usage based on your current configuration settings.
|
||||||
|
|
||||||
## Caching System
|
## Caching System
|
||||||
|
|
||||||
The LEDMatrix system includes a robust caching mechanism to optimize API calls and reduce network traffic:
|
The LEDMatrix system includes a robust caching mechanism to optimize API calls and reduce network traffic:
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ from requests.adapters import HTTPAdapter
|
|||||||
from urllib3.util.retry import Retry
|
from urllib3.util.retry import Retry
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
|
# Import API counter function
|
||||||
|
try:
|
||||||
|
from web_interface_v2 import increment_api_counter
|
||||||
|
except ImportError:
|
||||||
|
def increment_api_counter(kind: str, count: int = 1):
|
||||||
|
pass
|
||||||
|
|
||||||
# Get logger
|
# Get logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -248,6 +255,8 @@ class BaseMiLBManager:
|
|||||||
draw = ImageDraw.Draw(image)
|
draw = ImageDraw.Draw(image)
|
||||||
|
|
||||||
# For upcoming games, show date and time stacked in the center
|
# For upcoming games, show date and time stacked in the center
|
||||||
|
self.logger.debug(f"[MiLB] Game status: {game_data.get('status')}, status_state: {game_data.get('status_state')}")
|
||||||
|
self.logger.debug(f"[MiLB] Full game data: {game_data}")
|
||||||
if game_data['status'] == 'status_scheduled':
|
if game_data['status'] == 'status_scheduled':
|
||||||
# Ensure game_time_str is defined before use
|
# Ensure game_time_str is defined before use
|
||||||
game_time_str = game_data.get('start_time', '')
|
game_time_str = game_data.get('start_time', '')
|
||||||
@@ -261,48 +270,72 @@ class BaseMiLBManager:
|
|||||||
# Draw on the current image
|
# Draw on the current image
|
||||||
self.display_manager.draw = draw
|
self.display_manager.draw = draw
|
||||||
self.display_manager._draw_bdf_text(status_text, status_x, status_y, color=(255, 255, 255), font=self.display_manager.calendar_font)
|
self.display_manager._draw_bdf_text(status_text, status_x, status_y, color=(255, 255, 255), font=self.display_manager.calendar_font)
|
||||||
# Update the display
|
|
||||||
self.display_manager.update_display()
|
|
||||||
|
|
||||||
if not game_time_str or 'TBD' in game_time_str:
|
if not game_time_str or 'TBD' in game_time_str:
|
||||||
game_date_str = "TBD"
|
game_date_str = "TBD"
|
||||||
game_time_formatted_str = ""
|
game_time_formatted_str = ""
|
||||||
|
self.logger.debug(f"[MiLB] Game time is TBD or empty: {game_time_str}")
|
||||||
else:
|
else:
|
||||||
game_time = datetime.fromisoformat(game_time_str.replace('Z', '+00:00'))
|
self.logger.debug(f"[MiLB] Processing game time: {game_time_str}")
|
||||||
timezone_str = self.config.get('timezone', 'UTC')
|
|
||||||
try:
|
try:
|
||||||
tz = pytz.timezone(timezone_str)
|
game_time = datetime.fromisoformat(game_time_str.replace('Z', '+00:00'))
|
||||||
except pytz.exceptions.UnknownTimeZoneError:
|
timezone_str = self.config.get('timezone', 'UTC')
|
||||||
logger.warning(f"Unknown timezone: {timezone_str}, falling back to UTC")
|
try:
|
||||||
tz = pytz.UTC
|
tz = pytz.timezone(timezone_str)
|
||||||
if game_time.tzinfo is None:
|
except pytz.exceptions.UnknownTimeZoneError:
|
||||||
game_time = game_time.replace(tzinfo=pytz.UTC)
|
logger.warning(f"Unknown timezone: {timezone_str}, falling back to UTC")
|
||||||
local_time = game_time.astimezone(tz)
|
tz = pytz.UTC
|
||||||
|
if game_time.tzinfo is None:
|
||||||
# Check date format from config
|
game_time = game_time.replace(tzinfo=pytz.UTC)
|
||||||
use_short_date_format = self.config.get('display', {}).get('use_short_date_format', False)
|
local_time = game_time.astimezone(tz)
|
||||||
if use_short_date_format:
|
|
||||||
game_date_str = local_time.strftime("%-m/%-d")
|
self.logger.debug(f"[MiLB] Local time: {local_time}")
|
||||||
else:
|
|
||||||
game_date_str = self.display_manager.format_date_with_ordinal(local_time)
|
# Check date format from config
|
||||||
|
use_short_date_format = self.config.get('display', {}).get('use_short_date_format', False)
|
||||||
|
if use_short_date_format:
|
||||||
|
game_date_str = local_time.strftime("%-m/%-d")
|
||||||
|
else:
|
||||||
|
game_date_str = self.display_manager.format_date_with_ordinal(local_time)
|
||||||
|
|
||||||
game_time_formatted_str = self._format_game_time(game_data['start_time'])
|
game_time_formatted_str = self._format_game_time(game_data['start_time'])
|
||||||
|
|
||||||
|
self.logger.debug(f"[MiLB] Formatted date: {game_date_str}, time: {game_time_formatted_str}")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"[MiLB] Error processing game time: {e}")
|
||||||
|
game_date_str = "TBD"
|
||||||
|
game_time_formatted_str = "TBD"
|
||||||
|
|
||||||
# Draw date and time using NHL-style fonts
|
# Draw date and time using NHL-style fonts
|
||||||
date_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
|
try:
|
||||||
time_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
|
date_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
|
||||||
|
time_font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
|
||||||
|
self.logger.debug(f"[MiLB] Fonts loaded successfully")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"[MiLB] Failed to load fonts: {e}")
|
||||||
|
# Fallback to default font
|
||||||
|
date_font = ImageFont.load_default()
|
||||||
|
time_font = ImageFont.load_default()
|
||||||
|
|
||||||
# Draw date in center
|
# Draw date in center
|
||||||
date_width = draw.textlength(game_date_str, font=date_font)
|
date_width = draw.textlength(game_date_str, font=date_font)
|
||||||
date_x = (width - date_width) // 2
|
date_x = (width - date_width) // 2
|
||||||
date_y = (height - date_font.size) // 2 - 3
|
date_y = (height - date_font.size) // 2 - 3
|
||||||
|
self.logger.debug(f"[MiLB] Drawing date '{game_date_str}' at ({date_x}, {date_y})")
|
||||||
self._draw_text_with_outline(draw, game_date_str, (date_x, date_y), date_font)
|
self._draw_text_with_outline(draw, game_date_str, (date_x, date_y), date_font)
|
||||||
|
|
||||||
|
# Draw a simple test rectangle to verify drawing is working
|
||||||
|
draw.rectangle([date_x-2, date_y-2, date_x+date_width+2, date_y+date_font.size+2], outline=(255, 0, 0))
|
||||||
|
|
||||||
# Draw time below date
|
# Draw time below date
|
||||||
time_width = draw.textlength(game_time_formatted_str, font=time_font)
|
time_width = draw.textlength(game_time_formatted_str, font=time_font)
|
||||||
time_x = (width - time_width) // 2
|
time_x = (width - time_width) // 2
|
||||||
time_y = date_y + 10
|
time_y = date_y + 10
|
||||||
|
self.logger.debug(f"[MiLB] Drawing time '{game_time_formatted_str}' at ({time_x}, {time_y})")
|
||||||
self._draw_text_with_outline(draw, game_time_formatted_str, (time_x, time_y), time_font)
|
self._draw_text_with_outline(draw, game_time_formatted_str, (time_x, time_y), time_font)
|
||||||
|
|
||||||
|
# Draw a simple test rectangle to verify drawing is working
|
||||||
|
draw.rectangle([time_x-2, time_y-2, time_x+time_width+2, time_y+time_font.size+2], outline=(0, 255, 0))
|
||||||
|
|
||||||
# For recent/final games, show scores and status
|
# For recent/final games, show scores and status
|
||||||
elif game_data['status'] in ['status_final', 'final', 'completed']:
|
elif game_data['status'] in ['status_final', 'final', 'completed']:
|
||||||
@@ -316,8 +349,6 @@ class BaseMiLBManager:
|
|||||||
# Draw on the current image
|
# Draw on the current image
|
||||||
self.display_manager.draw = draw
|
self.display_manager.draw = draw
|
||||||
self.display_manager._draw_bdf_text(status_text, status_x, status_y, color=(255, 255, 255), font=self.display_manager.calendar_font)
|
self.display_manager._draw_bdf_text(status_text, status_x, status_y, color=(255, 255, 255), font=self.display_manager.calendar_font)
|
||||||
# Update the display
|
|
||||||
self.display_manager.update_display()
|
|
||||||
|
|
||||||
# Draw scores at the bottom using NHL-style font
|
# Draw scores at the bottom using NHL-style font
|
||||||
away_score = str(game_data['away_score'])
|
away_score = str(game_data['away_score'])
|
||||||
@@ -362,6 +393,7 @@ class BaseMiLBManager:
|
|||||||
def _format_game_time(self, game_time: str) -> str:
|
def _format_game_time(self, game_time: str) -> str:
|
||||||
"""Format game time for display."""
|
"""Format game time for display."""
|
||||||
try:
|
try:
|
||||||
|
self.logger.debug(f"[MiLB] Formatting game time: {game_time}")
|
||||||
# Get timezone from config
|
# Get timezone from config
|
||||||
timezone_str = self.config.get('timezone', 'UTC')
|
timezone_str = self.config.get('timezone', 'UTC')
|
||||||
try:
|
try:
|
||||||
@@ -376,7 +408,9 @@ class BaseMiLBManager:
|
|||||||
dt = dt.replace(tzinfo=pytz.UTC)
|
dt = dt.replace(tzinfo=pytz.UTC)
|
||||||
local_dt = dt.astimezone(tz)
|
local_dt = dt.astimezone(tz)
|
||||||
|
|
||||||
return local_dt.strftime("%I:%M%p").lstrip('0')
|
formatted_time = local_dt.strftime("%I:%M%p").lstrip('0')
|
||||||
|
self.logger.debug(f"[MiLB] Formatted time: {formatted_time}")
|
||||||
|
return formatted_time
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error formatting game time: {e}")
|
logger.error(f"Error formatting game time: {e}")
|
||||||
return "TBD"
|
return "TBD"
|
||||||
@@ -392,7 +426,9 @@ class BaseMiLBManager:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Check if test mode is enabled
|
# Check if test mode is enabled
|
||||||
if self.milb_config.get('test_mode', False):
|
test_mode = self.milb_config.get('test_mode', False)
|
||||||
|
self.logger.debug(f"[MiLB] Test mode: {test_mode}")
|
||||||
|
if test_mode:
|
||||||
self.logger.info("Using test mode data for MiLB")
|
self.logger.info("Using test mode data for MiLB")
|
||||||
return {
|
return {
|
||||||
'test_game_1': {
|
'test_game_1': {
|
||||||
@@ -417,6 +453,8 @@ class BaseMiLBManager:
|
|||||||
current_month = now.month
|
current_month = now.month
|
||||||
in_season = 4 <= current_month <= 9
|
in_season = 4 <= current_month <= 9
|
||||||
|
|
||||||
|
self.logger.debug(f"[MiLB] Current month: {current_month}, in_season: {in_season}")
|
||||||
|
|
||||||
if not in_season:
|
if not in_season:
|
||||||
self.logger.info("MiLB is currently in offseason (October-March). No games expected.")
|
self.logger.info("MiLB is currently in offseason (October-March). No games expected.")
|
||||||
self.logger.info("Consider enabling test_mode for offseason testing.")
|
self.logger.info("Consider enabling test_mode for offseason testing.")
|
||||||
@@ -440,6 +478,8 @@ class BaseMiLBManager:
|
|||||||
response = self.session.get(url, headers=self.headers, timeout=10)
|
response = self.session.get(url, headers=self.headers, timeout=10)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
# Increment API counter for successful request
|
||||||
|
increment_api_counter('sports', 1)
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
self.logger.error(f"Error fetching data from {url}: {e}")
|
self.logger.error(f"Error fetching data from {url}: {e}")
|
||||||
continue
|
continue
|
||||||
@@ -487,6 +527,8 @@ class BaseMiLBManager:
|
|||||||
if not event.get('gameDate'):
|
if not event.get('gameDate'):
|
||||||
self.logger.warning(f"Skipping game {game_pk} due to missing 'gameDate'.")
|
self.logger.warning(f"Skipping game {game_pk} due to missing 'gameDate'.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
self.logger.debug(f"[MiLB] Game {game_pk} gameDate: {event.get('gameDate')}")
|
||||||
|
|
||||||
is_favorite_game = (home_abbr in self.favorite_teams or away_abbr in self.favorite_teams)
|
is_favorite_game = (home_abbr in self.favorite_teams or away_abbr in self.favorite_teams)
|
||||||
|
|
||||||
@@ -522,6 +564,8 @@ class BaseMiLBManager:
|
|||||||
'away_record': away_record_str,
|
'away_record': away_record_str,
|
||||||
'home_record': home_record_str
|
'home_record': home_record_str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.logger.debug(f"[MiLB] Created game data for {game_pk}: status={mapped_status}, status_state={mapped_status_state}, start_time={event.get('gameDate')}")
|
||||||
|
|
||||||
if status_state == 'Live':
|
if status_state == 'Live':
|
||||||
linescore = event.get('linescore', {})
|
linescore = event.get('linescore', {})
|
||||||
@@ -1545,7 +1589,9 @@ class MiLBUpcomingManager(BaseMiLBManager):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# --- Optimization: Filter for favorite teams before processing ---
|
# --- Optimization: Filter for favorite teams before processing ---
|
||||||
if self.milb_config.get("show_favorite_teams_only", False) and self.favorite_teams:
|
show_favorite_only = self.milb_config.get("show_favorite_teams_only", False)
|
||||||
|
self.logger.debug(f"[MiLB] show_favorite_teams_only: {show_favorite_only}, favorite_teams: {self.favorite_teams}")
|
||||||
|
if show_favorite_only and self.favorite_teams:
|
||||||
games = {
|
games = {
|
||||||
game_id: game for game_id, game in games.items()
|
game_id: game for game_id, game in games.items()
|
||||||
if game.get('home_team') in self.favorite_teams or game.get('away_team') in self.favorite_teams
|
if game.get('home_team') in self.favorite_teams or game.get('away_team') in self.favorite_teams
|
||||||
@@ -1572,9 +1618,11 @@ class MiLBUpcomingManager(BaseMiLBManager):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
self.logger.debug(f"[MiLB] Parsing start_time: {game['start_time']}")
|
||||||
game_time = datetime.fromisoformat(game['start_time'].replace('Z', '+00:00'))
|
game_time = datetime.fromisoformat(game['start_time'].replace('Z', '+00:00'))
|
||||||
if game_time.tzinfo is None:
|
if game_time.tzinfo is None:
|
||||||
game_time = game_time.replace(tzinfo=timezone.utc)
|
game_time = game_time.replace(tzinfo=timezone.utc)
|
||||||
|
self.logger.debug(f"[MiLB] Parsed game_time: {game_time}")
|
||||||
except (ValueError, TypeError) as e:
|
except (ValueError, TypeError) as e:
|
||||||
self.logger.error(f"Could not parse start_time for game {game_id}: {game['start_time']}. Error: {e}")
|
self.logger.error(f"Could not parse start_time for game {game_id}: {game['start_time']}. Error: {e}")
|
||||||
continue
|
continue
|
||||||
@@ -1593,6 +1641,7 @@ class MiLBUpcomingManager(BaseMiLBManager):
|
|||||||
if is_upcoming:
|
if is_upcoming:
|
||||||
new_upcoming_games.append(game)
|
new_upcoming_games.append(game)
|
||||||
self.logger.info(f"[MiLB] Added upcoming game: {game.get('away_team')} @ {game.get('home_team')} at {game_time}")
|
self.logger.info(f"[MiLB] Added upcoming game: {game.get('away_team')} @ {game.get('home_team')} at {game_time}")
|
||||||
|
self.logger.debug(f"[MiLB] Game data for upcoming: {game}")
|
||||||
|
|
||||||
# Sort by game time (soonest first) and limit to upcoming_games_to_show
|
# Sort by game time (soonest first) and limit to upcoming_games_to_show
|
||||||
new_upcoming_games.sort(key=lambda x: x.get('start_time', ''))
|
new_upcoming_games.sort(key=lambda x: x.get('start_time', ''))
|
||||||
@@ -1622,6 +1671,7 @@ class MiLBUpcomingManager(BaseMiLBManager):
|
|||||||
|
|
||||||
def display(self, force_clear: bool = False):
|
def display(self, force_clear: bool = False):
|
||||||
"""Display upcoming games."""
|
"""Display upcoming games."""
|
||||||
|
self.logger.debug(f"[MiLB] Display called with {len(self.upcoming_games)} upcoming games")
|
||||||
if not self.upcoming_games:
|
if not self.upcoming_games:
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
if current_time - self.last_warning_time > self.warning_cooldown:
|
if current_time - self.last_warning_time > self.warning_cooldown:
|
||||||
@@ -1639,13 +1689,17 @@ class MiLBUpcomingManager(BaseMiLBManager):
|
|||||||
self.current_game = self.upcoming_games[self.current_game_index]
|
self.current_game = self.upcoming_games[self.current_game_index]
|
||||||
self.last_game_switch = current_time
|
self.last_game_switch = current_time
|
||||||
force_clear = True # Force clear when switching games
|
force_clear = True # Force clear when switching games
|
||||||
|
self.logger.debug(f"[MiLB] Switched to game {self.current_game_index}: {self.current_game.get('away_team')} @ {self.current_game.get('home_team')}")
|
||||||
|
|
||||||
# Create and display the game image
|
# Create and display the game image
|
||||||
if self.current_game:
|
if self.current_game:
|
||||||
|
self.logger.debug(f"[MiLB] Creating display for current game: {self.current_game.get('away_team')} @ {self.current_game.get('home_team')}")
|
||||||
game_image = self._create_game_display(self.current_game)
|
game_image = self._create_game_display(self.current_game)
|
||||||
self.display_manager.image = game_image
|
self.display_manager.image = game_image
|
||||||
self.display_manager.draw = ImageDraw.Draw(self.display_manager.image)
|
self.display_manager.draw = ImageDraw.Draw(self.display_manager.image)
|
||||||
self.display_manager.update_display()
|
self.display_manager.update_display()
|
||||||
|
else:
|
||||||
|
self.logger.debug(f"[MiLB] No current game to display")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"[MiLB] Error displaying upcoming game: {e}", exc_info=True)
|
self.logger.error(f"[MiLB] Error displaying upcoming game: {e}", exc_info=True)
|
||||||
@@ -13,6 +13,14 @@ from urllib3.util.retry import Retry
|
|||||||
import pytz
|
import pytz
|
||||||
from src.odds_manager import OddsManager
|
from src.odds_manager import OddsManager
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
# Get logger
|
# Get logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -447,6 +455,10 @@ class BaseMLBManager:
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
|
# Increment API counter for sports data call
|
||||||
|
increment_api_counter('sports', 1)
|
||||||
|
|
||||||
self.logger.info(f"Found {len(data.get('events', []))} total games for date {date}")
|
self.logger.info(f"Found {len(data.get('events', []))} total games for date {date}")
|
||||||
|
|
||||||
for event in data.get('events', []):
|
for event in data.get('events', []):
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ from src.config_manager import ConfigManager
|
|||||||
from src.odds_manager import OddsManager
|
from src.odds_manager import OddsManager
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
|
# 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
|
# Constants
|
||||||
ESPN_NBA_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/basketball/nba/scoreboard"
|
ESPN_NBA_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/basketball/nba/scoreboard"
|
||||||
|
|
||||||
@@ -283,6 +291,9 @@ class BaseNBAManager:
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
|
# Increment API counter for sports data call
|
||||||
|
increment_api_counter('sports', 1)
|
||||||
|
|
||||||
if use_cache:
|
if use_cache:
|
||||||
self.cache_manager.set(cache_key, data)
|
self.cache_manager.set(cache_key, data)
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ from src.cache_manager import CacheManager
|
|||||||
from requests.adapters import HTTPAdapter
|
from requests.adapters import HTTPAdapter
|
||||||
from urllib3.util.retry import Retry
|
from urllib3.util.retry import Retry
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -107,6 +115,9 @@ class NewsManager:
|
|||||||
response = self.session.get(url, headers=headers, timeout=10)
|
response = self.session.get(url, headers=headers, timeout=10)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
|
# Increment API counter for news data call
|
||||||
|
increment_api_counter('news', 1)
|
||||||
|
|
||||||
root = ET.fromstring(response.content)
|
root = ET.fromstring(response.content)
|
||||||
headlines = []
|
headlines = []
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ from src.config_manager import ConfigManager
|
|||||||
from src.odds_manager import OddsManager
|
from src.odds_manager import OddsManager
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
|
# 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
|
# Constants
|
||||||
NHL_API_BASE_URL = "https://api-web.nhle.com/v1/schedule/"
|
NHL_API_BASE_URL = "https://api-web.nhle.com/v1/schedule/"
|
||||||
|
|
||||||
@@ -126,6 +134,10 @@ class BaseNHLManager:
|
|||||||
response = requests.get(url)
|
response = requests.get(url)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
|
# Increment API counter for sports data call
|
||||||
|
increment_api_counter('sports', 1)
|
||||||
|
|
||||||
self.logger.info(f"[NHL] Successfully fetched data from NHL API for {date_str}")
|
self.logger.info(f"[NHL] Successfully fetched data from NHL API for {date_str}")
|
||||||
|
|
||||||
# Save to cache if caching is enabled
|
# Save to cache if caching is enabled
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ from .cache_manager import CacheManager
|
|||||||
from requests.adapters import HTTPAdapter
|
from requests.adapters import HTTPAdapter
|
||||||
from urllib3.util.retry import Retry
|
from urllib3.util.retry import Retry
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
# Get logger without configuring
|
# Get logger without configuring
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -197,6 +205,9 @@ class StockManager:
|
|||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
|
# Increment API counter for stock/crypto data call
|
||||||
|
increment_api_counter('stocks', 1)
|
||||||
|
|
||||||
# Extract the relevant data from the response
|
# Extract the relevant data from the response
|
||||||
chart_data = data.get('chart', {}).get('result', [{}])[0]
|
chart_data = data.get('chart', {}).get('result', [{}])[0]
|
||||||
meta = chart_data.get('meta', {})
|
meta = chart_data.get('meta', {})
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ from .cache_manager import CacheManager
|
|||||||
from requests.adapters import HTTPAdapter
|
from requests.adapters import HTTPAdapter
|
||||||
from urllib3.util.retry import Retry
|
from urllib3.util.retry import Retry
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -125,6 +133,9 @@ class StockNewsManager:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
|
# Increment API counter for news data call
|
||||||
|
increment_api_counter('news', 1)
|
||||||
news_items = data.get('news', [])
|
news_items = data.get('news', [])
|
||||||
|
|
||||||
processed_news = []
|
processed_news = []
|
||||||
|
|||||||
@@ -7,6 +7,14 @@ import freetype
|
|||||||
from .weather_icons import WeatherIcons
|
from .weather_icons import WeatherIcons
|
||||||
from .cache_manager import CacheManager
|
from .cache_manager import CacheManager
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
class WeatherManager:
|
class WeatherManager:
|
||||||
|
|
||||||
def __init__(self, config: Dict[str, Any], display_manager):
|
def __init__(self, config: Dict[str, Any], display_manager):
|
||||||
@@ -108,6 +116,9 @@ class WeatherManager:
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
geo_data = response.json()
|
geo_data = response.json()
|
||||||
|
|
||||||
|
# Increment API counter for geocoding call
|
||||||
|
increment_api_counter('weather', 1)
|
||||||
|
|
||||||
if not geo_data:
|
if not geo_data:
|
||||||
print(f"Could not find coordinates for {city}, {state}")
|
print(f"Could not find coordinates for {city}, {state}")
|
||||||
return
|
return
|
||||||
@@ -123,6 +134,9 @@ class WeatherManager:
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
one_call_data = response.json()
|
one_call_data = response.json()
|
||||||
|
|
||||||
|
# Increment API counter for weather data call
|
||||||
|
increment_api_counter('weather', 1)
|
||||||
|
|
||||||
# Store current weather data
|
# Store current weather data
|
||||||
self.weather_data = {
|
self.weather_data = {
|
||||||
'main': {
|
'main': {
|
||||||
|
|||||||
@@ -881,6 +881,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h4>API Calls (24h window)</h4>
|
||||||
|
<div id="api-metrics" class="stat-card" style="text-align:left;">
|
||||||
|
<div>Loading API metrics...</div>
|
||||||
|
<div style="margin-top:10px; font-size:12px; color:#666;">If empty, ensure the server is running and /api/metrics is reachable.</div>
|
||||||
|
<div style="margin-top:10px;">
|
||||||
|
<button class="btn btn-primary" onclick="updateApiMetrics()"><i class="fas fa-sync"></i> Refresh API Metrics</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h4>Quick Actions</h4>
|
<h4>Quick Actions</h4>
|
||||||
<div class="display-controls">
|
<div class="display-controls">
|
||||||
<button class="btn btn-primary" onclick="systemAction('restart_service')">
|
<button class="btn btn-primary" onclick="systemAction('restart_service')">
|
||||||
@@ -1407,15 +1416,6 @@
|
|||||||
Loading features configuration...
|
Loading features configuration...
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>API Calls (24h window)</h4>
|
|
||||||
<div id="api-metrics" class="stat-card" style="text-align:left;">
|
|
||||||
<div>Loading API metrics...</div>
|
|
||||||
<div style="margin-top:10px; font-size:12px; color:#666;">If empty, ensure the server is running and /api/metrics is reachable.</div>
|
|
||||||
<div style="margin-top:10px;">
|
|
||||||
<button class="btn btn-primary" onclick="updateApiMetrics()"><i class="fas fa-sync"></i> Refresh API Metrics</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Music Tab -->
|
<!-- Music Tab -->
|
||||||
|
|||||||
Reference in New Issue
Block a user