forked from renesansz/discord-greeter-bot
-
Notifications
You must be signed in to change notification settings - Fork 1
/
bot.js
287 lines (268 loc) · 9.37 KB
/
bot.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
var Discord = require('discord.io');
var fs = require('fs');
var logger = require('winston');
var auth = require('./auth.json');
// Configure logger settings
logger.remove(logger.transports.Console);
logger.add(logger.transports.Console, {
colorize: true
});
logger.level = 'info';
class RPGList {
constructor(title, channelID) {
this.channelID = channelID;
this.title = title;
this.path = __dirname+"/lists/"+channelID+"/"+title+".json"
this.entries = [];
fs.mkdir(__dirname+"/lists/"+channelID,
{ recursive: true }, (err) => {
if (err) throw err;
});
logger.debug("initialized lists/"+channelID+"/");
// If the file exists, load it; otherwise, save a blank file
if (fs.existsSync(this.path)) {
this.load();
} else {
this.save();
}
}
//add an entry to a list
addEntry(user, userID, message) {
logger.debug("user: "+user+"userID");
this.entries.push({text:message, author:user, authorID:userID});
this.save();
}
//get a printable version with title and numbered entries
get printable(){
let printable = '**'+this.title+"**\n";
for (var entrynum = 0; entrynum < this.entries.length; entrynum++) {
let humnum = entrynum + 1;
printable += humnum+". "+this.entries[entrynum].text+"\n";
};
printable += "Authors: "+this.authors+"\n";
return printable;
}
get authors(){
let authors = new Set();
for (let entry in this.entries){
logger.debug(this.entries[entry].author);
authors.add(this.entries[entry].author);
}
return Array.from(authors).join(", ");
}
get authorIDs(){
let authorIDs = "";
for (var entry in this.entries){
authorIDs += entry.authorID;
}
return authorIDs;
}
get json(){
return JSON.stringify(this);
}
load() {
// Make sure this.path isn't an empty file so loading JSON
// doesn't break everything
if (fs.statSync(this.path)["size"] != 0) {
this.entries = require(this.path);
logger.info(
this.channelID+":"+this.title+" "+this.entries.length+" items loaded");
}
}
save() {
if (this.entries.length == 0) {
fs.writeFile(
this.path,
"[]",
(err) => { if (err) throw err;
logger.info(
this.channelID+":"+this.title+' saved with '+this.entries.length+
" entries"); }
);
} else {
fs.writeFile(
this.path,
JSON.stringify(this.entries),
(err) => { if (err) throw err;
logger.info(
this.channelID+":"+this.title+' saved with '+this.entries.length+
" entries"); }
);
}
}
}
class Zadelrazz {
constructor(discordClient) {
this.bot = discordClient;
this.listeningForListItems = {};
this.helpText = "Commands:"
+ "\n!new [NAME] : Start listening for entries to table NAME."
+ "\n -> Each following message that begins with i., where i is an integer, will be added to the table."
+ "\n!title : Print the active table's name."
+ "\n!end : Close the active table, list its contents, and save them to the server."
+ "\n!help : Display this help message.";
}
initializeTitles(logger) {
var titles = {};
logger.info("Loading lists according to titles.json:");
if (fs.existsSync("./titles.json")) {
titles = require("./titles.json");
}
//We're about to print each channel and title, so this is redundant, I think
logger.debug(titles);
return titles;
}
loadActiveListsFromTitles(titles, logger) {
//for each active title, load that list from file
//key = channelID, titles[key] = title
var activeLists = {};
for (var channelID in titles) {
logger.debug(channelID+"attempting to load "+titles[channelID]);
this.listeningForListItems[channelID] = true
let newlist = new RPGList(titles[channelID], channelID);
activeLists[channelID] = newlist;
logger.debug("Lists loaded successfuly");
}
return activeLists;
}
writeTitlesToJSON(titles) {
fs.writeFile('titles.json',
JSON.stringify(titles),
(err) => { if (err) throw err; }
);
}
newList(channelID, title) {
//Close the active list, if any
this.endActiveList(channelID)
// Then, bombs away!
this.listeningForListItems[channelID] = true
titles[channelID] = title;
this.writeTitlesToJSON(titles);
activeLists[channelID] = new RPGList(title, channelID);
this.bot.sendMessage({
to: channelID,
message: 'Starting: ' + titles[channelID]
});
}
sendActiveTitle(channelID) {
if (this.listeningForListItems[channelID] && channelID in activeLists) {
this.bot.sendMessage({
to: channelID,
message: 'Current: '+titles[channelID]
});
} else {
this.bot.sendMessage({
to: channelID,
message: 'No current list for this channel.'
});
}
}
processListItem(user, userID, channelID, message, evt) {
if (this.listeningForListItems[channelID] && channelID in activeLists) {
let entrytext = message.substring(message.indexOf(".")+1);
entrytext = entrytext.trim();
//Now that zadelrazz is much more reliable
//bot.addReaction({
// channelID: channelID,
// messageID: evt.d.id,
// reaction: "🤖"
//}, (err,res) => {
// if (err) logger.info(err)
//});
logger.info(channelID+":"+activeLists[channelID].title+" adding entry:");
logger.info(entrytext);
logger.debug("By "+userID+":"+user);
//Printing the whole list object every time is messy and poorly formatted
logger.debug(activeLists[channelID].json);
activeLists[channelID].addEntry(user, userID, entrytext);
} else {
logger.info(channelID+': Ignoring apparently list-item-like message.');
}
}
endActiveList(channelID) {
logger.debug(channelID+": Attempting to end active list");
//If there is an active list,
if (titles[channelID]) {
//Print the list
this.bot.sendMessage({
to: channelID,
message: activeLists[channelID].printable
});
//Save the list
activeLists[channelID].save();
//Remove it from active
delete activeLists[channelID];
//Remove it from list of titles
delete titles[channelID];
//Update the json list of titles
this.writeTitlesToJSON(titles);
//Mark this channel as not listening for items
this.listeningForListItems[channelID] = false;
logger.debug(channelID+": List closed");
} else {
logger.debug(channelID+": No active list");
}
}
sendHelpText(channelID) {
bot.sendMessage({
to: channelID,
message: this.helpText
});
}
}
// Initialize Discord Bot
var bot = new Discord.Client({
token: auth.token,
autorun: true
});
// Confirm bot is ready
bot.on('ready', function (evt) {
logger.info('Connected');
logger.info('Logged in as: ');
logger.info(bot.username + ' - (' + bot.id + ')');
});
// Bring the big man in and let him do his business
var zd = new Zadelrazz(bot);
// Resume state if shit crashed last time, otherwise make new lists
var titles = zd.initializeTitles(logger);
var activeLists = zd.loadActiveListsFromTitles(titles, logger);
bot.on('message', function (user, userID, channelID, message, evt) {
// The philosophy is that this bot.on() function handles incoming text and,
// if they're valid commands, passes them on to Zadelrazz. It shouldn't
// decide what he does with them except in the case of failure, where bot.on
// politely requests that he send help text.
// Listen for messages that start with `!` and process the first word
// as a command
if (message.substring(0, 1) == '!') {
var args = message.substring(1).split(' ');
var cmd = args[0];
args = args.splice(1);
switch(cmd) {
// !new [title]
case 'new':
title = message.substring(5);
zd.newList(channelID, title);
break;
case 'title':
zd.sendActiveTitle(channelID);
break;
// save the list and reprint it collated
case 'end':
zd.endActiveList(channelID);
break;
case 'help':
zd.sendHelpText(channelID);
break;
default:
break;
//Unknown command is not a helpful response
//bot.sendMessage({ to: channelID, message: 'Unknown command.' });
//zd.sendHelpText();
}
}
// Listen for list entries that are just a number and a dot
let dotsplits = message.split('.');
if (dotsplits[0].length > 0 && !isNaN(dotsplits[0])) {
zd.processListItem(user, userID, channelID, message, evt);
}
})