The NHL has an interesting API that can access a wide range of information. It isn’t officially documented but I found some decent informal documentation.

For fun, I wrote a Python program to get the live feed for the games going on today. It’s nothing special but was an interesting diversion. The biggest challenge is working with the live feed when I want to watch the game.

The code is below:

from datetime import datetime
import jmespath
import json
import requests
from requests.exceptions import HTTPError
import sys
import time

BASE_URL = 'https://statsapi.web.nhl.com'


def main():

    # get today's date in yyyy-mm-dd format
    today = datetime.today().strftime('%Y-%m-%d')

    active_games = get_active_games(today)
    if len(active_games) == 0:
        print("No active games")
        sys.exit()

    # loop through and get the live information for each game
    while True:
        for game_url in active_games:
            res = get_url(game_url)
            # get the teams
            away = jmespath.search("gameData.teams.away.name", res)
            home = jmespath.search("gameData.teams.home.name", res)
            # get the game status
            status = jmespath.search("gameData.status.detailedState", res)
            # remove the games that are postponed or final
            if status == "Postponed" or  status == "Final":
                active_games.remove(game_url)
            else:
                # get the last play
                current_play = jmespath.search("liveData.plays.allPlays[-1].result.event", res)
                print(f"{away} @ {home}: {current_play}")

        # sleep after each round
        time.sleep(10)
        # stop the loop if there are no more games left
        if len(active_games) == 0:
            print("All active games complete")
            sys.exit()


def get_active_games(date):
    """ get_active_games returns array of games for date in yyyy-mm-dd format """

    calendar_url = BASE_URL + '/api/v1/schedule?date=' + date
    res = get_url(calendar_url)
    current_games = jmespath.search("dates[0].games[].link", res)

    # check the live feed for the status of the games
    active_games = []
    for link in current_games:
        game_url = BASE_URL + link
        res = get_url(game_url)
        # get the game status
        status = jmespath.search("gameData.status.detailedState", res)
        away = jmespath.search("gameData.teams.away.name", res)
        home = jmespath.search("gameData.teams.home.name", res)

        # remove the games that are postponed or final
        if status == "Postponed":
            print(f"{away} at {home} postponed")
        elif status == "Final":
            away_goals = jmespath.search("liveData.linescore.teams.away.goals", res)
            home_goals = jmespath.search("liveData.linescore.teams.home.goals", res)
            print(f"Final {away}:{away_goals} {home}:{home_goals}")
        else:
            active_games.append(game_url)

    return active_games


def get_url(url):
    """ get_url returns json string for a given url or prints an error """

    try:
        response = requests.get(url)
        response.raise_for_status()
    except HTTPError as http_err:
        print(f'HTTP error: {http_error}')
    except Exception as err:
        print('Error: {err}')
    else:
        return response.json()


if __name__ == "__main__":
    main()