This repository has been archived by the owner on Apr 14, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstatsbot.js
319 lines (292 loc) · 10.6 KB
/
statsbot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
var Discord = require("discord.js");
var mybot = new Discord.Client();
var request = require("request");
var CronJob = require("cron").CronJob;
var async = require("async");
var leftPad = require("left-pad"); // just cuz
var Sequelize = require("sequelize");
const moment = require("moment");
if (process.env.NODE_ENV != "production") {
require("dotenv").config();
}
var sequelize = new Sequelize(process.env.POSTGRES_URL, {
dialectOptions: {
ssl: true
}
});
var Channel = sequelize.define("channels", {
channel_id: {
type: Sequelize.BIGINT,
primaryKey: true
}
});
var TrackedPlayer = sequelize.define("tracked_players", {
player_battletag: Sequelize.STRING,
channel_id: Sequelize.BIGINT
});
var confirmationFlags = {};
mybot.on("message", function(message) {
let messageContents = message.cleanContent;
let messageRegex = messageContents.match(/([\w@#-]+)+/gm);
let me = "@" + message.client.user.username + "#" + message.client.user.discriminator;
let toMe;
if (messageRegex && messageRegex[0] == me) {
toMe = true;
} else {
toMe = false;
}
let helpCommands = ["setup", "track battletag#1234", "track battletag#1234 anotherbattletag#1234", "post", "list", "untrack battletag#1234", "untrack battletag#1234 anotherbattletag#1234", "stop"];
if (toMe) {
let command = messageRegex[1];
switch (command) {
case "stop":
stopPostingToChannel(message.channel.id, message);
break;
case "confirm":
confirm(message.channel.id, message);
break;
case "track":
let playersToTrack = messageRegex.slice(2);
if (playersToTrack.length == 0) {
mybot.sendMessage(message, "Ya gotta specify someone to track, numbnuts! Try something like `" + me + " track battletag#1234`");
} else {
async.eachSeries(playersToTrack, function(player, cb) {
startTrackingPlayer(message.channel.id, player, message, cb);
});
}
break;
case "untrack":
let playersToRemove = messageRegex.slice(2);
if (playersToRemove.length == 0) {
mybot.sendMessage(message, "Ya gotta specify someone to untrack, numbnuts! Try something like `" + me + " untrack battletag#1234`");
} else {
for (let player of playersToRemove) {
stopTrackingPlayer(message.channel.id, player, message);
}
}
break;
case "list":
listPlayers(message.channel.id, message);
break;
case "post":
postToChannel(message.channel.id, message);
break;
default:
mybot.sendMessage(message, "Er...what? Didn't quite get that. Try one of these commands:\n\n```" + helpCommands.join("\n" + me + " ") + "```");
delete confirmationFlags[message.channel.id];
}
}
});
var stopPostingToChannel = function(channel_id, message) {
let me = "@" + message.client.user.username + "#" + message.client.user.discriminator;
mybot.sendMessage(message, "I can stop posting to this channel, but if you want me to start again, you'll have to re-add all the players manually. Are you sure you want to do this? If so, say:\n\n`" + me + " confirm`");
// set confirmation flag for channel
confirmationFlags[message.channel.id] = true;
};
var confirm = function(channel_id, message) {
// check to see if confirmation flag is set
if (confirmationFlags[message.channel.id] == true) {
// if so, perform confirmation action
// remove channel
TrackedPlayer.findAll({
where: {
channel_id: message.channel.id
}
}).then(function(trackedPlayersInThisChannel) {
for (let trackedPlayer of trackedPlayersInThisChannel) {
trackedPlayer.destroy();
}
mybot.sendMessage(message, "Alright, I've stopped tracking all players in this channel.");
});
} else {
mybot.sendMessage(message, "Er...what? What am I supposed to be confirming?");
}
};
var startTrackingPlayer = function(channel_id, player_battletag, message, cb) {
let me = "@" + message.client.user.username + "#" + message.client.user.discriminator;
TrackedPlayer.find({
where: {
channel_id: channel_id,
player_battletag: player_battletag
}
}).then(function(player) {
if (player) {
mybot.sendMessage(message, "I'm already tracking " + player_battletag + " in this channel, numbnuts!\n\nIf you want me to stop tracking them, try:\n\n`" + me + " untrack " + player_battletag + "`");
cb();
} else {
getPlayerRank(player_battletag, function(err, player_stats) {
if (err) {
mybot.sendMessage(message, "Hmm...got some kind of error while trying to track " + player_battletag + " in this channel. Try again, and if that doesn't fix it, let us know about the bug! https://github.com/hofftech/statsbot/issues");
cb();
} else if (!("rank" in player_stats) || (!player_stats.rank) || (player_stats.rank == "")) {
mybot.sendMessage(message, "Hm, I can't find a rank for " + player_battletag + " at " + "https://playoverwatch.com/en-us/career/pc/us/" + player_battletag.split("#")[0] + "-" + player_battletag.split("#")[1] + " ! Either \"" + player_battletag + "\" doesn't exist in Overwatch, or they just haven't played enough games to be ranked yet.");
cb();
} else {
TrackedPlayer.create({
channel_id: channel_id,
player_battletag: player_battletag
}).then(function() {
// ensure channel exists
// this is where the problem is - if we add 5 players at once, then we add 5 channels at once
Channel.findOrCreate({
where: {
channel_id: channel_id
}
}).then(function() {
mybot.sendMessage(message, "Done! I've started tracking " + player_battletag + " in this channel.");
cb();
});
});
}
});
}
});
};
var stopTrackingPlayer = function(channel_id, player_battletag, message) {
let me = "@" + message.client.user.username + "#" + message.client.user.discriminator;
TrackedPlayer.find({
where: {
channel_id: channel_id,
player_battletag: player_battletag
}
}).then(function(player) {
if (!player) {
mybot.sendMessage(message, "I'm not tracking " + player_battletag + " in this channel, numbnuts!\n\nIf you want me to start tracking them, try:\n\n`" + me + " track " + player_battletag + "`");
} else {
player.destroy().then(function() {
mybot.sendMessage(message, "Done! I've stopped tracking " + player_battletag + " in this channel.");
});
}
});
};
var listPlayers = function(channel_id, message) {
let me = "@" + message.client.user.username + "#" + message.client.user.discriminator;
TrackedPlayer.findAll({
where: {
channel_id: channel_id
}
}).then(function(rawPlayers) {
let playerBattletags = rawPlayers.map(function(player) {
return player.get().player_battletag;
});
if (playerBattletags.length > 0) {
mybot.sendMessage(message, "I'm currently posting daily ranks for these players in this channel:\n\n" + playerBattletags.join("\n"));
} else {
mybot.sendMessage(message, "I'm not tracking anyone in this channel yet, numbnuts!\n\nStart tracking someone in this channel with:\n\n`" + me + " track battletag#1234`\n\nor\n\n`" + me + " track battletag#1234 anotherbattletag#1234`");
}
});
};
var postToChannel = function(channel_id) {
TrackedPlayer.findAll({
where: {
channel_id: channel_id
}
}).then(function(rawPlayers) {
let playerBattletagsToPost = rawPlayers.map(function(rawPlayer) {
return rawPlayer.get("player_battletag");
});
postPlayerRanks(channel_id, playerBattletagsToPost);
});
};
var getPlayerRank = function(player_id, cb) {
request("https://overwatch-stats-api.com/players/" + encodeURIComponent(player_id), function(error, response, body) {
if (!error && response.statusCode == 200) {
body = JSON.parse(body);
calculateLastTimePlayed(body, function(lastTimePlayed) {
if ("rank" in body) {
cb(null, {
player: player_id,
rank: body.rank,
lastPlayedCompetitive: humanizeLastTimePlayed(lastTimePlayed)
});
} else {
cb(null, {
player: player_id,
rank: "",
lastPlayedCompetitive: humanizeLastTimePlayed(lastTimePlayed)
});
}
});
} else {
cb(null, {
player: player_id,
rank: ""
});
}
});
};
// returns the last time that a player has played, in milliseconds since epoch
var calculateLastTimePlayed = function(player_data, cb) {
if (player_data.history.length == 0) {
return cb(null, moment(player_data.timestamp).valueOf());
}
if (player_data.history.length == 1) {
return cb(null, moment(player_data.history[0].timestamp).valueOf());
}
var mostRecentRank = player_data.rank;
for (var i = 0; i < player_data.history.length; i++) {
if (player_data.history[i].rank != mostRecentRank) {
let lastTimePlayed = player_data.history[i - 1].timestamp;
let converted = moment(lastTimePlayed).valueOf();
return cb(converted);
}
}
return cb(moment(player_data.history[player_data.history.length - 1].timestamp).valueOf());
};
// takes the last time played (in milliseconds since epoch) and returns a string with # of days ago
var humanizeLastTimePlayed = function(lastTimePlayed) {
var duration = moment(new Date()).valueOf() - moment(lastTimePlayed).valueOf();
if (duration < moment.duration(1, "day").valueOf()) {
return "less than 24 hours ago";
} else {
return moment.duration(duration).humanize() + " ago";
}
};
var postPlayerRanks = function(channel_id, player_ids) {
async.map(player_ids, getPlayerRank, function(err, results) {
results.sort(function(a, b) {
return b.rank - a.rank;
});
let strings = results.map(function(result) {
return leftPad(result.player, 20) + " | " + leftPad((result.rank ? result.rank : "-"), 2) + " | " + (result.lastPlayedCompetitive ? result.lastPlayedCompetitive : "-");
});
mybot.sendMessage(channel_id, "**It's hiiiiigh noon.**\n\n```" + leftPad("Player", 20) + " | Rank | Last Played (Competitive)" + "\n" + "-------------------- | ---- | -------------------------" + "\n" + strings.join("\n") + "```");
});
};
var postRanks = function() {
Channel.findAll().then(function(channels) {
for (let channel of channels) {
TrackedPlayer.findAll({
where: {
channel_id: channel.get("channel_id")
}
}).then(function(players) {
if (players.length > 0) {
postPlayerRanks(channel.get("channel_id"), players.map(function(player) {
return player.get("player_battletag");
}));
}
});
}
});
};
new CronJob("0 0 12 * * *", postRanks, function() {},
true, "America/Denver"
);
TrackedPlayer.sync().then(function() {
Channel.sync().then(function() {
console.log("Logging into Discord..."); // eslint-disable-line no-console
mybot.loginWithToken(process.env.DISCORD_KEY, function(err) {
if (err) {
throw err;
} else {
console.log("Successfully logged in to Discord."); // eslint-disable-line no-console
// postRanks();
}
});
});
});
mybot.autoReconnect = true;
mybot.on("disconnected", function(err) {
throw "Disconnected! " + err;
});