Files
vrobbler/vrobbler/apps/sports/thesportsdb.py
Colin Powell ea1b43d1b8
Some checks failed
build / test (push) Has been cancelled
[sports] Big sports structure revamp
This should make scrobbling sports more like tasks.

The root scrobbled items are a little more generic, but
it's easier to see viewing patterns.
2026-06-06 23:32:21 -04:00

148 lines
4.9 KiB
Python

import logging
import requests
from dateutil.parser import parse
from django.conf import settings
from django.core.files.base import ContentFile
from django.utils import timezone
from pysportsdb import TheSportsDbClient
from sports.models import League, Sport, Team
logger = logging.getLogger(__name__)
API_KEY = getattr(settings, "THESPORTSDB_API_KEY", "2")
client = TheSportsDbClient(api_key=API_KEY)
def has_logo(league_or_team) -> bool:
"""Check if a model instance has a logo (handles both NULL and empty string)."""
return bool(league_or_team.logo and league_or_team.logo.name)
def enrich_league_logo(league: League) -> None:
"""Fetch the league badge from TheSportsDB and save it as the league logo."""
if not league.thesportsdb_id or has_logo(league):
return
url = (
f"https://www.thesportsdb.com/api/v1/json/{API_KEY}"
f"/lookupleague.php?id={league.thesportsdb_id}"
)
try:
resp = requests.get(url, timeout=10)
data = resp.json()
leagues = data.get("leagues", [])
if not leagues:
return
badge_url = leagues[0].get("strBadge")
if badge_url:
r = requests.get(badge_url, timeout=10)
if r.status_code == 200:
fname = f"{league.uuid or league.thesportsdb_id}.png"
league.logo.save(fname, ContentFile(r.content), save=True)
logger.info(
"Saved league logo from TheSportsDB",
extra={"league_id": league.id, "league_name": league.name},
)
except Exception as e:
logger.warning(
"Failed to fetch league logo from TheSportsDB",
extra={"league_id": league.id, "error": str(e)},
)
def enrich_team_logo(team: Team) -> None:
"""Fetch the team badge from TheSportsDB and save it as the team logo."""
if not team.thesportsdb_id or has_logo(team):
return
try:
badge_url = None
# Try direct lookup by thesportsdb_id first (more reliable)
url = (
f"https://www.thesportsdb.com/api/v1/json/{API_KEY}"
f"/lookupteam.php?id={team.thesportsdb_id}"
)
resp = requests.get(url, timeout=10)
data = resp.json()
api_teams = data.get("teams", [])
if api_teams:
badge_url = api_teams[0].get("strBadge")
else:
# Fall back to name search
result = client.search_teams(team.name) or {}
api_teams = result.get("teams", [])
if api_teams:
badge_url = api_teams[0].get("strBadge")
if badge_url:
r = requests.get(badge_url, timeout=10)
if r.status_code == 200:
fname = f"{team.uuid or team.thesportsdb_id}.png"
team.logo.save(fname, ContentFile(r.content), save=True)
logger.info(
"Saved team logo from TheSportsDB",
extra={"team_id": team.id, "team_name": team.name},
)
except Exception as e:
logger.warning(
"Failed to fetch team logo from TheSportsDB",
extra={"team_id": team.id, "error": str(e)},
)
def lookup_event_from_thesportsdb(event_id: str) -> dict:
try:
event = client.lookup_event(event_id)["events"][0]
except TypeError:
return {}
if not event or type(event) != dict:
return {}
sport, _created = Sport.objects.get_or_create(thesportsdb_id=event.get("strSport"))
# Find or create the league and optionally enrich its logo
lid = event.get("idLeague")
league, l_created = League.objects.get_or_create(
thesportsdb_id=lid,
defaults={"name": event.get("strLeague", "")},
)
if l_created:
league.name = event.get("strLeague", "")
league.sport = sport
league.save(update_fields=["name", "sport"])
enrich_league_logo(league)
try:
start = parse(event.get("strTimestamp"))
except:
start = timezone.now()
data_dict = {
"EventId": event_id,
"ItemType": sport.default_event_type,
"Name": event.get("strEvent"),
"AltName": event.get("strEventAlternate"),
"Start": start,
"Provider_thesportsdb": event.get("idEvent"),
"RunTime": sport.default_event_run_time_seconds,
"Sport": event.get("strSport"),
"Season": event.get("strSeason"),
"LeagueId": lid,
"LeagueName": event.get("strLeague"),
"HomeTeamId": event.get("idHomeTeam"),
"HomeTeamName": event.get("strHomeTeam"),
"AwayTeamId": event.get("idAwayTeam"),
"AwayTeamName": event.get("strAwayTeam"),
"RoundId": event.get("intRound"),
"PlaybackPosition": None,
"UtcTimestamp": timezone.now().strftime("%Y-%m-%d %H:%M:%S.%f%z"),
"IsPaused": False,
"PlayedToCompletion": False,
"Source": "Vrobbler",
}
return data_dict