├── .gitignore ├── LICENSE ├── package.json ├── README.md ├── test └── index.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, James Weston 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mlbprobablepitchers", 3 | "version": "2.0.0", 4 | "description": "Get JSON object with MLB Probable Pitchers for a given day", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "lab -m 9999 -v -L -t 100" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/jaw187/mlbprobablepitchers.git" 12 | }, 13 | "keywords": [ 14 | "MLB", 15 | "Probable", 16 | "Pitchers" 17 | ], 18 | "author": "James Weston", 19 | "license": "ISC", 20 | "bugs": { 21 | "url": "https://github.com/jaw187/mlbprobablepitchers/issues" 22 | }, 23 | "homepage": "https://github.com/jaw187/mlbprobablepitchers#readme", 24 | "dependencies": { 25 | "x-ray": "2.x.x" 26 | }, 27 | "devDependencies": { 28 | "code": "2.x.x", 29 | "lab": "15.x.x" 30 | }, 31 | "engines": { 32 | "node": ">= 8.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mlbprobablepitchers 2 | Get JSON object with MLB Probable Pitchers for a given day 3 | 4 | ## Install 5 | ``` 6 | npm install mlbprobablepitchers 7 | ``` 8 | 9 | ## Usage 10 | ```javascript 11 | const Probables = require('mlbprobablepitchers'); 12 | const day = '2011/07/23'; 13 | 14 | Probables.get(day, (err, matchups) => { 15 | 16 | // do something 17 | }); 18 | ``` 19 | 20 | ## Example matchup 21 | ```javascript 22 | { 23 | "id": "2011/07/23/houmlb-chnmlb-1", 24 | "startTime": "2011-07-23T12:05:00", 25 | "easternTime": "2011-07-23T13:05:00", 26 | "timezone": "CDT", 27 | "teams": { 28 | "away": "112", 29 | "home": "117" 30 | }, 31 | "pitchers": { 32 | "away": { 33 | "id": "434643", 34 | "name": "Wandy Rodriguez", 35 | "throws": "LHP" 36 | }, 37 | "home": { 38 | "id": "448694", 39 | "name": "Randy Wells", 40 | "throws": "RHP" 41 | } 42 | } 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Probables = require('../'); 4 | const { expect } = require('code'); 5 | const { it, describe } = exports.lab = require('lab').script(); 6 | 7 | describe('MLB Probable Pitchers', () => { 8 | 9 | const day = '2011/07/23'; 10 | it(`Gets probables using date syntax ${day}`, (done) => { 11 | 12 | Probables.get(day, (err, dailyMatchups) => { 13 | 14 | expect(err).to.not.exist(); 15 | expect(dailyMatchups).to.exist(); 16 | expect(dailyMatchups.length).to.equal(15); 17 | expect(dailyMatchups[0].teams).to.exist(); 18 | expect(dailyMatchups[0].teams.away).to.equal('Astros'); 19 | expect(dailyMatchups[0].pitchers).to.exist(); 20 | expect(dailyMatchups[0].pitchers.away).to.exist(); 21 | expect(dailyMatchups[0].pitchers.away.id).to.equal('434643'); 22 | expect(dailyMatchups[0].pitchers.home).to.exist(); 23 | expect(dailyMatchups[0].pitchers.home.id).to.equal('448694'); 24 | done(); 25 | 26 | }); 27 | }); 28 | 29 | const dateDashes = '2011-07-23'; 30 | it(`Gets probables using date syntax ${dateDashes}`, (done) => { 31 | 32 | Probables.get(day, (err, dailyMatchups) => { 33 | 34 | expect(err).to.not.exist(); 35 | expect(dailyMatchups).to.exist(); 36 | expect(dailyMatchups.length).to.equal(15); 37 | expect(dailyMatchups[0].teams).to.exist(); 38 | expect(dailyMatchups[0].teams.away).to.equal('Astros'); 39 | expect(dailyMatchups[0].pitchers).to.exist(); 40 | expect(dailyMatchups[0].pitchers.away).to.exist(); 41 | expect(dailyMatchups[0].pitchers.away.id).to.equal('434643'); 42 | expect(dailyMatchups[0].pitchers.home).to.exist(); 43 | expect(dailyMatchups[0].pitchers.home.id).to.equal('448694'); 44 | done(); 45 | 46 | }); 47 | }); 48 | 49 | const invalidDate = '2011-07'; 50 | it(`Fails with invalid date syntax ${invalidDate}`, (done) => { 51 | 52 | Probables.get(day, (err, dailyMatchups) => { 53 | 54 | expect(err).to.exist(); 55 | done(); 56 | 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const Xray = require('x-ray'); 3 | 4 | class Probables { 5 | static get(dateString, callback) { 6 | 7 | let dateComponents = dateString.split('-'); 8 | if (dateComponents.length !== 3) { 9 | dateComponents = dateString.split('/'); 10 | if (dateComponents.length !== 3) { 11 | throw `Invalid date format. Use 'YYYY-MM-DD'`; 12 | } 13 | } 14 | const year = dateComponents[0]; 15 | const month = dateComponents[1]; 16 | const day = dateComponents[2]; 17 | 18 | const url = `https://www.mlb.com/probable-pitchers/${year}-${month}-${day}`; 19 | const scope = 'body'; 20 | const selector = { 21 | pitchers: ['div.probable-pitchers__pitcher-name a@href'], 22 | names: ['div.probable-pitchers__pitcher-name a'], 23 | throws: ['div.probable-pitchers__pitcher-details span.probable-pitchers__pitcher-pitch-hand'], 24 | teams: ['div.probable-pitchers__team-names span.probable-pitchers__team-name--away, div.probable-pitchers__team-names span.probable-pitchers__team-name--home'], 25 | games: ['div.probable-pitchers__matchup@data-gamePk'], 26 | startTimes: ['div.probable-pitchers__game-details div.probable-pitchers__game-date-time time@dateitme'], 27 | easternTimes: ['div.pitcher@eastern_time'], 28 | timezones: ['div.pitcher@local_time_zone'] 29 | }; 30 | 31 | const x = Xray(); 32 | x(url, scope, selector)((err, result) => { 33 | 34 | if (err) { 35 | return callback(err); 36 | } 37 | const matchups = Probables.convertResult(result); 38 | return callback(null, matchups); 39 | }); 40 | } 41 | 42 | static trimWhiteSpace(arr) { 43 | 44 | return arr.map((elem) => { 45 | 46 | return elem.replace(/\s/g, ''); 47 | }); 48 | } 49 | 50 | static convertResult(result) { 51 | 52 | const matchups = []; 53 | 54 | const pitcherIDInURL = /.*(\d{6}).*/; 55 | const pitcherIDs = result.pitchers.map((pitcher) => { 56 | 57 | const matches = pitcherIDInURL.exec(pitcher); 58 | if (matches.length !== 2) { 59 | throw `Unexpected URL format while trying to extract pitcher ID: ${pitcher}`; 60 | } 61 | return matches[1]; 62 | }); 63 | const teams = Probables.trimWhiteSpace(result.teams); 64 | const names = result.names; 65 | const throws = Probables.trimWhiteSpace(result.throws); 66 | 67 | for (let i = 0; i < pitcherIDs.length; i += 2) { 68 | const j = i + 1; 69 | const matchup = { 70 | id: result.games[i], 71 | startTime: result.startTimes[i], 72 | easternTime: result.easternTimes[i], 73 | timezone: result.timezones[i], 74 | teams: { 75 | away: teams[i], 76 | home: teams[j] 77 | }, 78 | pitchers: { 79 | away: { 80 | id: pitcherIDs[i], 81 | name: names[i], 82 | throws: throws[i] 83 | }, 84 | home: { 85 | id: pitcherIDs[j], 86 | name: names[j], 87 | throws: throws[j] 88 | } 89 | } 90 | }; 91 | 92 | matchups.push(matchup); 93 | } 94 | 95 | return matchups; 96 | } 97 | } 98 | 99 | module.exports = Probables; 100 | --------------------------------------------------------------------------------