From 5442eda9cd721a591d060d54ce10690489f52bba Mon Sep 17 00:00:00 2001 From: Alec Date: Mon, 22 Jul 2024 20:18:01 -0400 Subject: [PATCH 1/4] add current score to embed --- modules/current-play-processor.js | 14 +++++++++----- modules/gameday.js | 22 +++++++++++++--------- modules/livefeed.js | 14 ++++++++++++++ 3 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 modules/livefeed.js diff --git a/modules/current-play-processor.js b/modules/current-play-processor.js index f832a88..5a891ce 100644 --- a/modules/current-play-processor.js +++ b/modules/current-play-processor.js @@ -1,5 +1,6 @@ const globalCache = require('./global-cache'); const globals = require('../config/globals'); +const liveFeed = require('./livefeed'); module.exports = { process: (currentPlayJSON) => { @@ -40,6 +41,8 @@ module.exports = { return { reply, isStartEvent: currentPlayJSON.playEvents?.find(event => event?.details?.description === 'Status Change - In Progress'), + homeScore: currentPlayJSON.result?.homeScore, + awayScore: currentPlayJSON.result?.awayScore, isComplete: currentPlayJSON.about?.isComplete, description: (currentPlayJSON.result?.description || currentPlayJSON.details?.description), event: (currentPlayJSON.result?.event || currentPlayJSON.details?.event), @@ -54,6 +57,7 @@ module.exports = { function addScore (reply, currentPlayJSON) { reply += '\n'; + const feed = liveFeed(globalCache.values.game.currentLiveFeed); let homeScore, awayScore; if (currentPlayJSON.result) { homeScore = currentPlayJSON.result.homeScore; @@ -62,11 +66,11 @@ function addScore (reply, currentPlayJSON) { homeScore = currentPlayJSON.details.homeScore; awayScore = currentPlayJSON.details.awayScore; } - reply += (globalCache.values.game.currentLiveFeed.liveData.plays.currentPlay.about.halfInning === 'top' - ? '# _' + globalCache.values.game.currentLiveFeed.gameData.teams.away.abbreviation + ' ' + awayScore + '_, ' + - globalCache.values.game.currentLiveFeed.gameData.teams.home.abbreviation + ' ' + homeScore - : '# ' + globalCache.values.game.currentLiveFeed.gameData.teams.away.abbreviation + ' ' + awayScore + ', _' + - globalCache.values.game.currentLiveFeed.gameData.teams.home.abbreviation + ' ' + homeScore + '_'); + reply += (feed.halfInning() === 'top' + ? '# _' + feed.awayAbbreviation() + ' ' + awayScore + '_, ' + + feed.homeAbbreviation() + ' ' + homeScore + : '# ' + feed.awayAbbreviation() + ' ' + awayScore + ', _' + + feed.homeAbbreviation() + ' ' + homeScore + '_'); return reply; } diff --git a/modules/gameday.js b/modules/gameday.js index 7b4429a..080b8ea 100644 --- a/modules/gameday.js +++ b/modules/gameday.js @@ -6,6 +6,7 @@ const { EmbedBuilder } = require('discord.js'); const globals = require('../config/globals'); const LOGGER = require('./logger')(process.env.LOG_LEVEL?.trim() || globals.LOG_LEVEL.INFO); const ColorContrastChecker = require('color-contrast-checker'); +const liveFeed = require('./livefeed'); module.exports = { statusPoll, subscribe, getConstrastingEmbedColors, processAndPushPlay, pollForSavantData, processMatchingPlay @@ -103,11 +104,12 @@ function subscribe (bot, liveGame, games) { } function getConstrastingEmbedColors () { + const feed = liveFeed(globalCache.values.game.currentLiveFeed); globalCache.values.game.homeTeamColor = globals.TEAMS.find( - team => team.id === globalCache.values.game.currentLiveFeed.gameData.teams.home.id + team => team.id === feed.homeTeamId() ).primaryColor; const awayTeam = globals.TEAMS.find( - team => team.id === globalCache.values.game.currentLiveFeed.gameData.teams.away.id + team => team.id === feed.awayTeamId() ); const colorContrastChecker = new ColorContrastChecker(); if (colorContrastChecker.isLevelCustom(globalCache.values.game.homeTeamColor, awayTeam.primaryColor, globals.TEAM_COLOR_CONTRAST_RATIO)) { @@ -118,11 +120,12 @@ function getConstrastingEmbedColors () { } async function reportPlays (bot, gamePk) { - const currentPlay = globalCache.values.game.currentLiveFeed.liveData.plays.currentPlay; + const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const currentPlay = feed.currentPlay(); const atBatIndex = currentPlay.atBatIndex; const lastReportedCompleteAtBatIndex = globalCache.values.game.lastReportedCompleteAtBatIndex; if (atBatIndex > 0) { - const lastAtBat = globalCache.values.game.currentLiveFeed.liveData.plays.allPlays + const lastAtBat = feed.allPlays() .find((play) => play.about.atBatIndex === atBatIndex - 1); if (lastAtBat && lastAtBat.about.hasReview) { // a play that's been challenged. We should report updates on it. await processAndPushPlay(bot, currentPlayProcessor.process(lastAtBat), gamePk, atBatIndex - 1); @@ -154,16 +157,17 @@ async function processAndPushPlay (bot, play, gamePk, atBatIndex) { && !globalCache.values.game.reportedDescriptions .find(reportedDescription => reportedDescription.description === play.description && reportedDescription.atBatIndex === atBatIndex)) { globalCache.values.game.reportedDescriptions.push({ description: play.description, atBatIndex }); + const feed = liveFeed(globalCache.values.game.currentLiveFeed); if (play.isComplete) { globalCache.values.game.lastReportedCompleteAtBatIndex = atBatIndex; } const embed = new EmbedBuilder() - .setTitle(deriveHalfInning(globalCache.values.game.currentLiveFeed.liveData.plays.currentPlay.about.halfInning) + ' ' + - globalCache.values.game.currentLiveFeed.liveData.plays.currentPlay.about.inning + ', ' + - globalCache.values.game.currentLiveFeed.gameData.teams.away.abbreviation + ' vs. ' + - globalCache.values.game.currentLiveFeed.gameData.teams.home.abbreviation + (play.isScoringPlay ? ' - Scoring Play \u2757' : '')) + .setTitle(deriveHalfInning(feed.halfInning()) + ' ' + + feed.inning() + ', ' + + feed.awayAbbreviation() + (play.isScoringPlay ? ' vs. ' : ' ' + play.awayScore + ' - ' + play.homeScore + ' ') + + feed.homeAbbreviation() + (play.isScoringPlay ? ' - Scoring Play \u2757' : '')) .setDescription(play.reply) - .setColor((globalCache.values.game.currentLiveFeed.liveData.plays.currentPlay.about.halfInning === 'top' + .setColor((feed.halfInning() === 'top' ? globalCache.values.game.awayTeamColor : globalCache.values.game.homeTeamColor )); diff --git a/modules/livefeed.js b/modules/livefeed.js new file mode 100644 index 0000000..cd4f176 --- /dev/null +++ b/modules/livefeed.js @@ -0,0 +1,14 @@ +module.exports = (liveFeed) => { + return { + timestamp: () => { return liveFeed.metaData.timeStamp; }, + inning: () => { return liveFeed.liveData.plays.currentPlay.about.inning; }, + halfInning: () => { return liveFeed.liveData.plays.currentPlay.about.halfInning; }, + awayAbbreviation: () => { return liveFeed.gameData.teams.away.abbreviation; }, + homeAbbreviation: () => { return liveFeed.gameData.teams.home.abbreviation; }, + homeTeamId: () => { return liveFeed.gameData.teams.home.id; }, + awayTeamId: () => { return liveFeed.gameData.teams.away.id; }, + currentPlay: () => { return liveFeed.liveData.plays.currentPlay; }, + allPlays: () => { return liveFeed.liveData.plays.allPlays; } + + }; +}; From 7fa727e7b7c9b3b4a6f2b66340c8424230d5c7ce Mon Sep 17 00:00:00 2001 From: Alec Date: Tue, 23 Jul 2024 00:09:35 -0400 Subject: [PATCH 2/4] due up, indicate barrels --- modules/current-play-processor.js | 20 +++++++++++--------- modules/gameday.js | 28 +++++++++++++++++++++++----- modules/livefeed.js | 4 ++-- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/modules/current-play-processor.js b/modules/current-play-processor.js index 5a891ce..63681ae 100644 --- a/modules/current-play-processor.js +++ b/modules/current-play-processor.js @@ -38,11 +38,16 @@ module.exports = { } } } + /* two kinds of objects get processed - "at bats", which will have a "result" object, and events within at bats, which put + the same information in a "details" object. So we often have to check for both. + */ return { reply, isStartEvent: currentPlayJSON.playEvents?.find(event => event?.details?.description === 'Status Change - In Progress'), - homeScore: currentPlayJSON.result?.homeScore, - awayScore: currentPlayJSON.result?.awayScore, + isOut: currentPlayJSON.result?.isOut || currentPlayJSON.details?.isOut, + outs: currentPlayJSON.count?.outs, + homeScore: (currentPlayJSON.result ? currentPlayJSON.result.homeScore : currentPlayJSON.details?.homeScore), + awayScore: (currentPlayJSON.result ? currentPlayJSON.result.awayScore : currentPlayJSON.details?.awayScore), isComplete: currentPlayJSON.about?.isComplete, description: (currentPlayJSON.result?.description || currentPlayJSON.details?.description), event: (currentPlayJSON.result?.event || currentPlayJSON.details?.event), @@ -50,6 +55,7 @@ module.exports = { isScoringPlay: (currentPlayJSON.about?.isScoringPlay || currentPlayJSON.details?.isScoringPlay), isInPlay: (lastEvent?.details?.isInPlay || currentPlayJSON.details?.isInPlay), playId: (lastEvent?.playId || currentPlayJSON.playId), + metricsAvailable: (lastEvent?.hitData?.launchSpeed !== undefined || currentPlayJSON.hitData?.launchSpeed !== undefined), hitDistance: (lastEvent?.hitData?.totalDistance || currentPlayJSON.hitData?.totalDistance) }; } @@ -82,15 +88,11 @@ function addMetrics (lastEvent, reply) { getFireEmojis(lastEvent.hitData.launchSpeed) + '\n'; reply += 'Launch Angle: ' + lastEvent.hitData.launchAngle + '° \n'; reply += 'Distance: ' + lastEvent.hitData.totalDistance + ' ft.\n'; - reply += 'xBA: Pending...\n'; - reply += lastEvent.hitData.totalDistance && lastEvent.hitData.totalDistance >= 300 ? 'HR/Park: Pending...' : ''; + reply += 'xBA: Pending...'; + reply += lastEvent.hitData.totalDistance && lastEvent.hitData.totalDistance >= 300 ? '\nHR/Park: Pending...' : ''; } else { reply += '\n\n**Statcast Metrics:**\n'; - reply += 'Exit Velocity: Unavailable\n'; - reply += 'Launch Angle: Unavailable\n'; - reply += 'Distance: Unavailable\n'; - reply += 'xBA: Unavailable\n'; - reply += 'HR/Park: Unavailable'; + reply += 'Data was not available.'; } return reply; diff --git a/modules/gameday.js b/modules/gameday.js index 080b8ea..1d29ac6 100644 --- a/modules/gameday.js +++ b/modules/gameday.js @@ -164,9 +164,11 @@ async function processAndPushPlay (bot, play, gamePk, atBatIndex) { const embed = new EmbedBuilder() .setTitle(deriveHalfInning(feed.halfInning()) + ' ' + feed.inning() + ', ' + - feed.awayAbbreviation() + (play.isScoringPlay ? ' vs. ' : ' ' + play.awayScore + ' - ' + play.homeScore + ' ') + + feed.awayAbbreviation() + (play.isScoringPlay + ? ' vs. ' + : ' ' + play.awayScore + ' - ' + play.homeScore + ' ') + feed.homeAbbreviation() + (play.isScoringPlay ? ' - Scoring Play \u2757' : '')) - .setDescription(play.reply) + .setDescription(play.reply + (play.isOut && play.outs === 3 && !didGameEnd(play.homeScore, play.awayScore) ? getDueUp() : '')) .setColor((feed.halfInning() === 'top' ? globalCache.values.game.awayTeamColor : globalCache.values.game.homeTeamColor @@ -191,6 +193,22 @@ async function processAndPushPlay (bot, play, gamePk, atBatIndex) { } } +function didGameEnd (homeScore, awayScore) { + const feed = liveFeed(globalCache.values.game.currentLiveFeed); + return feed.linescore().currentInning >= 9 + && ( + (homeScore > awayScore && feed.linescore().inningState === 'Top') + || (awayScore > homeScore && feed.linescore().inningState === 'Bottom') + ); +} + +function getDueUp () { + const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const linescore = feed.linescore(); + + return '\n\n**Due up**: ' + linescore.offense.batter.fullName + ', ' + linescore.offense.onDeck.fullName + ', ' + linescore.offense.inHole.fullName; +} + async function sendMessage (returnedChannel, embed, messages) { LOGGER.debug('Sending!'); const message = await returnedChannel.send({ @@ -213,7 +231,7 @@ async function sendDelayedMessage (play, gamePk, channelSubscription, returnedCh } async function maybePopulateAdvancedStatcastMetrics (play, messages, gamePk) { - if (play.isInPlay) { + if (play.isInPlay && play.metricsAvailable) { if (play.playId) { try { // xBA and HR/Park for balls in play is available on a delay via baseballsavant. @@ -228,7 +246,7 @@ async function maybePopulateAdvancedStatcastMetrics (play, messages, gamePk) { notifySavantDataUnavailable(messages); } } else { - LOGGER.debug('Skipping savant poll - not in play.'); + LOGGER.debug('Skipping savant poll - not in play or metrics unavailable.'); } } @@ -277,7 +295,7 @@ function processMatchingPlay (matchingPlay, messages, messageTrackers, playId, h if (matchingPlay.xba && description.includes('xBA: Pending...')) { LOGGER.debug('Editing with xba: ' + playId); description = description.replaceAll('xBA: Pending...', 'xBA: ' + matchingPlay.xba + - (parseFloat(matchingPlay.xba) > 0.5 ? ' \uD83D\uDFE2' : '')); + (matchingPlay.is_barrel === 1 ? ' \uD83D\uDFE2 (Barreled)' : '')); receivedEmbed.setDescription(description); messages[i].edit({ embeds: [receivedEmbed] diff --git a/modules/livefeed.js b/modules/livefeed.js index cd4f176..73b88f8 100644 --- a/modules/livefeed.js +++ b/modules/livefeed.js @@ -8,7 +8,7 @@ module.exports = (liveFeed) => { homeTeamId: () => { return liveFeed.gameData.teams.home.id; }, awayTeamId: () => { return liveFeed.gameData.teams.away.id; }, currentPlay: () => { return liveFeed.liveData.plays.currentPlay; }, - allPlays: () => { return liveFeed.liveData.plays.allPlays; } - + allPlays: () => { return liveFeed.liveData.plays.allPlays; }, + linescore: () => { return liveFeed.liveData.linescore; } }; }; From 58afed7183b7536733f741da1d9d43adbea447e9 Mon Sep 17 00:00:00 2001 From: Alec Date: Tue, 23 Jul 2024 00:43:41 -0400 Subject: [PATCH 3/4] refactor --- modules/gameday-util.js | 42 +++++++++++++++++++++++++++++++++++++ modules/gameday.js | 46 +++++------------------------------------ spec/gameday-spec.js | 7 ++++--- 3 files changed, 51 insertions(+), 44 deletions(-) create mode 100644 modules/gameday-util.js diff --git a/modules/gameday-util.js b/modules/gameday-util.js new file mode 100644 index 0000000..8ad92b6 --- /dev/null +++ b/modules/gameday-util.js @@ -0,0 +1,42 @@ +const liveFeed = require('./livefeed'); +const globalCache = require('./global-cache'); +const globals = require('../config/globals'); +const ColorContrastChecker = require('color-contrast-checker'); + +module.exports = { + deriveHalfInning: (halfInningFull) => { + return halfInningFull === 'top' ? 'TOP' : 'BOT'; + }, + + didGameEnd: (homeScore, awayScore) => { + const feed = liveFeed(globalCache.values.game.currentLiveFeed); + return feed.inning() >= 9 + && ( + (homeScore > awayScore && feed.halfInning() === 'top') + || (awayScore > homeScore && feed.halfInning() === 'bottom') + ); + }, + + getConstrastingEmbedColors: () => { + const feed = liveFeed(globalCache.values.game.currentLiveFeed); + globalCache.values.game.homeTeamColor = globals.TEAMS.find( + team => team.id === feed.homeTeamId() + ).primaryColor; + const awayTeam = globals.TEAMS.find( + team => team.id === feed.awayTeamId() + ); + const colorContrastChecker = new ColorContrastChecker(); + if (colorContrastChecker.isLevelCustom(globalCache.values.game.homeTeamColor, awayTeam.primaryColor, globals.TEAM_COLOR_CONTRAST_RATIO)) { + globalCache.values.game.awayTeamColor = awayTeam.primaryColor; + } else { + globalCache.values.game.awayTeamColor = awayTeam.secondaryColor; + } + }, + + getDueUp: () => { + const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const linescore = feed.linescore(); + + return '\n\n**Due up**: ' + linescore.offense.batter.fullName + ', ' + linescore.offense.onDeck.fullName + ', ' + linescore.offense.inHole.fullName; + } +} diff --git a/modules/gameday.js b/modules/gameday.js index 1d29ac6..639210e 100644 --- a/modules/gameday.js +++ b/modules/gameday.js @@ -5,11 +5,11 @@ const currentPlayProcessor = require('./current-play-processor'); const { EmbedBuilder } = require('discord.js'); const globals = require('../config/globals'); const LOGGER = require('./logger')(process.env.LOG_LEVEL?.trim() || globals.LOG_LEVEL.INFO); -const ColorContrastChecker = require('color-contrast-checker'); const liveFeed = require('./livefeed'); +const gamedayUtil = require('./gameday-util'); module.exports = { - statusPoll, subscribe, getConstrastingEmbedColors, processAndPushPlay, pollForSavantData, processMatchingPlay + statusPoll, subscribe, processAndPushPlay, pollForSavantData, processMatchingPlay }; async function statusPoll (bot) { @@ -30,7 +30,7 @@ async function statusPoll (bot) { LOGGER.info('Gameday: polling stopped: a game is live.'); globalCache.resetGameCache(); globalCache.values.game.currentLiveFeed = await mlbAPIUtil.liveFeed(inProgressGame.gamePk); - module.exports.getConstrastingEmbedColors(); + gamedayUtil.getConstrastingEmbedColors(); module.exports.subscribe(bot, inProgressGame, nearestGames); } else { setTimeout(pollingFunction, globals.SLOW_POLL_INTERVAL); @@ -103,22 +103,6 @@ function subscribe (bot, liveGame, games) { ws.addEventListener('close', (e) => LOGGER.info('Gameday socket closed: ' + JSON.stringify(e))); } -function getConstrastingEmbedColors () { - const feed = liveFeed(globalCache.values.game.currentLiveFeed); - globalCache.values.game.homeTeamColor = globals.TEAMS.find( - team => team.id === feed.homeTeamId() - ).primaryColor; - const awayTeam = globals.TEAMS.find( - team => team.id === feed.awayTeamId() - ); - const colorContrastChecker = new ColorContrastChecker(); - if (colorContrastChecker.isLevelCustom(globalCache.values.game.homeTeamColor, awayTeam.primaryColor, globals.TEAM_COLOR_CONTRAST_RATIO)) { - globalCache.values.game.awayTeamColor = awayTeam.primaryColor; - } else { - globalCache.values.game.awayTeamColor = awayTeam.secondaryColor; - } -} - async function reportPlays (bot, gamePk) { const feed = liveFeed(globalCache.values.game.currentLiveFeed); const currentPlay = feed.currentPlay(); @@ -162,13 +146,13 @@ async function processAndPushPlay (bot, play, gamePk, atBatIndex) { globalCache.values.game.lastReportedCompleteAtBatIndex = atBatIndex; } const embed = new EmbedBuilder() - .setTitle(deriveHalfInning(feed.halfInning()) + ' ' + + .setTitle(gamedayUtil.deriveHalfInning(feed.halfInning()) + ' ' + feed.inning() + ', ' + feed.awayAbbreviation() + (play.isScoringPlay ? ' vs. ' : ' ' + play.awayScore + ' - ' + play.homeScore + ' ') + feed.homeAbbreviation() + (play.isScoringPlay ? ' - Scoring Play \u2757' : '')) - .setDescription(play.reply + (play.isOut && play.outs === 3 && !didGameEnd(play.homeScore, play.awayScore) ? getDueUp() : '')) + .setDescription(play.reply + (play.isOut && play.outs === 3 && !gamedayUtil.didGameEnd(play.homeScore, play.awayScore) ? gamedayUtil.getDueUp() : '')) .setColor((feed.halfInning() === 'top' ? globalCache.values.game.awayTeamColor : globalCache.values.game.homeTeamColor @@ -193,22 +177,6 @@ async function processAndPushPlay (bot, play, gamePk, atBatIndex) { } } -function didGameEnd (homeScore, awayScore) { - const feed = liveFeed(globalCache.values.game.currentLiveFeed); - return feed.linescore().currentInning >= 9 - && ( - (homeScore > awayScore && feed.linescore().inningState === 'Top') - || (awayScore > homeScore && feed.linescore().inningState === 'Bottom') - ); -} - -function getDueUp () { - const feed = liveFeed(globalCache.values.game.currentLiveFeed); - const linescore = feed.linescore(); - - return '\n\n**Due up**: ' + linescore.offense.batter.fullName + ', ' + linescore.offense.onDeck.fullName + ', ' + linescore.offense.inHole.fullName; -} - async function sendMessage (returnedChannel, embed, messages) { LOGGER.debug('Sending!'); const message = await returnedChannel.send({ @@ -323,7 +291,3 @@ function processMatchingPlay (matchingPlay, messages, messageTrackers, playId, h } } } - -function deriveHalfInning (halfInningFull) { - return halfInningFull === 'top' ? 'TOP' : 'BOT'; -} diff --git a/spec/gameday-spec.js b/spec/gameday-spec.js index 644d443..15f8922 100644 --- a/spec/gameday-spec.js +++ b/spec/gameday-spec.js @@ -1,4 +1,5 @@ const gameday = require('../modules/gameday'); +const gamedayUtil = require('../modules/gameday-util') const mlbAPIUtil = require('../modules/MLB-API-util'); const globals = require('../config/globals'); const mockResponses = require('./data/mock-responses'); @@ -8,7 +9,7 @@ const { EmbedBuilder } = require('discord.js'); describe('gameday', () => { describe('#statusPoll', () => { beforeEach(() => { - spyOn(gameday, 'getConstrastingEmbedColors').and.stub(); + spyOn(gamedayUtil, 'getConstrastingEmbedColors').and.stub(); spyOn(mlbAPIUtil, 'liveFeed').and.callFake((gamePk, fields) => { return {}; }); @@ -23,7 +24,7 @@ describe('gameday', () => { expect(gameday.subscribe).toHaveBeenCalled(); expect(mlbAPIUtil.liveFeed).toHaveBeenCalled(); expect(globalCache.resetGameCache).toHaveBeenCalled(); - expect(gameday.getConstrastingEmbedColors).toHaveBeenCalled(); + expect(gamedayUtil.getConstrastingEmbedColors).toHaveBeenCalled(); }); it('should continue polling if no game is live', async () => { @@ -39,7 +40,7 @@ describe('gameday', () => { expect(gameday.subscribe).not.toHaveBeenCalled(); expect(mlbAPIUtil.liveFeed).not.toHaveBeenCalled(); expect(globalCache.resetGameCache).not.toHaveBeenCalled(); - expect(gameday.getConstrastingEmbedColors).not.toHaveBeenCalled(); + expect(gamedayUtil.getConstrastingEmbedColors).not.toHaveBeenCalled(); jasmine.clock().uninstall(); }); }); From e7029956b2e9ec4ccde810fb4ef1dfb1a9814022 Mon Sep 17 00:00:00 2001 From: Alec Date: Tue, 23 Jul 2024 00:57:09 -0400 Subject: [PATCH 4/4] specs --- modules/current-play-processor.js | 2 +- modules/gameday-util.js | 10 +++--- modules/gameday.js | 4 +-- modules/livefeed.js | 48 +++++++++++++++++++++-------- spec/command-util-spec.js | 2 +- spec/current-play-processor-spec.js | 2 +- spec/diff-patch-spec.js | 2 +- spec/gameday-spec.js | 2 +- spec/gameday-util-spec.js | 48 +++++++++++++++++++++++++++++ 9 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 spec/gameday-util-spec.js diff --git a/modules/current-play-processor.js b/modules/current-play-processor.js index 63681ae..36e89f5 100644 --- a/modules/current-play-processor.js +++ b/modules/current-play-processor.js @@ -63,7 +63,7 @@ module.exports = { function addScore (reply, currentPlayJSON) { reply += '\n'; - const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const feed = liveFeed.init(globalCache.values.game.currentLiveFeed); let homeScore, awayScore; if (currentPlayJSON.result) { homeScore = currentPlayJSON.result.homeScore; diff --git a/modules/gameday-util.js b/modules/gameday-util.js index 8ad92b6..531ec60 100644 --- a/modules/gameday-util.js +++ b/modules/gameday-util.js @@ -9,7 +9,7 @@ module.exports = { }, didGameEnd: (homeScore, awayScore) => { - const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const feed = liveFeed.init(globalCache.values.game.currentLiveFeed); return feed.inning() >= 9 && ( (homeScore > awayScore && feed.halfInning() === 'top') @@ -18,7 +18,7 @@ module.exports = { }, getConstrastingEmbedColors: () => { - const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const feed = liveFeed.init(globalCache.values.game.currentLiveFeed); globalCache.values.game.homeTeamColor = globals.TEAMS.find( team => team.id === feed.homeTeamId() ).primaryColor; @@ -34,9 +34,9 @@ module.exports = { }, getDueUp: () => { - const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const feed = liveFeed.init(globalCache.values.game.currentLiveFeed); const linescore = feed.linescore(); - return '\n\n**Due up**: ' + linescore.offense.batter.fullName + ', ' + linescore.offense.onDeck.fullName + ', ' + linescore.offense.inHole.fullName; + return '\n\n**Due up**: ' + linescore.offense?.batter?.fullName + ', ' + linescore.offense?.onDeck?.fullName + ', ' + linescore.offense?.inHole?.fullName; } -} +}; diff --git a/modules/gameday.js b/modules/gameday.js index 639210e..30daa3a 100644 --- a/modules/gameday.js +++ b/modules/gameday.js @@ -104,7 +104,7 @@ function subscribe (bot, liveGame, games) { } async function reportPlays (bot, gamePk) { - const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const feed = liveFeed.init(globalCache.values.game.currentLiveFeed); const currentPlay = feed.currentPlay(); const atBatIndex = currentPlay.atBatIndex; const lastReportedCompleteAtBatIndex = globalCache.values.game.lastReportedCompleteAtBatIndex; @@ -141,7 +141,7 @@ async function processAndPushPlay (bot, play, gamePk, atBatIndex) { && !globalCache.values.game.reportedDescriptions .find(reportedDescription => reportedDescription.description === play.description && reportedDescription.atBatIndex === atBatIndex)) { globalCache.values.game.reportedDescriptions.push({ description: play.description, atBatIndex }); - const feed = liveFeed(globalCache.values.game.currentLiveFeed); + const feed = liveFeed.init(globalCache.values.game.currentLiveFeed); if (play.isComplete) { globalCache.values.game.lastReportedCompleteAtBatIndex = atBatIndex; } diff --git a/modules/livefeed.js b/modules/livefeed.js index 73b88f8..b0f06be 100644 --- a/modules/livefeed.js +++ b/modules/livefeed.js @@ -1,14 +1,36 @@ -module.exports = (liveFeed) => { - return { - timestamp: () => { return liveFeed.metaData.timeStamp; }, - inning: () => { return liveFeed.liveData.plays.currentPlay.about.inning; }, - halfInning: () => { return liveFeed.liveData.plays.currentPlay.about.halfInning; }, - awayAbbreviation: () => { return liveFeed.gameData.teams.away.abbreviation; }, - homeAbbreviation: () => { return liveFeed.gameData.teams.home.abbreviation; }, - homeTeamId: () => { return liveFeed.gameData.teams.home.id; }, - awayTeamId: () => { return liveFeed.gameData.teams.away.id; }, - currentPlay: () => { return liveFeed.liveData.plays.currentPlay; }, - allPlays: () => { return liveFeed.liveData.plays.allPlays; }, - linescore: () => { return liveFeed.liveData.linescore; } - }; +module.exports = { + init: (liveFeed) => { + return { + timestamp: () => { + return liveFeed.metaData.timeStamp; + }, + inning: () => { + return liveFeed.liveData.plays.currentPlay.about.inning; + }, + halfInning: () => { + return liveFeed.liveData.plays.currentPlay.about.halfInning; + }, + awayAbbreviation: () => { + return liveFeed.gameData.teams.away.abbreviation; + }, + homeAbbreviation: () => { + return liveFeed.gameData.teams.home.abbreviation; + }, + homeTeamId: () => { + return liveFeed.gameData.teams.home.id; + }, + awayTeamId: () => { + return liveFeed.gameData.teams.away.id; + }, + currentPlay: () => { + return liveFeed.liveData.plays.currentPlay; + }, + allPlays: () => { + return liveFeed.liveData.plays.allPlays; + }, + linescore: () => { + return liveFeed.liveData.linescore; + } + }; + } }; diff --git a/spec/command-util-spec.js b/spec/command-util-spec.js index c40cb28..d2b5d47 100644 --- a/spec/command-util-spec.js +++ b/spec/command-util-spec.js @@ -1,6 +1,6 @@ const commandUtil = require('../modules/command-util'); -describe('commandUtil', () => { +describe('command-util', () => { beforeAll(() => {}); describe('#formatSplits', () => { it('should format splits for a player that has played on multiple teams in a season', async () => { diff --git a/spec/current-play-processor-spec.js b/spec/current-play-processor-spec.js index 8bf3b00..5d72b5d 100644 --- a/spec/current-play-processor-spec.js +++ b/spec/current-play-processor-spec.js @@ -2,7 +2,7 @@ const currentPlayProcessor = require('../modules/current-play-processor'); const globalCache = require('../modules/global-cache'); const examplePlays = require('./data/example-plays'); -describe('currentPlayProcessor', () => { +describe('current-play-processor', () => { beforeAll(() => { globalCache.values.game.currentLiveFeed = require('./data/example-live-feed'); }); diff --git a/spec/diff-patch-spec.js b/spec/diff-patch-spec.js index e833f0c..0025566 100644 --- a/spec/diff-patch-spec.js +++ b/spec/diff-patch-spec.js @@ -3,7 +3,7 @@ const fs = require('fs'); const globalCache = require('../modules/global-cache'); const path = require('path'); -describe('diffPatch', () => { +describe('diff-patch', () => { let diff; beforeAll(() => { diff --git a/spec/gameday-spec.js b/spec/gameday-spec.js index 15f8922..767db06 100644 --- a/spec/gameday-spec.js +++ b/spec/gameday-spec.js @@ -1,5 +1,5 @@ const gameday = require('../modules/gameday'); -const gamedayUtil = require('../modules/gameday-util') +const gamedayUtil = require('../modules/gameday-util'); const mlbAPIUtil = require('../modules/MLB-API-util'); const globals = require('../config/globals'); const mockResponses = require('./data/mock-responses'); diff --git a/spec/gameday-util-spec.js b/spec/gameday-util-spec.js new file mode 100644 index 0000000..fe9ed0d --- /dev/null +++ b/spec/gameday-util-spec.js @@ -0,0 +1,48 @@ +const gamedayUtil = require('../modules/gameday-util'); +const liveFeed = require('../modules/livefeed'); + +describe('gameday-util', () => { + beforeAll(() => {}); + + describe('#didGameEnd', () => { + it('should say the game ended when the top of the 9th ended with the home team leading', async () => { + spyOn(liveFeed, 'init').and.returnValue({ + inning: () => { return 9; }, + halfInning: () => { return 'top'; } + }); + expect(gamedayUtil.didGameEnd(3, 2)).toBeTrue(); + }); + + it('should say the game ended when the bottom of the 9th ended with the away team leading', async () => { + spyOn(liveFeed, 'init').and.returnValue({ + inning: () => { return 9; }, + halfInning: () => { return 'bottom'; } + }); + expect(gamedayUtil.didGameEnd(2, 3)).toBeTrue(); + }); + + it('should say the game is still going if the game is tied', async () => { + spyOn(liveFeed, 'init').and.returnValue({ + inning: () => { return 9; }, + halfInning: () => { return 'bottom'; } + }); + expect(gamedayUtil.didGameEnd(3, 3)).toBeFalse(); + }); + + it('should say the game is still going the top of the 9th has ended with the away team leading', async () => { + spyOn(liveFeed, 'init').and.returnValue({ + inning: () => { return 9; }, + halfInning: () => { return 'top'; } + }); + expect(gamedayUtil.didGameEnd(3, 10)).toBeFalse(); + }); + + it('should say the game ended when the top of an extra inning ended with the home team leading', async () => { + spyOn(liveFeed, 'init').and.returnValue({ + inning: () => { return 15; }, + halfInning: () => { return 'top'; } + }); + expect(gamedayUtil.didGameEnd(3, 2)).toBeTrue(); + }); + }); +});