Stadium Progress & Achievements: - Add StadiumVisit and Achievement SwiftData models - Create Progress tab with interactive map view - Implement photo-based visit import with GPS/date matching - Add achievement badges (count-based, regional, journey) - Create shareable progress cards for social media - Add canonical data infrastructure (stadium identities, team aliases) - Implement score resolution from free APIs (MLB, NBA, NHL stats) UI Improvements: - Add ThemedSpinner and ThemedSpinnerCompact components - Replace all ProgressView() with themed spinners throughout app - Fix sport selection state not persisting when navigating away Bug Fixes: - Fix Coast to Coast trips showing only 1 city (validation issue) - Fix stadium progress showing 0/0 (filtering issue) - Remove "Stadium Quest" title from progress view 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
406 lines
15 KiB
Python
406 lines
15 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate Canonical Data for SportsTime App
|
|
==========================================
|
|
Generates team_aliases.json and league_structure.json from team mappings.
|
|
|
|
Usage:
|
|
python generate_canonical_data.py
|
|
python generate_canonical_data.py --output ./data
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
# =============================================================================
|
|
# LEAGUE STRUCTURE
|
|
# =============================================================================
|
|
|
|
MLB_STRUCTURE = {
|
|
"leagues": [
|
|
{"id": "mlb_al", "name": "American League", "abbreviation": "AL"},
|
|
{"id": "mlb_nl", "name": "National League", "abbreviation": "NL"},
|
|
],
|
|
"divisions": [
|
|
# American League
|
|
{"id": "mlb_al_east", "name": "AL East", "parent_id": "mlb_al", "teams": ["NYY", "BOS", "TOR", "BAL", "TBR"]},
|
|
{"id": "mlb_al_central", "name": "AL Central", "parent_id": "mlb_al", "teams": ["CLE", "DET", "MIN", "CHW", "KCR"]},
|
|
{"id": "mlb_al_west", "name": "AL West", "parent_id": "mlb_al", "teams": ["HOU", "SEA", "TEX", "LAA", "OAK"]},
|
|
# National League
|
|
{"id": "mlb_nl_east", "name": "NL East", "parent_id": "mlb_nl", "teams": ["ATL", "PHI", "NYM", "MIA", "WSN"]},
|
|
{"id": "mlb_nl_central", "name": "NL Central", "parent_id": "mlb_nl", "teams": ["MIL", "CHC", "STL", "PIT", "CIN"]},
|
|
{"id": "mlb_nl_west", "name": "NL West", "parent_id": "mlb_nl", "teams": ["LAD", "ARI", "SDP", "SFG", "COL"]},
|
|
]
|
|
}
|
|
|
|
NBA_STRUCTURE = {
|
|
"conferences": [
|
|
{"id": "nba_eastern", "name": "Eastern Conference", "abbreviation": "East"},
|
|
{"id": "nba_western", "name": "Western Conference", "abbreviation": "West"},
|
|
],
|
|
"divisions": [
|
|
# Eastern Conference
|
|
{"id": "nba_atlantic", "name": "Atlantic", "parent_id": "nba_eastern", "teams": ["BOS", "BRK", "NYK", "PHI", "TOR"]},
|
|
{"id": "nba_central", "name": "Central", "parent_id": "nba_eastern", "teams": ["CHI", "CLE", "DET", "IND", "MIL"]},
|
|
{"id": "nba_southeast", "name": "Southeast", "parent_id": "nba_eastern", "teams": ["ATL", "CHO", "MIA", "ORL", "WAS"]},
|
|
# Western Conference
|
|
{"id": "nba_northwest", "name": "Northwest", "parent_id": "nba_western", "teams": ["DEN", "MIN", "OKC", "POR", "UTA"]},
|
|
{"id": "nba_pacific", "name": "Pacific", "parent_id": "nba_western", "teams": ["GSW", "LAC", "LAL", "PHO", "SAC"]},
|
|
{"id": "nba_southwest", "name": "Southwest", "parent_id": "nba_western", "teams": ["DAL", "HOU", "MEM", "NOP", "SAS"]},
|
|
]
|
|
}
|
|
|
|
NHL_STRUCTURE = {
|
|
"conferences": [
|
|
{"id": "nhl_eastern", "name": "Eastern Conference", "abbreviation": "East"},
|
|
{"id": "nhl_western", "name": "Western Conference", "abbreviation": "West"},
|
|
],
|
|
"divisions": [
|
|
# Eastern Conference
|
|
{"id": "nhl_atlantic", "name": "Atlantic", "parent_id": "nhl_eastern", "teams": ["BOS", "BUF", "DET", "FLA", "MTL", "OTT", "TBL", "TOR"]},
|
|
{"id": "nhl_metropolitan", "name": "Metropolitan", "parent_id": "nhl_eastern", "teams": ["CAR", "CBJ", "NJD", "NYI", "NYR", "PHI", "PIT", "WSH"]},
|
|
# Western Conference
|
|
{"id": "nhl_central", "name": "Central", "parent_id": "nhl_western", "teams": ["ARI", "CHI", "COL", "DAL", "MIN", "NSH", "STL", "WPG"]},
|
|
{"id": "nhl_pacific", "name": "Pacific", "parent_id": "nhl_western", "teams": ["ANA", "CGY", "EDM", "LAK", "SEA", "SJS", "VAN", "VGK"]},
|
|
]
|
|
}
|
|
|
|
|
|
# =============================================================================
|
|
# TEAM ALIASES (Historical name changes, relocations, abbreviation changes)
|
|
# =============================================================================
|
|
|
|
# Format: {current_abbrev: [(alias_type, alias_value, valid_from, valid_until), ...]}
|
|
|
|
MLB_ALIASES = {
|
|
# Washington Nationals (formerly Montreal Expos)
|
|
"WSN": [
|
|
("name", "Montreal Expos", "1969-01-01", "2004-12-31"),
|
|
("abbreviation", "MON", "1969-01-01", "2004-12-31"),
|
|
("city", "Montreal", "1969-01-01", "2004-12-31"),
|
|
],
|
|
# Oakland Athletics (moving to Sacramento, formerly in Kansas City and Philadelphia)
|
|
"OAK": [
|
|
("name", "Kansas City Athletics", "1955-01-01", "1967-12-31"),
|
|
("abbreviation", "KCA", "1955-01-01", "1967-12-31"),
|
|
("city", "Kansas City", "1955-01-01", "1967-12-31"),
|
|
("name", "Philadelphia Athletics", "1901-01-01", "1954-12-31"),
|
|
("abbreviation", "PHA", "1901-01-01", "1954-12-31"),
|
|
("city", "Philadelphia", "1901-01-01", "1954-12-31"),
|
|
],
|
|
# Cleveland Guardians (formerly Indians)
|
|
"CLE": [
|
|
("name", "Cleveland Indians", "1915-01-01", "2021-12-31"),
|
|
],
|
|
# Tampa Bay Rays (formerly Devil Rays)
|
|
"TBR": [
|
|
("name", "Tampa Bay Devil Rays", "1998-01-01", "2007-12-31"),
|
|
],
|
|
# Miami Marlins (formerly Florida Marlins)
|
|
"MIA": [
|
|
("name", "Florida Marlins", "1993-01-01", "2011-12-31"),
|
|
("city", "Florida", "1993-01-01", "2011-12-31"),
|
|
],
|
|
# Los Angeles Angels (various names)
|
|
"LAA": [
|
|
("name", "Anaheim Angels", "1997-01-01", "2004-12-31"),
|
|
("name", "Los Angeles Angels of Anaheim", "2005-01-01", "2015-12-31"),
|
|
("name", "California Angels", "1965-01-01", "1996-12-31"),
|
|
],
|
|
# Texas Rangers (formerly Washington Senators II)
|
|
"TEX": [
|
|
("name", "Washington Senators", "1961-01-01", "1971-12-31"),
|
|
("abbreviation", "WS2", "1961-01-01", "1971-12-31"),
|
|
("city", "Washington", "1961-01-01", "1971-12-31"),
|
|
],
|
|
# Milwaukee Brewers (briefly Seattle Pilots)
|
|
"MIL": [
|
|
("name", "Seattle Pilots", "1969-01-01", "1969-12-31"),
|
|
("abbreviation", "SEP", "1969-01-01", "1969-12-31"),
|
|
("city", "Seattle", "1969-01-01", "1969-12-31"),
|
|
],
|
|
# Houston Astros (formerly Colt .45s)
|
|
"HOU": [
|
|
("name", "Houston Colt .45s", "1962-01-01", "1964-12-31"),
|
|
],
|
|
}
|
|
|
|
NBA_ALIASES = {
|
|
# Brooklyn Nets (formerly New Jersey Nets, New York Nets)
|
|
"BRK": [
|
|
("name", "New Jersey Nets", "1977-01-01", "2012-04-30"),
|
|
("abbreviation", "NJN", "1977-01-01", "2012-04-30"),
|
|
("city", "New Jersey", "1977-01-01", "2012-04-30"),
|
|
("name", "New York Nets", "1968-01-01", "1977-12-31"),
|
|
],
|
|
# Oklahoma City Thunder (formerly Seattle SuperSonics)
|
|
"OKC": [
|
|
("name", "Seattle SuperSonics", "1967-01-01", "2008-07-01"),
|
|
("abbreviation", "SEA", "1967-01-01", "2008-07-01"),
|
|
("city", "Seattle", "1967-01-01", "2008-07-01"),
|
|
],
|
|
# Memphis Grizzlies (formerly Vancouver Grizzlies)
|
|
"MEM": [
|
|
("name", "Vancouver Grizzlies", "1995-01-01", "2001-05-31"),
|
|
("abbreviation", "VAN", "1995-01-01", "2001-05-31"),
|
|
("city", "Vancouver", "1995-01-01", "2001-05-31"),
|
|
],
|
|
# New Orleans Pelicans (formerly Hornets, formerly Charlotte Hornets original)
|
|
"NOP": [
|
|
("name", "New Orleans Hornets", "2002-01-01", "2013-04-30"),
|
|
("abbreviation", "NOH", "2002-01-01", "2013-04-30"),
|
|
("name", "New Orleans/Oklahoma City Hornets", "2005-01-01", "2007-12-31"),
|
|
],
|
|
# Charlotte Hornets (current, formerly Bobcats)
|
|
"CHO": [
|
|
("name", "Charlotte Bobcats", "2004-01-01", "2014-04-30"),
|
|
("abbreviation", "CHA", "2004-01-01", "2014-04-30"),
|
|
],
|
|
# Washington Wizards (formerly Bullets)
|
|
"WAS": [
|
|
("name", "Washington Bullets", "1974-01-01", "1997-05-31"),
|
|
("name", "Capital Bullets", "1973-01-01", "1973-12-31"),
|
|
("name", "Baltimore Bullets", "1963-01-01", "1972-12-31"),
|
|
],
|
|
# Los Angeles Clippers (formerly San Diego, Buffalo)
|
|
"LAC": [
|
|
("name", "San Diego Clippers", "1978-01-01", "1984-05-31"),
|
|
("abbreviation", "SDC", "1978-01-01", "1984-05-31"),
|
|
("city", "San Diego", "1978-01-01", "1984-05-31"),
|
|
("name", "Buffalo Braves", "1970-01-01", "1978-05-31"),
|
|
("abbreviation", "BUF", "1970-01-01", "1978-05-31"),
|
|
("city", "Buffalo", "1970-01-01", "1978-05-31"),
|
|
],
|
|
# Sacramento Kings (formerly Kansas City Kings, etc.)
|
|
"SAC": [
|
|
("name", "Kansas City Kings", "1975-01-01", "1985-05-31"),
|
|
("abbreviation", "KCK", "1975-01-01", "1985-05-31"),
|
|
("city", "Kansas City", "1975-01-01", "1985-05-31"),
|
|
],
|
|
# Utah Jazz (formerly New Orleans Jazz)
|
|
"UTA": [
|
|
("name", "New Orleans Jazz", "1974-01-01", "1979-05-31"),
|
|
("city", "New Orleans", "1974-01-01", "1979-05-31"),
|
|
],
|
|
}
|
|
|
|
NHL_ALIASES = {
|
|
# Arizona/Utah Hockey Club (formerly Phoenix Coyotes, originally Winnipeg Jets)
|
|
"ARI": [
|
|
("name", "Arizona Coyotes", "2014-01-01", "2024-04-30"),
|
|
("name", "Phoenix Coyotes", "1996-01-01", "2013-12-31"),
|
|
("abbreviation", "PHX", "1996-01-01", "2013-12-31"),
|
|
("city", "Phoenix", "1996-01-01", "2013-12-31"),
|
|
("name", "Winnipeg Jets", "1979-01-01", "1996-05-31"), # Original Jets
|
|
],
|
|
# Carolina Hurricanes (formerly Hartford Whalers)
|
|
"CAR": [
|
|
("name", "Hartford Whalers", "1979-01-01", "1997-05-31"),
|
|
("abbreviation", "HFD", "1979-01-01", "1997-05-31"),
|
|
("city", "Hartford", "1979-01-01", "1997-05-31"),
|
|
],
|
|
# Colorado Avalanche (formerly Quebec Nordiques)
|
|
"COL": [
|
|
("name", "Quebec Nordiques", "1979-01-01", "1995-05-31"),
|
|
("abbreviation", "QUE", "1979-01-01", "1995-05-31"),
|
|
("city", "Quebec", "1979-01-01", "1995-05-31"),
|
|
],
|
|
# Dallas Stars (formerly Minnesota North Stars)
|
|
"DAL": [
|
|
("name", "Minnesota North Stars", "1967-01-01", "1993-05-31"),
|
|
("abbreviation", "MNS", "1967-01-01", "1993-05-31"),
|
|
("city", "Minnesota", "1967-01-01", "1993-05-31"),
|
|
],
|
|
# New Jersey Devils (formerly Kansas City Scouts, Colorado Rockies)
|
|
"NJD": [
|
|
("name", "Colorado Rockies", "1976-01-01", "1982-05-31"),
|
|
("abbreviation", "CLR", "1976-01-01", "1982-05-31"),
|
|
("city", "Colorado", "1976-01-01", "1982-05-31"),
|
|
("name", "Kansas City Scouts", "1974-01-01", "1976-05-31"),
|
|
("abbreviation", "KCS", "1974-01-01", "1976-05-31"),
|
|
("city", "Kansas City", "1974-01-01", "1976-05-31"),
|
|
],
|
|
# Winnipeg Jets (current, formerly Atlanta Thrashers)
|
|
"WPG": [
|
|
("name", "Atlanta Thrashers", "1999-01-01", "2011-05-31"),
|
|
("abbreviation", "ATL", "1999-01-01", "2011-05-31"),
|
|
("city", "Atlanta", "1999-01-01", "2011-05-31"),
|
|
],
|
|
# Florida Panthers (originally in Miami)
|
|
"FLA": [
|
|
("city", "Miami", "1993-01-01", "1998-12-31"),
|
|
],
|
|
# Vegas Golden Knights (no aliases, expansion team)
|
|
# Seattle Kraken (no aliases, expansion team)
|
|
}
|
|
|
|
|
|
def generate_league_structure() -> list[dict]:
|
|
"""Generate league_structure.json data."""
|
|
structures = []
|
|
order = 0
|
|
|
|
# MLB
|
|
structures.append({
|
|
"id": "mlb_league",
|
|
"sport": "MLB",
|
|
"type": "league",
|
|
"name": "Major League Baseball",
|
|
"abbreviation": "MLB",
|
|
"parent_id": None,
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
for league in MLB_STRUCTURE["leagues"]:
|
|
structures.append({
|
|
"id": league["id"],
|
|
"sport": "MLB",
|
|
"type": "conference", # AL/NL are like conferences
|
|
"name": league["name"],
|
|
"abbreviation": league["abbreviation"],
|
|
"parent_id": "mlb_league",
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
for div in MLB_STRUCTURE["divisions"]:
|
|
structures.append({
|
|
"id": div["id"],
|
|
"sport": "MLB",
|
|
"type": "division",
|
|
"name": div["name"],
|
|
"abbreviation": None,
|
|
"parent_id": div["parent_id"],
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
# NBA
|
|
structures.append({
|
|
"id": "nba_league",
|
|
"sport": "NBA",
|
|
"type": "league",
|
|
"name": "National Basketball Association",
|
|
"abbreviation": "NBA",
|
|
"parent_id": None,
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
for conf in NBA_STRUCTURE["conferences"]:
|
|
structures.append({
|
|
"id": conf["id"],
|
|
"sport": "NBA",
|
|
"type": "conference",
|
|
"name": conf["name"],
|
|
"abbreviation": conf["abbreviation"],
|
|
"parent_id": "nba_league",
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
for div in NBA_STRUCTURE["divisions"]:
|
|
structures.append({
|
|
"id": div["id"],
|
|
"sport": "NBA",
|
|
"type": "division",
|
|
"name": div["name"],
|
|
"abbreviation": None,
|
|
"parent_id": div["parent_id"],
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
# NHL
|
|
structures.append({
|
|
"id": "nhl_league",
|
|
"sport": "NHL",
|
|
"type": "league",
|
|
"name": "National Hockey League",
|
|
"abbreviation": "NHL",
|
|
"parent_id": None,
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
for conf in NHL_STRUCTURE["conferences"]:
|
|
structures.append({
|
|
"id": conf["id"],
|
|
"sport": "NHL",
|
|
"type": "conference",
|
|
"name": conf["name"],
|
|
"abbreviation": conf["abbreviation"],
|
|
"parent_id": "nhl_league",
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
for div in NHL_STRUCTURE["divisions"]:
|
|
structures.append({
|
|
"id": div["id"],
|
|
"sport": "NHL",
|
|
"type": "division",
|
|
"name": div["name"],
|
|
"abbreviation": None,
|
|
"parent_id": div["parent_id"],
|
|
"display_order": order,
|
|
})
|
|
order += 1
|
|
|
|
return structures
|
|
|
|
|
|
def generate_team_aliases() -> list[dict]:
|
|
"""Generate team_aliases.json data."""
|
|
aliases = []
|
|
alias_id = 1
|
|
|
|
for sport, sport_aliases in [("MLB", MLB_ALIASES), ("NBA", NBA_ALIASES), ("NHL", NHL_ALIASES)]:
|
|
for current_abbrev, alias_list in sport_aliases.items():
|
|
team_canonical_id = f"team_{sport.lower()}_{current_abbrev.lower()}"
|
|
|
|
for alias_type, alias_value, valid_from, valid_until in alias_list:
|
|
aliases.append({
|
|
"id": f"alias_{sport.lower()}_{alias_id}",
|
|
"team_canonical_id": team_canonical_id,
|
|
"alias_type": alias_type,
|
|
"alias_value": alias_value,
|
|
"valid_from": valid_from,
|
|
"valid_until": valid_until,
|
|
})
|
|
alias_id += 1
|
|
|
|
return aliases
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Generate canonical data JSON files')
|
|
parser.add_argument('--output', type=str, default='./data', help='Output directory')
|
|
args = parser.parse_args()
|
|
|
|
output_dir = Path(args.output)
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Generate league structure
|
|
print("Generating league_structure.json...")
|
|
league_structure = generate_league_structure()
|
|
with open(output_dir / 'league_structure.json', 'w') as f:
|
|
json.dump(league_structure, f, indent=2)
|
|
print(f" Created {len(league_structure)} structure entries")
|
|
|
|
# Generate team aliases
|
|
print("Generating team_aliases.json...")
|
|
team_aliases = generate_team_aliases()
|
|
with open(output_dir / 'team_aliases.json', 'w') as f:
|
|
json.dump(team_aliases, f, indent=2)
|
|
print(f" Created {len(team_aliases)} alias entries")
|
|
|
|
print(f"\nFiles written to {output_dir}")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|