Created
December 21, 2025 12:04
-
-
Save dword4/1d0eed93452db7562becb64efb08d980 to your computer and use it in GitHub Desktop.
extracts shootout details from a NHL gamecenter play-py-play call
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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