hockeybar
Version:
A bot used to automate the updating of hockey league subreddit markdown
239 lines (229 loc) • 8.76 kB
JavaScript
const Snoowrap = require('snoowrap');
const Joi = require('joi');
const {
EventSchema,
TeamSchema,
SkaterSchema,
GoalieSchema
} = require('./schemas');
const Teams = require('./teams');
const ScheduleBuilder = require('./parsers/schedule');
const TeamStatsBuilder = require('./parsers/teamStats');
const PlayerStatsBuilder = require('./parsers/playerStats');
const GameStatsBuilder = require('./parsers/gameStats');
/**
*
* @example
* var hockeyBar = new HockeyBar(
* 'anaheim-ducks'
* ,{
* clientId: process.env.CLIENT_ID,
* clientSecret: process.env.CLIENT_SECRET,
* userId: process.env.REDDIT_USER,
* userPassword: process.env.REDDIT_PASS,
* subreddit: process.env.SUBREDDIT
* }
* ,sidebarTemplate);
*/
var HockeyBar = class HockeyBar {
/**
* this is constructor description.
* @param {string} teamName The name of your team should be all lower case with spaces replaced by a dash (-). For example if your reddit team is the New Jersey Devils, you would use 'new-jersey-devils'.
* @param {{clientId: string, clientSecret: string, userId: string, userPassword: string, subreddit: string}} redditOptions This object is used to authenticate with Snoowrap a reddit API library.
* @param {string} sidebarTemplate This is your subreddit sidebar template markdown. It can be supplied with the constructor or fetched after instantiation using loadSidebarTemplateFromReddit().
*/
constructor(teamName, redditOptions, sidebarTemplate, includePreSeason = false) {
this.team = Teams[teamName];
this.team.uri = teamName;
this.subreddit = redditOptions.subreddit;
console.log(`Constructing HockeyBar for the ${this.team.name}`);
this.reddit = new Snoowrap({
userAgent: `${this.teamName}-hockey-bar`,
clientId: redditOptions.clientId,
clientSecret: redditOptions.clientSecret,
username: redditOptions.userId,
password: redditOptions.userPassword
});
console.log('reddit client loaded...')
if (sidebarTemplate === undefined) {
console.log('sidebarTemplate undefined, load from subreddit wiki')
} else {
this.sidebarTemplate = sidebarTemplate;
this.markdown = sidebarTemplate;
}
this.scheduleBuilder = new ScheduleBuilder(this.team, includePreSeason);
this.gameStatsBuilder = new GameStatsBuilder(this.team);
this.teamStatsBuilder = new TeamStatsBuilder(this.team);
this.playerStatsBuilder = new PlayerStatsBuilder(this.team);
}
/**
* This function may be called to load a markdown template from the supplied wiki page.
* @param {string} wikiPage The wiki page that should be queried for the markdown template
*/
loadSidebarTemplateFromReddit(wikiPage) {
return new Promise((resolve, reject) => {
this.reddit.getSubreddit(this.subreddit).getWikiPage('sidebar').fetch().then((page) => {
this.sidebarTemplate = page.content_md;
this.markdown = page.content_md;
console.log('sidebarTemplate set from subreddit wiki')
return resolve();
});
});
}
/**
* This function provides the raw team schedule data that may be used to generate markdown.
* @param {number} days The number of days to include in the array of events
*/
fetchTeamSchedule(days = 5) {
return new Promise((resolve, reject) => {
this.scheduleBuilder.parse(days).then((data) => {
resolve(data);
});
});
}
/**
* This function provides the raw skater data that may be used to generate markdown
* @param {number} top The number of skaters to include in the array of data.
*/
fetchTeamSkaters(top = 5) {
return new Promise((resolve, reject) => {
this.playerStatsBuilder.parse(top, 1).then((data) => {
resolve(data);
});
});
}
/**
* This function provides the raw skater data that may be used to generate markdown
* @param {number} top The number of skaters to include in the array of data.
*/
fetchTeamGoalies(top = 5) {
return new Promise((resolve, reject) => {
this.playerStatsBuilder.parse(top, 2).then((data) => {
resolve(data);
});
});
}
/**
* This function provides the raw skater data that may be used to generate markdown
*/
fetchDivisionStats() {
return new Promise((resolve, reject) => {
this.teamStatsBuilder.parse().then((data) => {
resolve(data);
});
});
}
/**
* This function provides the raw skater data that may be used to generate markdown
*/
fetchConferenceStats() {
return new Promise((resolve, reject) => {
this.teamStatsBuilder.parse(2).then((data) => {
resolve(data);
});
});
}
/**
*
* @param {any[]} data The array returned from a fetchDataType() function.
* @param {Function} markdownBuilder You may pass in a delegate function to override the default markdown building functionality.
*
*
* @example
* asMarkdown(data, () => {
* var buildEventMarkdown = (event) => {
* var markdown = `[${event.date}](http://some-site.com/${event.opponent.name})`;
* return markdown;
* };
* var eventMarkdown = '';
* for (var i = 0; i < data.length; i++) {
* eventMarkdown = eventMarkdown + buildEventMarkdown(data[i]);
* }
* return eventMarkdown;
* })
*/
asMarkdown(data, markdownBuilder = () => {}) {
if (data.length > 0) {
let type = this.getType(data[0]);
return new Promise((resolve, reject) => {
switch (type) {
case Types.Event:
markdownBuilder = this.scheduleBuilder.buildTeamScheduleMarkdown.bind(this.scheduleBuilder);
break;
case Types.Skater:
markdownBuilder = this.playerStatsBuilder.buildSkaterStats.bind(this.playerStatsBuilder);
break;
case Types.Goalie:
markdownBuilder = this.playerStatsBuilder.buildGoalieStats.bind(this.playerStatsBuilder);
break;
default:
markdownBuilder = this.teamStatsBuilder.buildStats.bind(this.teamStatsBuilder);
break;
}
markdownBuilder(data).then(md => {
resolve(md);
});
});
}
}
/**
* This function is used to replace a known substring target with generated markdown.
* @param {string} replaceStr The search pattern that will be found and replaced with the markdown.
* @param {string} markdown The generated markdown.
*/
updateTemplate(replaceStr, markdown) {
return new Promise((resolve, reject) => {
this.markdown = this.markdown.replace(replaceStr, markdown);
resolve();
});
}
/**
* This function is used to write the updated sidebar template to the current subreddit.
*/
updateRedditSidebar() {
return new Promise((resolve, reject) => {
var self = this;
this.reddit.getSubreddit(this.subreddit).editSettings({
description: self.markdown
}).then(() => {
this.markdown = this.sidebarTemplate;
resolve();
});
});
}
/**
*
*/
fetchCurrentGameStats(){
return new Promise((resolve, reject) => {
this.gameStatsBuilder.getCurrentGame().then(gameData => {
resolve(gameData);
});
});
}
/**
* @private
* @param {Object} obj The object used to infer its type or structure.
*/
getType(obj) {
if (obj.type === 'event') {
return Types.Event;
}
if (obj.type === 'skater') {
return Types.Skater;
}
if (obj.type === 'goalie') {
return Types.Goalie;
}
if (obj.type === 'team') {
return Types.Team;
}
}
}
const Types = Object.freeze({
Event: "EVENT_DATA_TYPE",
Skater: "SKATER_DATA_TYPE",
Goalie: "GOALIE_DATA_TYPE",
Team: "TEAM_DATA_TYPE"
});
module.exports = HockeyBar;