mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
added more missing soccer logos
This commit is contained in:
96
test/README_soccer_logos.md
Normal file
96
test/README_soccer_logos.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Soccer Logo Checker and Downloader
|
||||
|
||||
## Overview
|
||||
|
||||
The `check_soccer_logos.py` script automatically checks for missing logos of major teams from supported soccer leagues and downloads them from ESPN API if missing.
|
||||
|
||||
## Supported Leagues
|
||||
|
||||
- **Premier League** (eng.1) - 20 teams
|
||||
- **La Liga** (esp.1) - 15 teams
|
||||
- **Bundesliga** (ger.1) - 15 teams
|
||||
- **Serie A** (ita.1) - 14 teams
|
||||
- **Ligue 1** (fra.1) - 12 teams
|
||||
- **Liga Portugal** (por.1) - 15 teams
|
||||
- **Champions League** (uefa.champions) - 13 major teams
|
||||
- **Europa League** (uefa.europa) - 11 major teams
|
||||
- **MLS** (usa.1) - 25 teams
|
||||
|
||||
**Total: 140 major teams across 9 leagues**
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cd test
|
||||
python check_soccer_logos.py
|
||||
```
|
||||
|
||||
## What It Does
|
||||
|
||||
1. **Checks Existing Logos**: Scans `assets/sports/soccer_logos/` for existing logo files
|
||||
2. **Identifies Missing Logos**: Compares against the list of major teams
|
||||
3. **Downloads from ESPN**: Automatically fetches missing logos from ESPN API
|
||||
4. **Creates Placeholders**: If download fails, creates colored placeholder logos
|
||||
5. **Provides Summary**: Shows detailed statistics of the process
|
||||
|
||||
## Output
|
||||
|
||||
The script provides detailed logging showing:
|
||||
- ✅ Existing logos found
|
||||
- ⬇️ Successfully downloaded logos
|
||||
- ❌ Failed downloads (with placeholders created)
|
||||
- 📊 Summary statistics
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
🔍 Checking por.1 (Liga Portugal)
|
||||
📊 Found 2 existing logos, 13 missing
|
||||
✅ Existing: BEN, POR
|
||||
❌ Missing: ARO (Arouca), BRA (SC Braga), CHA (Chaves), ...
|
||||
|
||||
Downloading ARO (Arouca) from por.1
|
||||
✅ Successfully downloaded ARO (Arouca)
|
||||
...
|
||||
|
||||
📈 SUMMARY
|
||||
✅ Existing logos: 25
|
||||
⬇️ Downloaded: 115
|
||||
❌ Failed downloads: 0
|
||||
📊 Total teams checked: 140
|
||||
```
|
||||
|
||||
## Logo Storage
|
||||
|
||||
All logos are stored in: `assets/sports/soccer_logos/`
|
||||
|
||||
Format: `{TEAM_ABBREVIATION}.png` (e.g., `BEN.png`, `POR.png`, `LIV.png`)
|
||||
|
||||
## Integration with LEDMatrix
|
||||
|
||||
These logos are automatically used by the soccer manager when displaying:
|
||||
- Live games
|
||||
- Recent games
|
||||
- Upcoming games
|
||||
- Odds ticker
|
||||
- Leaderboards
|
||||
|
||||
The system will automatically download missing logos on-demand during normal operation, but this script ensures all major teams have logos available upfront.
|
||||
|
||||
## Notes
|
||||
|
||||
- **Real Logos**: Downloaded from ESPN's official API
|
||||
- **Placeholders**: Created for teams not found in ESPN data
|
||||
- **Caching**: Logos are cached locally to avoid repeated downloads
|
||||
- **Format**: All logos converted to RGBA PNG format for LEDMatrix compatibility
|
||||
- **Size**: Logos are optimized for LED matrix display (typically 36x36 pixels)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If downloads fail:
|
||||
1. Check internet connectivity
|
||||
2. Verify ESPN API is accessible
|
||||
3. Some teams may not be in current league rosters
|
||||
4. Placeholder logos will be created as fallback
|
||||
|
||||
The script is designed to be robust and will always provide some form of logo for every team.
|
||||
315
test/check_soccer_logos.py
Normal file
315
test/check_soccer_logos.py
Normal file
@@ -0,0 +1,315 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Soccer Logo Checker and Downloader
|
||||
|
||||
This script checks for missing logos of major teams from supported soccer leagues
|
||||
and downloads them from ESPN API if missing.
|
||||
|
||||
Supported Leagues:
|
||||
- Premier League (eng.1)
|
||||
- La Liga (esp.1)
|
||||
- Bundesliga (ger.1)
|
||||
- Serie A (ita.1)
|
||||
- Ligue 1 (fra.1)
|
||||
- Liga Portugal (por.1)
|
||||
- Champions League (uefa.champions)
|
||||
- Europa League (uefa.europa)
|
||||
- MLS (usa.1)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
# Add src directory to path for imports
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))
|
||||
|
||||
from logo_downloader import download_missing_logo, get_soccer_league_key, LogoDownloader
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Major teams for each league (with their ESPN abbreviations)
|
||||
MAJOR_TEAMS = {
|
||||
'eng.1': { # Premier League
|
||||
'ARS': 'Arsenal',
|
||||
'AVL': 'Aston Villa',
|
||||
'BHA': 'Brighton & Hove Albion',
|
||||
'BOU': 'AFC Bournemouth',
|
||||
'BRE': 'Brentford',
|
||||
'BUR': 'Burnley',
|
||||
'CHE': 'Chelsea',
|
||||
'CRY': 'Crystal Palace',
|
||||
'EVE': 'Everton',
|
||||
'FUL': 'Fulham',
|
||||
'LIV': 'Liverpool',
|
||||
'LUT': 'Luton Town',
|
||||
'MCI': 'Manchester City',
|
||||
'MUN': 'Manchester United',
|
||||
'NEW': 'Newcastle United',
|
||||
'NFO': 'Nottingham Forest',
|
||||
'SHU': 'Sheffield United',
|
||||
'TOT': 'Tottenham Hotspur',
|
||||
'WHU': 'West Ham United',
|
||||
'WOL': 'Wolverhampton Wanderers'
|
||||
},
|
||||
'esp.1': { # La Liga
|
||||
'ALA': 'Alavés',
|
||||
'ATH': 'Athletic Bilbao',
|
||||
'ATM': 'Atlético Madrid',
|
||||
'BAR': 'Barcelona',
|
||||
'BET': 'Real Betis',
|
||||
'CEL': 'Celta Vigo',
|
||||
'ESP': 'Espanyol',
|
||||
'GET': 'Getafe',
|
||||
'GIR': 'Girona',
|
||||
'LEG': 'Leganés',
|
||||
'RAY': 'Rayo Vallecano',
|
||||
'RMA': 'Real Madrid',
|
||||
'SEV': 'Sevilla',
|
||||
'VAL': 'Valencia',
|
||||
'VLD': 'Valladolid'
|
||||
},
|
||||
'ger.1': { # Bundesliga
|
||||
'BOC': 'VfL Bochum',
|
||||
'DOR': 'Borussia Dortmund',
|
||||
'FCA': 'FC Augsburg',
|
||||
'FCB': 'Bayern Munich',
|
||||
'FCU': 'FC Union Berlin',
|
||||
'KOL': '1. FC Köln',
|
||||
'LEV': 'Bayer Leverkusen',
|
||||
'M05': 'Mainz 05',
|
||||
'RBL': 'RB Leipzig',
|
||||
'SCF': 'SC Freiburg',
|
||||
'SGE': 'Eintracht Frankfurt',
|
||||
'STU': 'VfB Stuttgart',
|
||||
'SVW': 'Werder Bremen',
|
||||
'TSG': 'TSG Hoffenheim',
|
||||
'WOB': 'VfL Wolfsburg'
|
||||
},
|
||||
'ita.1': { # Serie A
|
||||
'ATA': 'Atalanta',
|
||||
'CAG': 'Cagliari',
|
||||
'EMP': 'Empoli',
|
||||
'FIO': 'Fiorentina',
|
||||
'INT': 'Inter Milan',
|
||||
'JUV': 'Juventus',
|
||||
'LAZ': 'Lazio',
|
||||
'MIL': 'AC Milan',
|
||||
'MON': 'Monza',
|
||||
'NAP': 'Napoli',
|
||||
'ROM': 'Roma',
|
||||
'TOR': 'Torino',
|
||||
'UDI': 'Udinese',
|
||||
'VER': 'Hellas Verona'
|
||||
},
|
||||
'fra.1': { # Ligue 1
|
||||
'LIL': 'Lille',
|
||||
'LYON': 'Lyon',
|
||||
'MAR': 'Marseille',
|
||||
'MON': 'Monaco',
|
||||
'NAN': 'Nantes',
|
||||
'NICE': 'Nice',
|
||||
'OL': 'Olympique Lyonnais',
|
||||
'OM': 'Olympique de Marseille',
|
||||
'PAR': 'Paris Saint-Germain',
|
||||
'PSG': 'Paris Saint-Germain',
|
||||
'REN': 'Rennes',
|
||||
'STR': 'Strasbourg'
|
||||
},
|
||||
'por.1': { # Liga 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',
|
||||
'SCP': 'Sporting CP', # Alternative abbreviation
|
||||
'VGU': 'Vitória de Guimarães',
|
||||
'VSC': 'Vitória de Setúbal'
|
||||
},
|
||||
'uefa.champions': { # Champions League (major teams)
|
||||
'AJX': 'Ajax',
|
||||
'ATM': 'Atlético Madrid',
|
||||
'BAR': 'Barcelona',
|
||||
'BAY': 'Bayern Munich',
|
||||
'CHE': 'Chelsea',
|
||||
'INT': 'Inter Milan',
|
||||
'JUV': 'Juventus',
|
||||
'LIV': 'Liverpool',
|
||||
'MCI': 'Manchester City',
|
||||
'MUN': 'Manchester United',
|
||||
'PSG': 'Paris Saint-Germain',
|
||||
'RMA': 'Real Madrid',
|
||||
'TOT': 'Tottenham Hotspur'
|
||||
},
|
||||
'uefa.europa': { # Europa League (major teams)
|
||||
'ARS': 'Arsenal',
|
||||
'ATM': 'Atlético Madrid',
|
||||
'BAR': 'Barcelona',
|
||||
'CHE': 'Chelsea',
|
||||
'INT': 'Inter Milan',
|
||||
'JUV': 'Juventus',
|
||||
'LIV': 'Liverpool',
|
||||
'MUN': 'Manchester United',
|
||||
'NAP': 'Napoli',
|
||||
'ROM': 'Roma',
|
||||
'SEV': 'Sevilla'
|
||||
},
|
||||
'usa.1': { # MLS
|
||||
'ATL': 'Atlanta United',
|
||||
'AUS': 'Austin FC',
|
||||
'CHI': 'Chicago Fire',
|
||||
'CIN': 'FC Cincinnati',
|
||||
'CLB': 'Columbus Crew',
|
||||
'DAL': 'FC Dallas',
|
||||
'DC': 'D.C. United',
|
||||
'HOU': 'Houston Dynamo',
|
||||
'LA': 'LA Galaxy',
|
||||
'LAFC': 'Los Angeles FC',
|
||||
'MIA': 'Inter Miami',
|
||||
'MIN': 'Minnesota United',
|
||||
'MTL': 'CF Montréal',
|
||||
'NSC': 'Nashville SC',
|
||||
'NYC': 'New York City FC',
|
||||
'NYR': 'New York Red Bulls',
|
||||
'ORL': 'Orlando City',
|
||||
'PHI': 'Philadelphia Union',
|
||||
'POR': 'Portland Timbers',
|
||||
'RSL': 'Real Salt Lake',
|
||||
'SEA': 'Seattle Sounders',
|
||||
'SJ': 'San Jose Earthquakes',
|
||||
'SKC': 'Sporting Kansas City',
|
||||
'TOR': 'Toronto FC',
|
||||
'VAN': 'Vancouver Whitecaps'
|
||||
}
|
||||
}
|
||||
|
||||
def check_logo_exists(team_abbr: str, logo_dir: str) -> bool:
|
||||
"""Check if a logo file exists for the given team abbreviation."""
|
||||
logo_path = os.path.join(logo_dir, f"{team_abbr}.png")
|
||||
return os.path.exists(logo_path)
|
||||
|
||||
def download_team_logo(team_abbr: str, team_name: str, league_code: str) -> bool:
|
||||
"""Download a team logo from ESPN API."""
|
||||
try:
|
||||
soccer_league_key = get_soccer_league_key(league_code)
|
||||
logger.info(f"Downloading {team_abbr} ({team_name}) from {league_code}")
|
||||
|
||||
success = download_missing_logo(team_abbr, soccer_league_key, team_name)
|
||||
if success:
|
||||
logger.info(f"✅ Successfully downloaded {team_abbr} ({team_name})")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"❌ Failed to download {team_abbr} ({team_name})")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error downloading {team_abbr} ({team_name}): {e}")
|
||||
return False
|
||||
|
||||
def check_league_logos(league_code: str, teams: Dict[str, str], logo_dir: str) -> Tuple[int, int]:
|
||||
"""Check and download missing logos for a specific league."""
|
||||
logger.info(f"\n🔍 Checking {league_code} ({LEAGUE_NAMES.get(league_code, league_code)})")
|
||||
|
||||
missing_logos = []
|
||||
existing_logos = []
|
||||
|
||||
# Check which logos are missing
|
||||
for team_abbr, team_name in teams.items():
|
||||
if check_logo_exists(team_abbr, logo_dir):
|
||||
existing_logos.append(team_abbr)
|
||||
else:
|
||||
missing_logos.append((team_abbr, team_name))
|
||||
|
||||
logger.info(f"📊 Found {len(existing_logos)} existing logos, {len(missing_logos)} missing")
|
||||
|
||||
if existing_logos:
|
||||
logger.info(f"✅ Existing: {', '.join(existing_logos)}")
|
||||
|
||||
if missing_logos:
|
||||
logger.info(f"❌ Missing: {', '.join([f'{abbr} ({name})' for abbr, name in missing_logos])}")
|
||||
|
||||
# Download missing logos
|
||||
downloaded_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for team_abbr, team_name in missing_logos:
|
||||
if download_team_logo(team_abbr, team_name, league_code):
|
||||
downloaded_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
|
||||
return downloaded_count, failed_count
|
||||
|
||||
def main():
|
||||
"""Main function to check and download all soccer logos."""
|
||||
logger.info("⚽ Soccer Logo Checker and Downloader")
|
||||
logger.info("=" * 50)
|
||||
|
||||
# Ensure logo directory exists
|
||||
logo_dir = "assets/sports/soccer_logos"
|
||||
os.makedirs(logo_dir, exist_ok=True)
|
||||
logger.info(f"📁 Logo directory: {logo_dir}")
|
||||
|
||||
# League names for display
|
||||
global LEAGUE_NAMES
|
||||
LEAGUE_NAMES = {
|
||||
'eng.1': 'Premier League',
|
||||
'esp.1': 'La Liga',
|
||||
'ger.1': 'Bundesliga',
|
||||
'ita.1': 'Serie A',
|
||||
'fra.1': 'Ligue 1',
|
||||
'por.1': 'Liga Portugal',
|
||||
'uefa.champions': 'Champions League',
|
||||
'uefa.europa': 'Europa League',
|
||||
'usa.1': 'MLS'
|
||||
}
|
||||
|
||||
total_downloaded = 0
|
||||
total_failed = 0
|
||||
total_existing = 0
|
||||
|
||||
# Check each league
|
||||
for league_code, teams in MAJOR_TEAMS.items():
|
||||
downloaded, failed = check_league_logos(league_code, teams, logo_dir)
|
||||
total_downloaded += downloaded
|
||||
total_failed += failed
|
||||
total_existing += len(teams) - downloaded - failed
|
||||
|
||||
# Summary
|
||||
logger.info("\n" + "=" * 50)
|
||||
logger.info("📈 SUMMARY")
|
||||
logger.info("=" * 50)
|
||||
logger.info(f"✅ Existing logos: {total_existing}")
|
||||
logger.info(f"⬇️ Downloaded: {total_downloaded}")
|
||||
logger.info(f"❌ Failed downloads: {total_failed}")
|
||||
logger.info(f"📊 Total teams checked: {total_existing + total_downloaded + total_failed}")
|
||||
|
||||
if total_failed > 0:
|
||||
logger.warning(f"\n⚠️ {total_failed} logos failed to download. This might be due to:")
|
||||
logger.warning(" - Network connectivity issues")
|
||||
logger.warning(" - ESPN API rate limiting")
|
||||
logger.warning(" - Team abbreviations not matching ESPN's format")
|
||||
logger.warning(" - Teams not currently in the league")
|
||||
|
||||
if total_downloaded > 0:
|
||||
logger.info(f"\n🎉 Successfully downloaded {total_downloaded} new logos!")
|
||||
logger.info(" These logos are now available for use in the LEDMatrix display.")
|
||||
|
||||
logger.info(f"\n📁 All logos are stored in: {os.path.abspath(logo_dir)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user