mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
improve odds ticker dynamic duration
This commit is contained in:
@@ -6,7 +6,7 @@ import json
|
||||
import os
|
||||
from io import BytesIO
|
||||
import requests
|
||||
from typing import Union
|
||||
from typing import Union, Dict, Any, Optional
|
||||
from PIL import Image, ImageEnhance
|
||||
import queue # Added import
|
||||
|
||||
@@ -15,6 +15,14 @@ from .spotify_client import SpotifyClient
|
||||
from .ytm_client import YTMClient
|
||||
# Removed: import config
|
||||
|
||||
# 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
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -313,6 +321,10 @@ class MusicManager:
|
||||
try:
|
||||
response = requests.get(url, timeout=5) # 5-second timeout for image download
|
||||
response.raise_for_status() # Raise an exception for bad status codes
|
||||
|
||||
# Increment API counter for music data
|
||||
increment_api_counter('music', 1)
|
||||
|
||||
img_data = BytesIO(response.content)
|
||||
img = Image.open(img_data)
|
||||
|
||||
|
||||
@@ -13,6 +13,14 @@ from src.config_manager import ConfigManager
|
||||
from src.odds_manager import OddsManager
|
||||
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
|
||||
ESPN_NCAAMB_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/basketball/mens-college-basketball/scoreboard"
|
||||
|
||||
@@ -328,6 +336,9 @@ class BaseNCAAMBasketballManager:
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
# Increment API counter for sports data
|
||||
increment_api_counter('sports', 1)
|
||||
|
||||
if use_cache:
|
||||
self.cache_manager.set(cache_key, data)
|
||||
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import requests
|
||||
import time
|
||||
import logging
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from src.cache_manager import CacheManager
|
||||
from src.config_manager import ConfigManager
|
||||
from typing import Optional, List, Dict, Any
|
||||
import pytz
|
||||
from typing import Dict, Any, Optional, List
|
||||
|
||||
# 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 OddsManager:
|
||||
def __init__(self, cache_manager: CacheManager, config_manager: ConfigManager):
|
||||
def __init__(self, cache_manager: CacheManager, config_manager=None):
|
||||
self.cache_manager = cache_manager
|
||||
self.config_manager = config_manager
|
||||
self.logger = logging.getLogger(__name__)
|
||||
@@ -31,6 +40,9 @@ class OddsManager:
|
||||
response = requests.get(url, timeout=10)
|
||||
response.raise_for_status()
|
||||
raw_data = response.json()
|
||||
|
||||
# Increment API counter for odds data
|
||||
increment_api_counter('odds', 1)
|
||||
self.logger.debug(f"Received raw odds data from ESPN: {json.dumps(raw_data, indent=2)}")
|
||||
|
||||
odds_data = self._extract_espn_data(raw_data)
|
||||
|
||||
@@ -1194,6 +1194,8 @@ class OddsTickerManager:
|
||||
|
||||
def calculate_dynamic_duration(self):
|
||||
"""Calculate the exact time needed to display all odds ticker content"""
|
||||
logger.debug(f"calculate_dynamic_duration called - dynamic_duration_enabled: {self.dynamic_duration_enabled}, total_scroll_width: {self.total_scroll_width}")
|
||||
|
||||
# If dynamic duration is disabled, use fixed duration from config
|
||||
if not self.dynamic_duration_enabled:
|
||||
self.dynamic_duration = self.odds_ticker_config.get('display_duration', 60)
|
||||
@@ -1202,6 +1204,7 @@ class OddsTickerManager:
|
||||
|
||||
if not self.total_scroll_width:
|
||||
self.dynamic_duration = self.min_duration # Use configured minimum
|
||||
logger.debug(f"total_scroll_width is 0, using minimum duration: {self.min_duration}s")
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -1257,7 +1260,12 @@ class OddsTickerManager:
|
||||
logger.debug("get_dynamic_duration called but total_scroll_width is 0, attempting update...")
|
||||
try:
|
||||
# Force an update to get the data and calculate proper duration
|
||||
self._perform_update()
|
||||
# Bypass the update interval check for duration calculation
|
||||
self.games_data = self._fetch_upcoming_games()
|
||||
self.scroll_position = 0
|
||||
self.current_game_index = 0
|
||||
self._create_ticker_image() # Create the composite image
|
||||
logger.debug(f"Force update completed, total_scroll_width: {self.total_scroll_width}px")
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating odds ticker for dynamic duration: {e}")
|
||||
|
||||
|
||||
@@ -14,6 +14,14 @@ from src.config_manager import ConfigManager
|
||||
from src.odds_manager import OddsManager
|
||||
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
|
||||
# ESPN_SOCCER_SCOREBOARD_URL = "https://site.api.espn.com/apis/site/v2/sports/soccer/scoreboards" # Old URL
|
||||
ESPN_SOCCER_LEAGUE_SCOREBOARD_URL_FORMAT = "http://site.api.espn.com/apis/site/v2/sports/soccer/{}/scoreboard" # New format string
|
||||
@@ -192,6 +200,9 @@ class BaseSoccerManager:
|
||||
response = requests.get(url, params=params, timeout=10) # Add timeout
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
# Increment API counter for sports data
|
||||
increment_api_counter('sports', 1)
|
||||
cls.logger.debug(f"[Soccer Map Build] Fetched data for {league_slug}")
|
||||
|
||||
for event in data.get("events", []):
|
||||
@@ -264,6 +275,10 @@ class BaseSoccerManager:
|
||||
response = requests.get(url, params=params)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
# Increment API counter for sports data
|
||||
increment_api_counter('sports', 1)
|
||||
|
||||
self.logger.info(f"[Soccer] Fetched data from ESPN API for {league_slug} on {fetch_date}")
|
||||
|
||||
if use_cache:
|
||||
|
||||
@@ -8,6 +8,14 @@ from rgbmatrix import RGBMatrix, RGBMatrixOptions
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
|
||||
# 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
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -57,6 +65,10 @@ class YouTubeDisplay:
|
||||
try:
|
||||
response = requests.get(url)
|
||||
data = response.json()
|
||||
|
||||
# Increment API counter for YouTube data
|
||||
increment_api_counter('youtube', 1)
|
||||
|
||||
if data['items']:
|
||||
channel = data['items'][0]
|
||||
return {
|
||||
|
||||
@@ -1996,6 +1996,9 @@
|
||||
<div><strong>Stocks:</strong> ${u.stocks || 0} used / ${f.stocks || 0} forecast</div>
|
||||
<div><strong>Sports:</strong> ${u.sports || 0} used / ${f.sports || 0} forecast</div>
|
||||
<div><strong>News:</strong> ${u.news || 0} used / ${f.news || 0} forecast</div>
|
||||
<div><strong>Odds:</strong> ${u.odds || 0} used / ${f.odds || 0} forecast</div>
|
||||
<div><strong>Music:</strong> ${u.music || 0} used / ${f.music || 0} forecast</div>
|
||||
<div><strong>YouTube:</strong> ${u.youtube || 0} used / ${f.youtube || 0} forecast</div>
|
||||
`;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
|
||||
@@ -815,6 +815,9 @@ api_counters = {
|
||||
'stocks': {'used': 0},
|
||||
'sports': {'used': 0},
|
||||
'news': {'used': 0},
|
||||
'odds': {'used': 0},
|
||||
'music': {'used': 0},
|
||||
'youtube': {'used': 0},
|
||||
}
|
||||
api_window_start = time.time()
|
||||
api_window_seconds = 24 * 3600
|
||||
@@ -875,6 +878,27 @@ def get_metrics():
|
||||
except Exception:
|
||||
forecast['news'] = 0
|
||||
|
||||
# Odds ticker
|
||||
try:
|
||||
o_int = int(config.get('odds_ticker', {}).get('update_interval', 3600))
|
||||
forecast['odds'] = max(1, int(api_window_seconds / max(1, o_int)))
|
||||
except Exception:
|
||||
forecast['odds'] = 0
|
||||
|
||||
# Music manager (image downloads)
|
||||
try:
|
||||
m_int = int(config.get('music', {}).get('POLLING_INTERVAL_SECONDS', 5))
|
||||
forecast['music'] = max(1, int(api_window_seconds / max(1, m_int)))
|
||||
except Exception:
|
||||
forecast['music'] = 0
|
||||
|
||||
# YouTube display
|
||||
try:
|
||||
y_int = int(config.get('youtube', {}).get('update_interval', 300))
|
||||
forecast['youtube'] = max(1, int(api_window_seconds / max(1, y_int)))
|
||||
except Exception:
|
||||
forecast['youtube'] = 0
|
||||
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'window_seconds': api_window_seconds,
|
||||
|
||||
Reference in New Issue
Block a user