Pavel KerbelOr Koren
Created December 1, 2016

Fantasy Sport Skill

Around 100M people play Fantasy Sports every year! We now bring the game to your home using Alexa.

AdvancedProtip4 hours124
Fantasy Sport Skill

Things used in this project

Hardware components

Echo Dot
Amazon Alexa Echo Dot
×1

Software apps and online services

AWS Lambda
Amazon Web Services AWS Lambda
Alexa Skills Kit
Amazon Alexa Alexa Skills Kit

Story

Read more

Custom parts and enclosures

Video of Fantasy Sport skill usage

A video of how we use Fantasy Sport Skill live

Schematics

NBA Fantasy League Sequence

NBA Fantasy League Sequence

Fantasy League Alexa Skill Project Documentation

Code

fantasy_sport_lambda

JavaScript
This is a Node.js v4.3.1 code that runs on AWS lambda
'use strict';

const Alexa = require('alexa-sdk');
const util = require('util');
var OAuth = require('oauth').OAuth;
var _ = require('underscore');

const APP_ID = 'AlexaIsAwesome';

var FANTASY_STATES = {
    SETUPMODE: "_SETUPMODE", // set up league.
    STATUSMODE: "_STATUSMODE", // status of the game.
};

var LEAGUE_TYPE; // global vairiable
// for yahoo API:
var leagueTypes = {
    'NBA': 364,
    'NFL': 273,
    'NHL': 303,
    'MLB': 268
};
    
// all speach should be saved in languageStrings.
const languageStrings = {    
    'en-US': {
        translation: {
            SETUP: 'Lets set up your fantasy league team. What is your league ID?',
            STATUS: 'This is a status',
            SKILL_NAME: 'Fantasy Sport',
            GET_STATUS_MESSAGE: "Here's your status: ",
            HELP_MESSAGE: 'You can say tell me what is the status of my team?, or, you can say exit... What can I help you with?',
            HELP_REPROMPT: 'What can I help you with?',
            STOP_MESSAGE: 'Goodbye!',
        },
    },
};

var newSessionHandlers = {
     // This will short-cut any incoming intent or launch requests and route them to this handler.
    'NewSession': function() {
        if(Object.keys(this.attributes).length === 0) { // Check if it's the first time the skill has been invoked
            this.attributes['endedSessionCount'] = 0;
        }
        this.handler.state = FANTASY_STATES.SETUPMODE;
        this.emit(':ask', `Welcome to Fantasy Sport. 
            Lets login to your Fantasy NBA, NFL, NHL or MLB account.            
            `);
    }
};

var setupLeagueHandlers = Alexa.CreateStateHandler(FANTASY_STATES.SETUPMODE, {

    'SetUpMyFantasyLeagueIntent': function() {
        console.log(util.format(this.event));        
        let leagueType = this.event.request.intent.slots.LeagueType.value;

        let arr = Object.keys(leagueTypes);

        if(arr.indexOf(leagueType) == -1) {
            let message = `I do not recognized your sport. Please choose: NBA, NFL, NHL or MLB`;
            this.emit(':ask', message);
        } else {            
             
            LEAGUE_TYPE = leagueTypes[leagueType];

            let message = `Lets set up your ${leagueType} Fantasy Sport.
                           What is your league ID?`;    

            this.emit(':ask', message, message);
            
            this.attributes['leagueType'] = leagueType;
            this.emit(':saveState', true);
        }
        
    },

    'WhatisYourGroupIDIntent': function() {
          
        let LeagueId = this.event.request.intent.slots.LeagueId.value;
        
        // save in DDB  
        this.attributes['leagueId'] = LeagueId;
        this.emit(':saveState', true);     

        // response:
        let message = `Great. I got your league ID: ${LeagueId}.
        What is your team ID?`;
        this.emit(':ask', message);    

    },
    
    'WhatisYourTeamIDIntent': function() {
                
        let teamId = this.event.request.intent.slots.TeamId.value;      

        // save in DDB
        this.attributes['teamId'] = teamId;    
        
        getPlayersList(this.attributes['leagueId'], teamId, (err, res)=> {
            if (err) {
                this.emit(':tell', err.message);
            } else {
                let teamName = res.teamName;
                let playerNames = res.playerList; 
                let lastPlayer = playerNames.pop();                              
                
                // change status
                this.handler.state = FANTASY_STATES.STATUSMODE;

                // reponse:
                let message = `I Got your team set up.
                Your team name is: ${teamName}. 
                Your Players are: ${playerNames.join(', ')} and ${lastPlayer}.
                You can ask for current matchup status at any time.`;

                this.emit(':saveState', true);
                this.emit(':ask', message);                      
            }
            
        });
    
    },

    'AMAZON.HelpIntent': function() {
        var message = 'Helping, What is your league ID?';
        this.emit(':ask', message, message);
    }, 

    'SessionEndedRequest': function () {
        console.log('session ended!');
        this.attributes['endedSessionCount'] += 1;
        this.emit(':saveState', true);
    },

    'Unhandled': function() {
        var message = 'Unhandled, Welcome to Fantasy Sport.';
        this.emit(':ask', message, message);
    }
});

var statusLeagueHandlers = Alexa.CreateStateHandler(FANTASY_STATES.STATUSMODE, {    

    'GetCurrentMatchUpStatusIntent': function() {                
        
        console.log('inisde GetCurrentMatchUpStatusIntent');
        
        getMatchup(this.attributes['leagueId'], this.attributes['teamId'], null, (err, res)=> {
            console.log('inisde GetCurrentMatchUpStatusIntent callback');
            if (err) {
                this.emit(':tell', err.message);
            } else {

                // reponse:
                let message = '';                
                for (let matchup of res) {
                    message = message + ` Team: ${matchup.team_name} have ${matchup.total_points} total points.`;
                }                        
                
                this.emit(':tell', message);      
            }
            
        });
    },

    'SessionEndedRequest': function () {
        console.log('session ended!');
        this.attributes['endedSessionCount'] += 1;
        this.emit(':saveState', true);
    },

    'Unhandled': function() {
        var message = 'You can ask for Matchup';
        this.emit(':ask', message, message);
    }

    // TODO: add more funcionality here

});

/**
    call yahoo fantasy sports API.    
*/
function yahooSearch(query, count, leagueId, resource, sub_resource, callback_error_data_response){
    
    var consumerKey = 'dj0yJmk9UDNsNjRlZnR6RTNHJmQ9WVdrOVRFbDBOa0ZWTkc4bWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD0zYw--';
    var consumerSecret = 'b4f23716a82635dbb22bfc41ca8ad4924d4b96b0';

    var webSearchUrl = 'http://fantasysports.yahooapis.com/fantasy/v2/' +
    resource + '/364.l.' + leagueId + '/' + sub_resource;
    var finalUrl = webSearchUrl;

    if (query) {
        finalUrl  = webSearchUrl + ';' + query;
    }
    finalUrl  = finalUrl + '?format=json';

    var oa = new OAuth(webSearchUrl, webSearchUrl, consumerKey, consumerSecret, "1.0", null, "HMAC-SHA1");
    oa.setClientOptions({ requestTokenHttpMethod: 'GET' });
    oa.getProtectedResource(finalUrl, "GET", '','', callback_error_data_response);

};

/**
 * Get Players list and team name from API
 * @param {String} leagueId
 * @param {String} teamId
 * @return {Object} objRet
 */
function getPlayersList(leagueId, teamId, cb) {
    console.log('getting players list');
    yahooSearch(
        '',
        1,
        leagueId + '.t.' + teamId,
        'team',
        'roster/players',
        function(err, data){
            console.log('got players list', err, data);
            if (err) {
                cb(err);
            } else {
                var obj = JSON.parse(data);
                var playerList = _.map(_.filter(obj.fantasy_content.team[1].roster['0'].players, 
                    function(result,key){ 
                        if (_.isObject(result)) {
                            return result.player[0][2].name.full;
                        }
                    }),
                    function(res, key){
                    return res.player[0][2].name.full;
                });
                var teamName = obj.fantasy_content.team[0][2].name;
                var objRet = {'teamName':teamName, 'playerList': playerList};
                                
                cb(null, objRet);
            }
        }
    );
};

/**
 * Get Matchup Data for a week
 * @param {String} leagueId
 * @param {String} teamId
 * @param {String} week
 * @return {Object} objRet
 */
function getMatchup(leagueId, teamId, week, cb) {
    week = week || 'midevent';

    yahooSearch(
        '',
        1,
        leagueId + '.t.' + teamId,
        'team',
        'matchups',
        function(err, data){
            if (err) {
                cb(err);
            } else {
                var obj = JSON.parse(data);
                var Matchup = _.map(_.filter(obj.fantasy_content.team[1].matchups,                 
                function(result,key){ 
                    if (_.isObject(result) &&
                        result.matchup.status == week) {
                        return result;
                    }
                }),
                function(res, key){
                    var objRet = [];
                    // My Team Points                   
                    objRet.push({
                        'team_name': res.matchup['0'].teams['0'].team[0][2].name,
                        'total_points': res.matchup['0'].teams['0'].team[1].team_points.total
                                });
                    // Other Team Points
                    objRet.push({
                        'team_name': res.matchup['0'].teams['1'].team[0][2].name,
                        'total_points': res.matchup['0'].teams['1'].team[1].team_points.total
                                });
                    return objRet;
                });

                cb(null, Matchup[0]);
            }
        }
    );
};

exports.handler = (event, context) => {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    alexa.dynamoDBTableName = 'fantasyLeague';
    // To enable string internationalization (i18n) features, set a resources object.
    alexa.resources = languageStrings;
    alexa.registerHandlers(newSessionHandlers, setupLeagueHandlers, statusLeagueHandlers);
    alexa.execute();
};

Credits

Pavel Kerbel

Pavel Kerbel

1 project • 0 followers
Or Koren

Or Koren

1 project • 0 followers

Comments