New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@sahirb/nba-stats

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sahirb/nba-stats - npm Package Compare versions

Comparing version 1.0.3 to 1.0.4

data/box_scores/2003_2004.txt

269

example.js

@@ -0,1 +1,2 @@

const fs = require('fs');
const bref = require('@sahirb/nba-stats')

@@ -23,8 +24,8 @@

start: {
year: 2009,
year: 2003,
month: 10,
day: 27
day: 28
},
end: {
year: 2010,
year: 2004,
month: 4,

@@ -34,38 +35,2 @@ day: 14

},
{
start: {
year: 2008,
month: 10,
day: 28
},
end: {
year: 2009,
month: 4,
day: 16
}
},
{
start: {
year: 2007,
month: 10,
day: 30
},
end: {
year: 2008,
month: 4,
day: 16
}
},
{
start: {
year: 2006,
month: 10,
day: 31
},
end: {
year: 2007,
month: 4,
day: 18
}
},
// {

@@ -109,38 +74,159 @@ // start: {

const sortedLakers = bref.getSeasonScores(2022)
.filter(boxScore => {
return boxScore.roadTeam === 'LA Lakers' && boxScore.winningTeam !== 'LA Lakers';
}).sort((boxScoreA, boxScoreB) => {
return boxScoreA.roadTeamTotal - boxScoreB.roadTeamTotal;
}).map(boxScore => {
return {
date: boxScore.gameDate,
total: boxScore.roadTeamTotal,
diff: boxScore.roadTeamTotal - boxScore.homeTeamTotal,
numPossessions: boxScore.numPossessions,
q2Diff: boxScore.periodBreakdown[1].roadTotal - boxScore.periodBreakdown[1].homeTotal,
// const sortedLakers = bref.getSeasonScores(2022)
// .filter(boxScore => {
// return boxScore.roadTeam === 'LA Lakers' && boxScore.winningTeam !== 'LA Lakers';
// }).sort((boxScoreA, boxScoreB) => {
// return boxScoreA.roadTeamTotal - boxScoreB.roadTeamTotal;
// }).map(boxScore => {
// return {
// date: boxScore.gameDate,
// total: boxScore.roadTeamTotal,
// diff: boxScore.roadTeamTotal - boxScore.homeTeamTotal,
// numPossessions: boxScore.numPossessions,
// q2Diff: boxScore.periodBreakdown[1].roadTotal - boxScore.periodBreakdown[1].homeTotal,
// }
// });
// console.log(sortedLakers);
// const years = [2022, 2021, 2020, 2019, 2018];
// years.forEach(year => {
// const top5Off = bref.getEfficiencyDataByTeam(year)
// .filter(summary => {
// return summary.offEfficiencyRank <= 5;
// })
// .map(summary => {
// return {
// teamName: summary.teamName,
// offRank: summary.offEfficiencyRank,
// off: summary.offEfficiency,
// points: summary.totalPointsScored,
// averagePace: summary.averagePace
// };
// })
// .sort((a, b) => {
// return a.offRank - b.offRank;
// });
// console.log(year);
// console.log(top5Off);
// });
const teams = ['Atlanta', 'Boston', 'Brooklyn', 'Charlotte', 'Chicago', 'Cleveland', 'Dallas', 'Denver', 'Detroit', 'Golden State', 'Houston',
'Indiana', 'LA Clippers', 'LA Lakers', 'Memphis', 'Miami', 'Milwaukee', 'Minnesota', 'New Orleans', 'New Jersey', 'New York', 'Oklahoma City', 'Orlando', 'Philadelphia', 'Phoenix', 'Portland',
'Sacramento', 'San Antonio', 'Seattle', 'Toronto', 'Utah', 'Washington'];
// const teams = ['New Orleans']
let doubleError = false;
let seasonTeamCount = 0;
function workEff(seasonStart, teamsIndex) {
doubleError = false;
if (teamsIndex >= teams.length) {
if (seasonTeamCount !== 30) {
console.log('not enough teams for this season!!!');
return;
}
seasonTeamCount = 0;
console.log('new season ' + (seasonStart-1));
workEff(seasonStart - 1, 0);
return;
}
});
console.log(sortedLakers);
const team = teams[teamsIndex];
const teamTLA = bref.getTeamTLA(team, seasonStart, 12);
// console.log(` fetchSeasonSummary ${team} ${seasonStart} ${teamsIndex}`);
bref.fetchSeasonSummary(teamTLA, seasonStart).then(result => {
++seasonTeamCount;
// console.log(result);
// let boxScores = bref.getSeasonScores(seasonStart);
const local_file_path_tempalte = "/Users/boghani/ns2/data/box_scores/";
const local_file_path = "/Users/boghani/basketball-reference-js-box-score/data/box_scores/2019_2020.txt";
const filePath = `./data/season_averages/${seasonStart}_${seasonStart+1}.txt`;
const box_score_transformation = (boxScore) => {
let feeling = 'snooze fest';
fs.appendFileSync(filePath, JSON.stringify({
teamName: team,
teamTLA: teamTLA,
offensiveEfficiency: result.offRating,
defensiveEfficiency: result.defRating,
pace: result.pace,
}) + '\n');
if (boxScore.gameTotal > 220) {
feeling = 'wow points and stuff';
// console.log(`${team} ${seasonStart} next team in 3s ${result.pace}`);
setTimeout(() => {
workEff(seasonStart, teamsIndex + 1);
}, 3000);
if (boxScore.winningTeamScore - boxScore.losingTeamScore < 10) {
feeling = 'be still my heart <4';
// boxScores.forEach((boxScore, index) => {
// if (boxScore.roadTeam === team) {
// bref.updateBoxScore(filePath, index, (boxScoreLine) => {
// boxScoreLine.roadTeamSeasonOffEff = result.offRating;
// });
// }
// });
// bref.updateBoxScore(filePath, index, (boxScoreLine) => {
// ++numInsignificant;
// boxScoreLine.numPossessions = pace;
// if (boxScoreLine.periodBreakdown[0].roadTotal > max || boxScoreLine.periodBreakdown[0].roadTotal < min) {
// console.log(numInsignificant + ' later q1 ----- ' + min + '-' + max);
// numInsignificant = 0;
// if (boxScoreLine.periodBreakdown[0].roadTotal > max) {
// max = boxScoreLine.periodBreakdown[0].roadTotal;
// }
// if (boxScoreLine.periodBreakdown[0].roadTotal < min) {
// min = boxScoreLine.periodBreakdown[0].roadTotal;
// }
// console.log('new q1 --------- ' + min + '-' + max);
// }
// return boxScoreLine;
// });
}).catch(error => {
// console.log(error);
if (!doubleError) {
doubleError = true;
workEff(seasonStart, teamsIndex + 1);
}
}
});
}
boxScore.feeling = feeling;
};
// workEff(2012, 0);
[2022, 2021, 2020, 2019, 2018].forEach(year => {
const sortedTop3 = bref.getSeasonSummaries(year)
.filter(summary => {
return summary.offensiveEfficiencyRank <= 3;
}).map(summary => {
return {
teamName: summary.teamName,
offensiveEfficiencyRank: summary.offensiveEfficiencyRank,
pointsRank: summary.pointsScoredPerGameRank,
offensiveEfficiency: summary.offensiveEfficiency,
points: summary.pointsScoredPerGame,
pace: summary.pace
}
}).sort((a, b) => {
return a.offRank - b.offRank;
});
console.log('--------------------------------------------------------------------');
console.log(year);
console.log(sortedTop3);
});
// const summaries = bref.getSeasonSummaries(2022).sort((a, b) => {
// return a.offensiveEfficiencyRank - b.offensiveEfficiencyRank;
// });
// console.log(summaries);
const local_file_path_tempalte = "./data/box_scores/";
// bref.sortFileByGameDate(local_file_path);

@@ -165,3 +251,3 @@

bref.getBoxScoresForDates(backfillSeason.end, num_additional_days_to_fetch, null, null)
bref.fetchBoxScoresForDates(backfillSeason.end, num_additional_days_to_fetch, null, null)
.then(boxScores => {

@@ -177,2 +263,3 @@ boxScores.sort((a, b) => {

}
// backfill(0);

@@ -184,8 +271,26 @@ const season = {

const seasonStart = 2022;
const boxScores = bref.getSeasonScores(seasonStart);
const limit = boxScores.length;
let seasonStart = 2015;
let boxScores = bref.getSeasonScores(seasonStart);
let limit = boxScores.length;
let min = 500;
let max = 1;
let numInsignificant = 0;
function work(index) {
if (index >= limit) {
console.log('done, time for ' + (seasonStart-1));
if (seasonStart <= 2008) {
return;
}
seasonStart--;
boxScores = bref.getSeasonScores(seasonStart);
limit = boxScores.length;
max = 500;
max = 1;
numInsignificant = 0;
console.log('working on ' + seasonStart + ' with ' + limit + ' games');
work(0);
return;

@@ -195,6 +300,8 @@ }

const boxScore = boxScores[index];
// console.log('working on ' + index);
// console.log(boxScore)
const filePath = `./data/box_scores/${seasonStart}_${seasonStart+1}.txt`;
if (!boxScore.numPossessions) {
bref.getAdvancedStats(boxScore.homeTeam, boxScore.gameDate)
bref.fetchAdvancedStats(boxScore.homeTeam, boxScore.gameDate)
.then(pace => {

@@ -204,9 +311,25 @@ console.log('got pace ' + pace);

bref.updateBoxScore(filePath, index, (boxScoreLine) => {
++numInsignificant;
boxScoreLine.numPossessions = pace;
if (boxScoreLine.periodBreakdown[0].roadTotal > max || boxScoreLine.periodBreakdown[0].roadTotal < min) {
console.log(numInsignificant + ' later q1 ----- ' + min + '-' + max);
numInsignificant = 0;
if (boxScoreLine.periodBreakdown[0].roadTotal > max) {
max = boxScoreLine.periodBreakdown[0].roadTotal;
}
if (boxScoreLine.periodBreakdown[0].roadTotal < min) {
min = boxScoreLine.periodBreakdown[0].roadTotal;
}
console.log('new q1 --------- ' + min + '-' + max);
}
return boxScoreLine;
})
});
const progress = Math.round(index / limit * 1000);
const originalLen = 3*limit/60;
console.log('going to work again after 3s (' + (limit - index) + ' remaining aka ' + (3*(limit-index)/60) + ' minutos)');
console.log('going to work again after 3s - ' + (limit - index) + ' remaining aka ' + (3*(limit-index)/60) + ' minutos remaining, original ' + originalLen);
setTimeout(() => {

@@ -217,3 +340,3 @@ work(index+1);

} else {
console.log('skiping ' + index + ' already have ' + boxScore.numPossessions);
// console.log('skiping ' + index + ' already have ' + boxScore.numPossessions);
work(index+1);

@@ -220,0 +343,0 @@ }

@@ -31,3 +31,7 @@ // made by sahir (iKnow im also shocked)

.catch(error => {
console.log(`Error fetching url ${url}: ${error.code} ${error.response.statusText}`)
if (error.response) {
console.log(`Error fetching url ${url}: ${error.code} ${error.response.statusText}`)
} else {
console.log(`Error fetching url ${url}: ${error.message.substring(0, 200)}`);
}

@@ -60,3 +64,3 @@ if (currentAttempt < maxAttempts) {

function getTeamTLA(team) {
function getTeamTLA(team, game_year, game_month) {
if (team.includes('Atlanta')) {

@@ -72,3 +76,10 @@ return 'ATL';

if (team.includes('Charlotte')) {
return 'CHO';
// hornets (2014-2015 onwards)
if (game_year >= 2014) {
if (game_year > 2014 || game_month > 7) {
return 'CHO';
}
}
return 'CHA'; // bobcats
}

@@ -118,4 +129,25 @@ if (team.includes('Chicago')) {

if (team.includes('New Orleans')) {
return 'NOP';
console.log("new orleans " + game_year + " " + game_month);
// pelicans (2013-2014 - present)
if (game_year >= 2013) {
if (game_year > 2013 || game_month > 7) {
return 'NOP';
}
}
// okc hornets
if (game_month > 7 && (game_year == 2005 || game_year == 2006)) {
return 'NOK';
}
if (game_month < 7 && (game_year == 2006 || game_year == 2007)) {
return 'NOK';
}
// hornets
return 'NOH';
}
if (team.includes('New Jersey')) {
return 'NJN';
}
if (team.includes('New York')) {

@@ -145,2 +177,5 @@ return 'NYK';

}
if (team.includes('Seattle')) {
return 'SEA';
}
if (team.includes('Toronto')) {

@@ -157,7 +192,33 @@ return 'TOR';

function getAdvancedStats(home_team, game_date) {
function fetchSeasonSummary(team_tla, season_start_year) {
function parseWithRegex(input, regex) {
const match = input.match(regex)[0];
return parseFloat(match.substring(match.indexOf('>') + 1));
}
return new Promise((resolve, reject) => {
httpGet(`https://www.basketball-reference.com/teams/${team_tla}/${season_start_year+1}.html`)
.then(response => {
const offRating = parseWithRegex(response.data, /off_rtg\" \>([\.\d+]+)?/);
const defRating = parseWithRegex(response.data, /def_rtg\" \>([\.\d+]+)?/);
const pace = parseWithRegex(response.data, /pace\" \>([\.\d+]+)?/);
resolve({
offRating: offRating,
defRating: defRating,
pace: pace
});
})
.catch(error => {
reject(error);
});
});
}
function fetchAdvancedStats(home_team, game_date) {
const date = game_date.split('-');
const dateString = `${date[0]}${getPaddedNumber(date[1])}${getPaddedNumber(date[2])}`;
const homeTLA = getTeamTLA(home_team);
const homeTLA = getTeamTLA(home_team, parseInt(date[0]), parseInt(date[1]));

@@ -167,5 +228,2 @@ return new Promise((resolve, reject) => {

.then(response => {
// use cheerio to parse HTML
const $ = cheerio.load(response.data);
const paceRegex = /pace\" \>([\.\d+]+)?/; // matches one or more digits, optionally followed by a dot and one or more digits

@@ -176,2 +234,5 @@ const paceMatch = response.data.match(paceRegex)[0];

resolve(pace);
})
.catch(error => {
reject(error);
});

@@ -181,3 +242,3 @@ });

function getBoxScoresForDate(date) {
function fetchBoxScoresForDateInternal(date) {
return new Promise((resolve, reject) => {

@@ -264,3 +325,3 @@ httpGet(`https://www.basketball-reference.com/boxscores/?&year=${date.year}&month=${date.month}&day=${date.day}`)

function readBoxScores(file_path) {
function readLines(file_path) {
const boxScores = [];

@@ -282,3 +343,3 @@ const lines = fs.readFileSync(file_path, 'utf-8').split('\n');

function updateBoxScore(file_path, index, box_score_transformation) {
const updatedBoxScores = readBoxScores(file_path);
const updatedBoxScores = readLines(file_path);
updatedBoxScores[index] = box_score_transformation(updatedBoxScores[index]);

@@ -290,3 +351,3 @@

function sortFileByGameDate(file_path) {
const sortedBoxScores = readBoxScores(file_path);
const sortedBoxScores = readLines(file_path);

@@ -305,2 +366,77 @@ sortedBoxScores.sort((a, b) => {

function getSeasonSummariesHelper(box_scores) {
const seasonSummaryByTeam = {};
function getOrCreateTeamSummary(teamName) {
let teamSummary = seasonSummaryByTeam[teamName];
if (!teamSummary) {
teamSummary = {
teamName: teamName,
totalGames: 0,
totalPointsScored: 0,
totalPointsAgainst: 0,
totalPossessions: 0,
};
}
seasonSummaryByTeam[teamName] = teamSummary;
return teamSummary;
}
box_scores.forEach(box_score => {
const roadTeamSummary = getOrCreateTeamSummary(box_score.roadTeam);
const homeTeamSummary = getOrCreateTeamSummary(box_score.homeTeam);
++roadTeamSummary.totalGames;
roadTeamSummary.totalPointsScored += box_score.roadTeamTotal;
roadTeamSummary.totalPointsAgainst += box_score.homeTeamTotal;
++homeTeamSummary.totalGames;
homeTeamSummary.totalPointsScored += box_score.homeTeamTotal;
homeTeamSummary.totalPointsAgainst += box_score.roadTeamTotal;
});
const seasonSummaries = [];
Object.keys(seasonSummaryByTeam).forEach(key => {
const summary = seasonSummaryByTeam[key];
seasonSummaries.push(summary);
});
return seasonSummaries;
}
function sortAndRank(data, field) {
data.sort((a, b) => {
return b[field] - a[field];
});
data.forEach((d, index) => {
d[`${field}Rank`] = index + 1;
});
}
function getSeasonSummaries(season_start_year) {
const filePath = `data/season_averages/${season_start_year}_${season_start_year+1}.txt`;
const seasonAverages = readLines(filePath);
const seasonSummaries = getSeasonSummariesHelper(getSeasonScores(season_start_year));
seasonSummaries.forEach(summary => {
summary.pointsScoredPerGame = summary.totalPointsScored / summary.totalGames;
summary.pointsAgainstPerGame = summary.totalPointsAgainst / summary.totalGames;
seasonAverages.forEach(sa => {
if (sa.teamName === summary.teamName) {
summary.offensiveEfficiency = sa.offensiveEfficiency;
summary.defensiveEfficiency = sa.defensiveEfficiency;
summary.pace = sa.pace;
}
});
});
sortAndRank(seasonSummaries, 'offensiveEfficiency');
sortAndRank(seasonSummaries, 'defensiveEfficiency');
sortAndRank(seasonSummaries, 'pace');
sortAndRank(seasonSummaries, 'pointsScoredPerGame');
sortAndRank(seasonSummaries, 'pointsAgainstPerGame');
return seasonSummaries;
}
function decorateBoxScore(box_score) {

@@ -340,6 +476,6 @@ let roadTeamTotal = 0;

function getBoxScoresForDatesHelper(current_game_date, num_additional_days, daily_scores, resolve, reject, file_path, box_score_transformation) {
getBoxScoresForDate(current_game_date)
function fetchBoxScoresForDatesHelper(current_game_date, num_additional_days, daily_scores, resolve, reject, file_path, box_score_transformation) {
fetchBoxScoresForDateInternal(current_game_date)
.then(boxScores => {
console.log(`Fetched ${boxScores.length} games played on ${current_game_date.month}-${current_game_date.day}, ${num_additional_days} days left to query`);
console.log(`Fetched ${boxScores.length} games played on ${current_game_date.month}-${current_game_date.day}, ${num_additional_days} days left to query (${num_additional_days/20} mins)`);

@@ -366,4 +502,4 @@ if (boxScores.length > 0) {

const prev_game_date = previousDay(current_game_date);
doAfterSeconds(20, () => {
getBoxScoresForDatesHelper(prev_game_date, num_additional_days - 1, daily_scores, resolve, reject, file_path, box_score_transformation);
doAfterSeconds(3, () => {
fetchBoxScoresForDatesHelper(prev_game_date, num_additional_days - 1, daily_scores, resolve, reject, file_path, box_score_transformation);
});

@@ -377,10 +513,10 @@ }

function getBoxScoresForDates(last_game_date, num_additional_days, file_path, box_score_transformation) {
function fetchBoxScoresForDates(last_game_date, num_additional_days, file_path, box_score_transformation) {
return new Promise((resolve, reject) => {
getBoxScoresForDatesHelper(last_game_date, num_additional_days, [], resolve, reject, file_path, box_score_transformation);
fetchBoxScoresForDatesHelper(last_game_date, num_additional_days, [], resolve, reject, file_path, box_score_transformation);
});
}
function getBoxScores(date) {
return getBoxScoresForDates(date, 0);
function fetchBoxScores(date) {
return fetchBoxScoresForDates(date, 0);
}

@@ -399,3 +535,3 @@

const filePath = `data/box_scores/${season.startYear}_${season.endYear}.txt`;
const boxScores = readBoxScores(filePath);
const boxScores = readLines(filePath);

@@ -428,11 +564,20 @@ const decoratedBoxScores = [];

const bref = {}; // bref == basketball reference :)
bref.getBoxScores = getBoxScores;
bref.getBoxScoresForDates = getBoxScoresForDates;
bref.appendCompactBoxScores = appendCompactBoxScores;
// the goods in local files
bref.getSeasonSummaries = getSeasonSummaries;
bref.getSeasonScores = getSeasonScores;
bref.getSeasonScoresSimple = getSeasonScoresSimple;
bref.getTeamTLA = getTeamTLA;
// network request
bref.fetchBoxScores = fetchBoxScores;
bref.fetchBoxScoresForDates = fetchBoxScoresForDates;
bref.fetchSeasonSummary = fetchSeasonSummary;
bref.fetchAdvancedStats = fetchAdvancedStats;
// local file ops
bref.appendCompactBoxScores = appendCompactBoxScores;
bref.sortFileByGameDate = sortFileByGameDate;
bref.updateBoxScore = updateBoxScore;
bref.getAdvancedStats = getAdvancedStats;
module.exports = bref // npm link, npm link @sahirb/basketball-reference
{
"name": "@sahirb/nba-stats",
"version": "1.0.3",
"version": "1.0.4",
"description": "NBA data and Javascript APIs to access stats. Also the util APIs that were used to build the stats files.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -13,10 +13,12 @@ Making NBA data more accessible for fellow fanatics! 🏀 🤗

Current Data:
- Box Scores
- Points per quarter (for season off/def point average & ranking)
- 2006-2023 (17 seasons)
Game scores with season averages `[2003-2023 (20 seasons)]`
- Possessions per game (for season off/def efficiency rating & ranking)
- 2022-2023
- Points scored in each quarter
- Team rank per season
- Points per game
- Pace
- Offensive/defensive efficiency
Possible Future Data:
- Betting lines
- More seasons

@@ -28,2 +30,69 @@ - Advanced team/game stats (fouls, fg/ft/3fg attempts, etc.)

If we want the top 3 offenses from the last 5 years:
```javascript
// offensiveEfficiencyRank: 3, pointsRank: 11
// guess which eastern conference team isn't good, just slow!?
// hint: 'the mecca of basketball' but not for the home team lol
[2022, 2021, 2020, 2019, 2018].forEach(year => {
const sortedTop3 = bref.getSeasonSummaries(year)
.filter(summary => {
return summary.offensiveEfficiencyRank <= 3;
}).map(summary => {
return {
teamName: summary.teamName,
offensiveEfficiencyRank: summary.offensiveEfficiencyRank,
pointsRank: summary.pointsScoredPerGameRank,
offensiveEfficiency: summary.offensiveEfficiency,
points: summary.pointsScoredPerGame,
pace: summary.pace
}
}).sort((a, b) => {
return a.offRank - b.offRank;
});
console.log(year);
console.log(sortedTop3);
});
// -- result --
2022
[
{
teamName: 'Sacramento',
offensiveEfficiencyRank: 1,
pointsRank: 1,
offensiveEfficiency: 119.4,
points: 120.70731707317073,
pace: 100.3
},
{
teamName: 'New York',
offensiveEfficiencyRank: 3,
pointsRank: 11,
offensiveEfficiency: 117.8,
points: 116.02439024390245,
pace: 97.1
},
{
teamName: 'Boston',
offensiveEfficiencyRank: 2,
pointsRank: 4,
offensiveEfficiency: 118,
points: 117.9390243902439,
pace: 98.5
}
]
2021
[
{
teamName: 'Atlanta',
offensiveEfficiencyRank: 2,
...
}
]
...
```
If we want the game total & q2 difference for 2022 Lakers road losses (sorted by game total):

@@ -30,0 +99,0 @@ ```javascript

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc