Skip to content

Instantly share code, notes, and snippets.

@dword4
Created December 21, 2025 12:04
Show Gist options
  • Select an option

  • Save dword4/1d0eed93452db7562becb64efb08d980 to your computer and use it in GitHub Desktop.

Select an option

Save dword4/1d0eed93452db7562becb64efb08d980 to your computer and use it in GitHub Desktop.
extracts shootout details from a NHL gamecenter play-py-play call
import requests
import json
def get_shootout_results(game_id):
"""
Fetch and parse shootout results from NHL API
Args:
game_id: NHL game ID (e.g., 2025020485)
Returns:
dict with shootout information
"""
url = f"https://api-web.nhle.com/v1/gamecenter/{game_id}/play-by-play"
try:
response = requests.get(url)
response.raise_for_status()
data = response.json()
# Check if shootout occurred
if not data.get('shootoutInUse', False):
return {"error": "No shootout in this game"}
# Filter plays for shootout period
shootout_plays = [
play for play in data.get('plays', [])
if play.get('periodDescriptor', {}).get('periodType') == 'SO'
]
results = []
for play in shootout_plays:
# Only look at shot attempts (goals, shots on goal, missed shots)
type_code = play.get('typeCode')
# Debug: print each shootout event
# print(f"Event {play.get('eventId')}: typeCode={type_code}, typeDescKey={play.get('typeDescKey')}")
if type_code in [505, 506, 507]: # goal, shot-on-goal, or missed shot
details = play.get('details', {})
# Goals use 'scoringPlayerId', shots/misses use 'shootingPlayerId'
shooter_id = details.get('scoringPlayerId') or details.get('shootingPlayerId')
if not shooter_id:
# print(f" Skipping - no shootingPlayerId or scoringPlayerId")
continue
# Determine result based on type code
is_goal = type_code == 505
is_save = type_code == 506
is_miss = type_code == 507
result = {
'player_id': shooter_id,
'team_id': details.get('eventOwnerTeamId'),
'shot_type': details.get('shotType', 'unknown'),
'goal': is_goal,
'saved': is_save,
'missed': is_miss,
'event_id': play.get('eventId'),
'x_coord': details.get('xCoord'),
'y_coord': details.get('yCoord')
}
# Add scoring details if it was a goal
if is_goal:
result['away_score'] = details.get('awayScore')
result['home_score'] = details.get('homeScore')
results.append(result)
# Get team info
away_team = {
'id': data['awayTeam']['id'],
'name': data['awayTeam']['commonName']['default'],
'abbrev': data['awayTeam']['abbrev']
}
home_team = {
'id': data['homeTeam']['id'],
'name': data['homeTeam']['commonName']['default'],
'abbrev': data['homeTeam']['abbrev']
}
# Get roster info for player names
roster = {}
for player in data.get('rosterSpots', []):
roster[player['playerId']] = {
'first_name': player['firstName']['default'],
'last_name': player['lastName']['default'],
'number': player['sweaterNumber']
}
# Add player names to results
for attempt in results:
player_info = roster.get(attempt['player_id'], {})
attempt['player_name'] = f"{player_info.get('first_name', 'Unknown')} {player_info.get('last_name', 'Unknown')}"
attempt['player_number'] = player_info.get('number', 'N/A')
return {
'game_id': game_id,
'away_team': away_team,
'home_team': home_team,
'shootout_attempts': results,
'total_attempts': len(results)
}
except requests.exceptions.RequestException as e:
return {"error": f"Failed to fetch data: {str(e)}"}
except json.JSONDecodeError as e:
return {"error": f"Failed to parse JSON: {str(e)}"}
# Example usage
if __name__ == "__main__":
game_id = "2025020485"
result = get_shootout_results(game_id)
if "error" in result:
print(result["error"])
else:
print(f"\n{result['away_team']['name']} vs {result['home_team']['name']}")
print(f"Game ID: {result['game_id']}")
print(f"Final Score: {result['away_team']['abbrev']} {result['away_team']['abbrev']} - {result['home_team']['abbrev']} {result['home_team']['abbrev']}")
print(f"\nShootout Attempts ({result['total_attempts']} total):\n")
for i, attempt in enumerate(result['shootout_attempts'], 1):
team = result['away_team']['abbrev'] if attempt['team_id'] == result['away_team']['id'] else result['home_team']['abbrev']
outcome = "⭐ GOAL" if attempt['goal'] else ("❌ SAVED" if attempt['saved'] else "➖ MISSED")
print(f"{i}. #{attempt['player_number']} {attempt['player_name']} ({team})")
print(f" Result: {outcome}")
print(f" Shot Type: {attempt['shot_type']}")
if attempt['goal']:
print(f" Score after: {result['away_team']['abbrev']} {attempt['away_score']} - {result['home_team']['abbrev']} {attempt['home_score']}")
print()
# Summary
goals = [a for a in result['shootout_attempts'] if a['goal']]
if goals:
print(f"\n🎯 Shootout Goals:")
for goal in goals:
team = result['away_team']['abbrev'] if goal['team_id'] == result['away_team']['id'] else result['home_team']['abbrev']
print(f" • {goal['player_name']} ({team})")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment