mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 21:03:01 +00:00
added portuguese soccer league to documentation for soccer manager and added auto-download missing logos for soccer teams
This commit is contained in:
@@ -59,7 +59,7 @@ The system supports live, recent, and upcoming game information for multiple spo
|
|||||||
- NCAA Football
|
- NCAA Football
|
||||||
- NCAA Men's Basketball
|
- NCAA Men's Basketball
|
||||||
- NCAA Men's Baseball
|
- NCAA Men's Baseball
|
||||||
- Soccer
|
- Soccer (Premier League, La Liga, Bundesliga, Serie A, Ligue 1, Liga Portugal, Champions League, Europa League, MLS)
|
||||||
- (Note, some of these sports seasons were not active during development and might need fine tuning when games are active)
|
- (Note, some of these sports seasons were not active during development and might need fine tuning when games are active)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -755,6 +755,20 @@ MLB Conferences/Divisions
|
|||||||
OAK => Oakland Athletics
|
OAK => Oakland Athletics
|
||||||
SEA => Seattle Mariners
|
SEA => Seattle Mariners
|
||||||
TEX => Texas Rangers
|
TEX => Texas Rangers
|
||||||
|
|
||||||
|
Soccer Leagues:
|
||||||
|
LEAGUE_SLUGS = {
|
||||||
|
"eng.1": "Premier League",
|
||||||
|
"esp.1": "La Liga",
|
||||||
|
"ger.1": "Bundesliga",
|
||||||
|
"ita.1": "Serie A",
|
||||||
|
"fra.1": "Ligue 1",
|
||||||
|
"uefa.champions": "Champions League",
|
||||||
|
"uefa.europa": "Europa League",
|
||||||
|
"usa.1": "MLS",
|
||||||
|
"por.1": "Liga Portugal", # Add this line
|
||||||
|
}
|
||||||
|
|
||||||
Soccer - Premier League (England)
|
Soccer - Premier League (England)
|
||||||
ARS => Arsenal
|
ARS => Arsenal
|
||||||
AVL => Aston Villa
|
AVL => Aston Villa
|
||||||
@@ -886,6 +900,24 @@ Soccer - Champions League
|
|||||||
VFB => VfB Stuttgart
|
VFB => VfB Stuttgart
|
||||||
VIL => Villarreal
|
VIL => Villarreal
|
||||||
|
|
||||||
|
Soccer - Liga Portugal (Portugal)
|
||||||
|
ARO => Arouca
|
||||||
|
BEN => SL Benfica
|
||||||
|
BRA => SC Braga
|
||||||
|
CHA => Chaves
|
||||||
|
EST => Estoril Praia
|
||||||
|
FAM => Famalicão
|
||||||
|
GIL => Gil Vicente
|
||||||
|
MOR => Moreirense
|
||||||
|
POR => FC Porto
|
||||||
|
PTM => Portimonense
|
||||||
|
RIO => Rio Ave
|
||||||
|
SR => Sporting CP
|
||||||
|
VGU => Vitória de Guimarães
|
||||||
|
VSC => Vitória de Setúbal
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Soccer - Other Teams
|
Soccer - Other Teams
|
||||||
austin => Austin FC
|
austin => Austin FC
|
||||||
cf_montral => CF Montréal
|
cf_montral => CF Montréal
|
||||||
|
|||||||
BIN
assets/sports/soccer_logos/BEN.png
Normal file
BIN
assets/sports/soccer_logos/BEN.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
BIN
assets/sports/soccer_logos/SCP.png
Normal file
BIN
assets/sports/soccer_logos/SCP.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -31,7 +31,17 @@ class LogoDownloader:
|
|||||||
'ncaa_fb_all': 'https://site.api.espn.com/apis/site/v2/sports/football/college-football/teams', # Includes FCS
|
'ncaa_fb_all': 'https://site.api.espn.com/apis/site/v2/sports/football/college-football/teams', # Includes FCS
|
||||||
'fcs': 'https://site.api.espn.com/apis/site/v2/sports/football/college-football/teams', # FCS teams from same endpoint
|
'fcs': 'https://site.api.espn.com/apis/site/v2/sports/football/college-football/teams', # FCS teams from same endpoint
|
||||||
'ncaam_basketball': 'https://site.api.espn.com/apis/site/v2/sports/basketball/mens-college-basketball/teams',
|
'ncaam_basketball': 'https://site.api.espn.com/apis/site/v2/sports/basketball/mens-college-basketball/teams',
|
||||||
'ncaa_baseball': 'https://site.api.espn.com/apis/site/v2/sports/baseball/college-baseball/teams'
|
'ncaa_baseball': 'https://site.api.espn.com/apis/site/v2/sports/baseball/college-baseball/teams',
|
||||||
|
# Soccer leagues
|
||||||
|
'soccer_eng.1': 'https://site.api.espn.com/apis/site/v2/sports/soccer/eng.1/teams',
|
||||||
|
'soccer_esp.1': 'https://site.api.espn.com/apis/site/v2/sports/soccer/esp.1/teams',
|
||||||
|
'soccer_ger.1': 'https://site.api.espn.com/apis/site/v2/sports/soccer/ger.1/teams',
|
||||||
|
'soccer_ita.1': 'https://site.api.espn.com/apis/site/v2/sports/soccer/ita.1/teams',
|
||||||
|
'soccer_fra.1': 'https://site.api.espn.com/apis/site/v2/sports/soccer/fra.1/teams',
|
||||||
|
'soccer_por.1': 'https://site.api.espn.com/apis/site/v2/sports/soccer/por.1/teams',
|
||||||
|
'soccer_uefa.champions': 'https://site.api.espn.com/apis/site/v2/sports/soccer/uefa.champions/teams',
|
||||||
|
'soccer_uefa.europa': 'https://site.api.espn.com/apis/site/v2/sports/soccer/uefa.europa/teams',
|
||||||
|
'soccer_usa.1': 'https://site.api.espn.com/apis/site/v2/sports/soccer/usa.1/teams'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Directory mappings for different leagues
|
# Directory mappings for different leagues
|
||||||
@@ -44,7 +54,17 @@ class LogoDownloader:
|
|||||||
'ncaa_fb_all': 'assets/sports/ncaa_fbs_logos', # FCS teams go in same directory
|
'ncaa_fb_all': 'assets/sports/ncaa_fbs_logos', # FCS teams go in same directory
|
||||||
'fcs': 'assets/sports/ncaa_fbs_logos', # FCS teams go in same directory
|
'fcs': 'assets/sports/ncaa_fbs_logos', # FCS teams go in same directory
|
||||||
'ncaam_basketball': 'assets/sports/ncaa_fbs_logos',
|
'ncaam_basketball': 'assets/sports/ncaa_fbs_logos',
|
||||||
'ncaa_baseball': 'assets/sports/ncaa_fbs_logos'
|
'ncaa_baseball': 'assets/sports/ncaa_fbs_logos',
|
||||||
|
# Soccer leagues - all use the same soccer_logos directory
|
||||||
|
'soccer_eng.1': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_esp.1': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_ger.1': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_ita.1': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_fra.1': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_por.1': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_uefa.champions': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_uefa.europa': 'assets/sports/soccer_logos',
|
||||||
|
'soccer_usa.1': 'assets/sports/soccer_logos'
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, request_timeout: int = 30, retry_attempts: int = 3):
|
def __init__(self, request_timeout: int = 30, retry_attempts: int = 3):
|
||||||
@@ -605,6 +625,20 @@ class LogoDownloader:
|
|||||||
return converted_count, failed_count
|
return converted_count, failed_count
|
||||||
|
|
||||||
|
|
||||||
|
# Helper function to map soccer league codes to logo downloader format
|
||||||
|
def get_soccer_league_key(league_code: str) -> str:
|
||||||
|
"""
|
||||||
|
Map soccer league codes to logo downloader format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
league_code: Soccer league code (e.g., 'eng.1', 'por.1')
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Logo downloader league key (e.g., 'soccer_eng.1', 'soccer_por.1')
|
||||||
|
"""
|
||||||
|
return f"soccer_{league_code}"
|
||||||
|
|
||||||
|
|
||||||
# Convenience function for easy integration
|
# Convenience function for easy integration
|
||||||
def download_missing_logo(team_abbreviation: str, league: str, team_name: str = None, create_placeholder: bool = True) -> bool:
|
def download_missing_logo(team_abbreviation: str, league: str, team_name: str = None, create_placeholder: bool = True) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from src.display_manager import DisplayManager
|
|||||||
from src.cache_manager import CacheManager
|
from src.cache_manager import CacheManager
|
||||||
from src.config_manager import ConfigManager
|
from src.config_manager import ConfigManager
|
||||||
from src.odds_manager import OddsManager
|
from src.odds_manager import OddsManager
|
||||||
|
from src.logo_downloader import download_missing_logo, get_soccer_league_key
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
# Import the API counter function from web interface
|
# Import the API counter function from web interface
|
||||||
@@ -32,6 +33,7 @@ LEAGUE_SLUGS = {
|
|||||||
"ger.1": "Bundesliga",
|
"ger.1": "Bundesliga",
|
||||||
"ita.1": "Serie A",
|
"ita.1": "Serie A",
|
||||||
"fra.1": "Ligue 1",
|
"fra.1": "Ligue 1",
|
||||||
|
"por.1": "Liga Portugal",
|
||||||
"uefa.champions": "Champions League",
|
"uefa.champions": "Champions League",
|
||||||
"uefa.europa": "Europa League",
|
"uefa.europa": "Europa League",
|
||||||
"usa.1": "MLS",
|
"usa.1": "MLS",
|
||||||
@@ -408,42 +410,61 @@ class BaseSoccerManager:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if not os.path.exists(logo_path) and not (cache_logo_path and os.path.exists(cache_logo_path)):
|
if not os.path.exists(logo_path) and not (cache_logo_path and os.path.exists(cache_logo_path)):
|
||||||
self.logger.info(f"Creating placeholder logo for {team_abbrev}")
|
self.logger.info(f"Logo not found for {team_abbrev} at {logo_path}. Attempting to download from ESPN.")
|
||||||
# Try to create placeholder in cache directory instead of assets directory
|
|
||||||
cache_logo_path = None
|
|
||||||
try:
|
|
||||||
# Use cache directory for placeholder logos
|
|
||||||
if hasattr(self.cache_manager, 'cache_dir') and self.cache_manager.cache_dir:
|
|
||||||
cache_logo_dir = os.path.join(self.cache_manager.cache_dir, 'placeholder_logos')
|
|
||||||
os.makedirs(cache_logo_dir, exist_ok=True)
|
|
||||||
cache_logo_path = os.path.join(cache_logo_dir, f"{team_abbrev}.png")
|
|
||||||
|
|
||||||
# Create placeholder logo
|
# Try to download the logo from ESPN API for each configured league
|
||||||
|
download_success = False
|
||||||
|
for league_code in self.target_leagues_config:
|
||||||
|
if league_code in LEAGUE_SLUGS:
|
||||||
|
soccer_league_key = get_soccer_league_key(league_code)
|
||||||
|
self.logger.debug(f"Attempting to download {team_abbrev} logo from {league_code} ({soccer_league_key})")
|
||||||
|
|
||||||
|
success = download_missing_logo(team_abbrev, soccer_league_key, team_abbrev)
|
||||||
|
if success:
|
||||||
|
self.logger.info(f"Successfully downloaded logo for {team_abbrev} from {league_code}")
|
||||||
|
download_success = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.logger.debug(f"Failed to download {team_abbrev} logo from {league_code}")
|
||||||
|
|
||||||
|
if not download_success:
|
||||||
|
self.logger.warning(f"Failed to download logo for {team_abbrev} from any configured league. Creating placeholder.")
|
||||||
|
# Try to create placeholder in cache directory instead of assets directory
|
||||||
|
cache_logo_path = None
|
||||||
|
try:
|
||||||
|
# Use cache directory for placeholder logos
|
||||||
|
if hasattr(self.cache_manager, 'cache_dir') and self.cache_manager.cache_dir:
|
||||||
|
cache_logo_dir = os.path.join(self.cache_manager.cache_dir, 'placeholder_logos')
|
||||||
|
os.makedirs(cache_logo_dir, exist_ok=True)
|
||||||
|
cache_logo_path = os.path.join(cache_logo_dir, f"{team_abbrev}.png")
|
||||||
|
|
||||||
|
# Create placeholder logo
|
||||||
|
logo = Image.new('RGBA', (36, 36), (random.randint(50, 200), random.randint(50, 200), random.randint(50, 200), 255))
|
||||||
|
draw = ImageDraw.Draw(logo)
|
||||||
|
# Optionally add text to placeholder
|
||||||
|
try:
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
|
||||||
|
placeholder_font = ImageFont.truetype(font_4x6, 12)
|
||||||
|
text_width = draw.textlength(team_abbrev, font=placeholder_font)
|
||||||
|
text_x = (36 - text_width) // 2
|
||||||
|
text_y = 10
|
||||||
|
draw.text((text_x, text_y), team_abbrev, fill=(0,0,0,255), font=placeholder_font)
|
||||||
|
except IOError:
|
||||||
|
pass # Font not found, skip text
|
||||||
|
logo.save(cache_logo_path)
|
||||||
|
self.logger.info(f"Created placeholder logo in cache at {cache_logo_path}")
|
||||||
|
# Update logo_path to use cache version
|
||||||
|
logo_path = cache_logo_path
|
||||||
|
else:
|
||||||
|
# No cache directory available, just use in-memory placeholder
|
||||||
|
raise PermissionError("No writable cache directory available")
|
||||||
|
except (PermissionError, OSError) as pe:
|
||||||
|
self.logger.debug(f"Could not create placeholder logo file for {team_abbrev}: {pe}")
|
||||||
|
# Return a simple in-memory placeholder instead
|
||||||
logo = Image.new('RGBA', (36, 36), (random.randint(50, 200), random.randint(50, 200), random.randint(50, 200), 255))
|
logo = Image.new('RGBA', (36, 36), (random.randint(50, 200), random.randint(50, 200), random.randint(50, 200), 255))
|
||||||
draw = ImageDraw.Draw(logo)
|
self._logo_cache[team_abbrev] = logo
|
||||||
# Optionally add text to placeholder
|
return logo
|
||||||
try:
|
|
||||||
font_4x6 = os.path.abspath(os.path.join(script_dir, "../assets/fonts/4x6-font.ttf"))
|
|
||||||
placeholder_font = ImageFont.truetype(font_4x6, 12)
|
|
||||||
text_width = draw.textlength(team_abbrev, font=placeholder_font)
|
|
||||||
text_x = (36 - text_width) // 2
|
|
||||||
text_y = 10
|
|
||||||
draw.text((text_x, text_y), team_abbrev, fill=(0,0,0,255), font=placeholder_font)
|
|
||||||
except IOError:
|
|
||||||
pass # Font not found, skip text
|
|
||||||
logo.save(cache_logo_path)
|
|
||||||
self.logger.info(f"Created placeholder logo in cache at {cache_logo_path}")
|
|
||||||
# Update logo_path to use cache version
|
|
||||||
logo_path = cache_logo_path
|
|
||||||
else:
|
|
||||||
# No cache directory available, just use in-memory placeholder
|
|
||||||
raise PermissionError("No writable cache directory available")
|
|
||||||
except (PermissionError, OSError) as pe:
|
|
||||||
self.logger.debug(f"Could not create placeholder logo file for {team_abbrev}: {pe}")
|
|
||||||
# Return a simple in-memory placeholder instead
|
|
||||||
logo = Image.new('RGBA', (36, 36), (random.randint(50, 200), random.randint(50, 200), random.randint(50, 200), 255))
|
|
||||||
self._logo_cache[team_abbrev] = logo
|
|
||||||
return logo
|
|
||||||
|
|
||||||
# Try to load logo from original path or cache directory
|
# Try to load logo from original path or cache directory
|
||||||
logo_to_load = None
|
logo_to_load = None
|
||||||
|
|||||||
Reference in New Issue
Block a user