initial commit

This commit is contained in:
Brandon Rozek 2016-07-11 23:24:15 -04:00
commit bf865d4535
39 changed files with 1056 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

55
Rozbot.js Normal file
View file

@ -0,0 +1,55 @@
var promise = require('promise-polyfill');
var prototypes = require('./lib/helpers/additionalPrototypes.js');
var User = require('./User.js');
module.exports = function() {
//Store possible commands
this.commandList = [];
//Store users
this.userList = [];
//Add commands to the commandList
this.extend = function(command) {
if (typeof(command) === 'object') {
this.commandList.push(command);
} else {
throw new Error("Extend must take a Command Object");
}
};
//Add user to userlist
this.addUser = function(username, sendMethod) {
var user = new User(username, sendMethod);
this.userList.push(user);
return user;
}
//Get's user from userlist by username
this.getUser = function(username) {
for (var i = 0; i < this.userList.length; i++) {
if (this.userList[i].username === username) {
return this.userList[i];
}
}
//User not found
return null;
}
//Gives Rozbot's response
this.respond = function(message, user) {
//Store whether or not an app wants to listen to the next message
var inAppScope = user.inAppScope
//Used to allow apps to get the next message
user.listener.emit('message', message);
if (!inAppScope) {
var args = [message, user.send];
//Find the right command to run
var command = this.commandList.find(function(cmd) {
return cmd.condition(message) === true;
});
//Run the command using user's contextual data (app by app basis)
if (command !== undefined) {
command.respond.apply(command, args.concat(user.getData(command.name)));
}
}
}
}

57
User.js Normal file
View file

@ -0,0 +1,57 @@
var EventEmitter = require('events');
var promise = require('promise-polyfill');
module.exports = function(username, sendMethod) {
this.username = username;
this.data = {};
this.inAppScope = false;
this.listener = new EventEmitter();
this.send = sendMethod;
this.getData = function(commandName) {
var self = this;
//If it doesn't exist, create it
if (this.data[commandName] === undefined) {
this.data[commandName] = {
properties: [],
setProperty: function(key, value) {
//First make sure it doesn't already exist
for (var i = 0; i < this.properties.length; i++) {
//If it does then update it
if (this.properties[i].key === key) {
this.properties[i].value = value;
return;
}
}
//If it doesnt exist then add it to the properties array
this.properties.push({key: key, value: value});
},
getProperty: function(key) {
for (var i = 0; i < this.properties.length; i++) {
if (this.properties[i].key === key) {
return this.properties[i].value;
}
}
//Key does not exist
return null;
},
isset: function(key) {
return this.getProperty(key) !== null;
},
prompt: function(question) {
question = question || "is reading your next message";
//Inform user that the next input goes to the app
self.send(commandName + ": " + question);
//Make it so that the input doesnt get processed by any other app
self.inAppScope = true;
return new promise(function(resolve, reject) {
self.listener.once('message', function(text) {
resolve(text);
self.inAppScope = false;
});
});
}
}
}
return this.data[commandName];
}
}

36
example.js Normal file
View file

@ -0,0 +1,36 @@
var Rozbot = require('./Rozbot.js');
var User = require('./User.js');
var rozbot = new Rozbot();
/*
Order matters!!
-Rozbot checks through all the commands until it hits one that matches
*/
rozbot.extend(require('./lib/commands/onTheRadio.js'));
getWeather = require('./lib/commands/getWeather.js');
getWeather.setId('188d435fd17dcf22261679cf64e98cd5');
rozbot.extend(getWeather);
rozbot.extend(require('./lib/commands/grabUpdates.js'));
rozbot.extend(require('./lib/commands/grabTweets.js'));
rozbot.extend(require('./lib/commands/displayTweet.js'));
rozbot.extend(require('./lib/commands/Hangman.js'));
rozbot.extend(require('./lib/commands/grabPictures.js'));
rozbot.extend(require('./lib/commands/grabWikipedia.js'));
rozbot.extend(require('./lib/commands/grabDefinition.js'));
rozbot.extend(require('./lib/commands/calculate.js'));
rozbot.extend(require('./lib/commands/timer.js'));
rozbot.extend(require('./lib/commands/search.js'));
//rozbot.extend(require('./lib/commands/naturalSpeech.js'));
rozbot.extend(require('./lib/commands/queryDuckDuckGo.js'));
//rozbot.respond(process.argv[2], rozbot.getUser("Command Line") || rozbot.addUser("Command Line"));
rozbot.respond("Let's play hangman!", rozbot.getUser("Command Line") || rozbot.addUser("Command Line", function(msg) {
console.log(msg);
}));
var letters = ["a", "e", "i", "o", "u", "b"]
rozbot.respond(letters[0], rozbot.getUser("Command Line"));
rozbot.respond(letters[1], rozbot.getUser("Command Line"));
rozbot.respond(letters[2], rozbot.getUser("Command Line"));
rozbot.respond(letters[3], rozbot.getUser("Command Line"));
rozbot.respond(letters[4], rozbot.getUser("Command Line"));

8
lib/commands/Command.js Normal file
View file

@ -0,0 +1,8 @@
module.exports = function(commandName, condition, commandFunction) {
//Name for identification purproses
this.name = commandName;
//Must be a function which returns a boolean if it believes that the it's the appropriate command for the message
this.condition = condition;
//The command's core functionality
this.respond = commandFunction;
}

112
lib/commands/Hangman.js Normal file
View file

@ -0,0 +1,112 @@
var Command = require('./Command.js');
var fetch = require('../promise/fetch.js');
var cheeriop = require('../promise/cheerio.js');
var promise = require('promise-polyfill');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.contain('play') && tokens.contain('hangman');
}
module.exports = new Command("Hangman", condition, function(text, send, userData) {
var GUESSES_ALLOWED = 7;
//Lets get a random word!
send("I'm thinking of a word...");
//Grabs headline of random page
var grabHeadline = function(html) {
return new promise(function(resolve, reject) {
cheeriop(html).then(function($) {
var response = $('#headword').text().trim()
if (response) {
resolve(response);
} else {
reject("");
}
}).catch(function(error) {
console.log(error);
reject("");
})
});
}
//Recursive guessing letters until person loses or wins
var guessLetter = function() {
var correctLetters = userData.getProperty("correctLetters");
var guessedLetters = userData.getProperty("guessedLetters");
var word = userData.getProperty("word");
var numOfUniqueLetters = userData.getProperty("numOfUniqueLetters");
if (correctLetters.length === numOfUniqueLetters) {
send("You win!!");
return;
}
if (guessedLetters.length - correctLetters.length > GUESSES_ALLOWED) {
send("You lose...");
send("The word was " + word);
return;
}
return new promise(function(resolve, reject) {
userData.prompt("Guess a letter").then(function(letter) {
if (letter.length != 1) {
send("You can only guess one letter at a time");
} else {
if (guessedLetters.indexOf(letter) !== -1) {
send("You already guessed this letter");
} else {
if (word.indexOf(letter) !== -1) {
send("The letter is in the word!");
correctLetters.push(letter);
} else {
send("The letter is not in the word..");
}
//Push letter to lettersGuessed array and send the part of the word guessed so far.
guessedLetters.push(letter);
send(revealKnownCharacters(word, correctLetters));
}
}
return;
}).then(function() { resolve(guessLetter()) }).catch(function(e) { console.log(e); reject(e); });
});
}
//Shows player word with __ and known letters
var revealKnownCharacters = function(word, lettersArray) {
return word.split('').map(function(item) {
return (lettersArray.indexOf(item) !== -1)? item: "_";
}).join('');
}
//Counts the number of unique letters in a word
var countUniqueLetters = function(word) {
var letters = [];
for (var i = 0; i < word.length; i++) {
if (letters.indexOf(word[i]) === -1) {
letters.push(word[i]);
}
}
return letters.length;
}
//Grab a random word from wordnik and start the game
fetch("https://wordnik.com/randoml", {rejectUnauthorized: false}).then(function(res) {
origin = res.meta.finalUrl;
return grabHeadline(res.body.toString());
}).then(function(word) {
send("The word is " + word.length + " letters long");
//Setup game variables
userData.setProperty("word", word);
userData.setProperty("numOfUniqueLetters", countUniqueLetters(word));
userData.setProperty("correctLetters", []);
userData.setProperty("guessedLetters", []);
//start
guessLetter();
}).catch(function(error) {
send(error);
});
});

23
lib/commands/calculate.js Normal file
View file

@ -0,0 +1,23 @@
var Command = require('./Command.js');
var mathEval = require('../promise/math-eval.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.contain('calculate') || tokens.contain('calc');
}
module.exports = new Command("Mathjax", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var query;
if (tokens.contain('calculate')) {
query = text.from('calculate');
} else if (tokens.contain('calc')) {
query = text.from('calc');
}
query = query.removeAll('?');
mathEval(query.toString()).then(function(answer) {
send(answer);
}).catch(function(error) {
send("I'm not smart enough to calcuate that yet >.<");
});
});

View file

@ -0,0 +1,26 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var parseTwitter = require('../helpers/parseTwitter.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.filter(function(item) {
return item.contains("twitter.com") && item.contains("/status/")
}).length > 0;
}
module.exports = new Command("DisplayTweet", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var status = tokens.filter(function(item) {
return item.contains("twitter.com") && item.contains("/status/")
});
status.forEach(function(item) {
grabURL(item + '?').then(function(response) {
return parseTwitter(response.body.toString());
}).then(function(tweet) {
send(tweet);
}).catch(function(error) {
console.log(error);
});
});
})

View file

@ -0,0 +1,48 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return command.id != '' && tokens.contain('weather');
}
var command = new Command("Weather", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var location = tokens.slice(tokens.indexOf('weather') + 1, tokens.length);
//Function to get the weather
var getWeather = function(loc) {
grabURL("http://api.openweathermap.org/data/2.5/weather?q=" + loc.join('+') + "&units=imperial&appid=" + command.id)
.then(function(response) { return response.body.toString(); })
.then(function(text) { return JSON.parse(text); })
.then(function(json) {
if (json.cod == 401) {
send("Invalid API key set");
} else {
send(json.weather[0].description + " and the temperature is " + json.main.temp + " degrees Fahrenheit in " + json.name + "\nWeather provided by OpenWeatherMap");
}
}).catch(function(error) { send(error); });
}
//Did the person not specify the location and have no location set?
if (location.length === 0 && !userData.isset("location")) {
userData.prompt("Where do you live?").then(function(loc) {
userData.setProperty("location", loc.split(" "));
getWeather(loc.split(" "));
});
}
//The person specified the location
else if (location.length !== 0) {
getWeather(location);
}
//The person didn't specify but he has a location saved
else {
getWeather(userData.getProperty("location"));
}
});
command.id = '';
//Need to call this with a proper id for this command to work
command.setId = function(id) {
this.id = id;
}
module.exports = command;

View file

@ -0,0 +1,33 @@
var Command = require('./Command.js');
var fetch = require('../promise/fetch.js');
var parseWordnik = require('../helpers/parseWordnik.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
var query;
if (tokens.contain("define") && tokens[tokens.indexOf('define') + 1]) {
query = tokens.splice(tokens.indexOf('define') + 1).join("%20");
} else if (tokens.contain("definition") && tokens[tokens.indexOf('definition') + 1]) {
query = tokens.splice(tokens.indexOf('definition') + 1).join("%20");
}
return (tokens.contain("define") || tokens.contain("definition")) && query != "";
}
module.exports = new Command("Dictionary", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var query = "";
if (tokens.contain("define") && tokens[tokens.indexOf('define') + 1]) {
query = tokens.splice(tokens.indexOf('define') + 1).join("%20");
} else if (tokens.contain("definition") && tokens[tokens.indexOf('definition') + 1]) {
query = tokens.splice(tokens.indexOf('definition') + 1).join("%20");
}
var origin;
fetch("https://www.wordnik.com/words/" + query, {rejectUnauthorized: false}).then(function(res) {
origin = res.meta.finalUrl;
return parseWordnik(res.body.toString());
}).then(function(def) {
send(def + "\nFor more go to " + origin);
}).catch(function(error) {
send(error);
});
})

View file

@ -0,0 +1,42 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var parsePictures = require('../helpers/parsePictures.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.contain('photo') || tokens.contain('photos') || tokens.superContain('pic') || tokens.superContain('pics');
}
module.exports = new Command("Pixabay", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var of = "";
var amt = 0;
if (tokens.contain("photo")) {
of = tokens.slice(tokens.indexOf('photo') + 1).join(' ');
amt = 1;
} else if (tokens.contain("photos")) {
of = tokens.slice(tokens.indexOf('photos') + 1).join(' ');
amt = 5;
} else if (tokens.superContain("pic")) {
//Is the last letter a 's'?
if (tokens[tokens.superContainAt('pic')][tokens[tokens.superContainAt('pic')].length - 1] == 's') {
amt = 5;
} else {
amt = 1;
}
of = tokens.slice(tokens.superContainAt('pic') + 1).join(' ');
}
var origin;
grabURL("https://pixabay.com/en/photos/?q=" + of).then(function(res) {
origin = res.meta.finalUrl;
return parsePictures(res.body.toString(), amt);
}).then(function(pictures) {
if (amt == 1) {
send("Here is a picture: " + pictures);
} else {
send("Here are some pictures of " + of + ": \n" + pictures.join("\n") + " For more, check out " + origin);
}
}).catch(function(error) {
send(error);
});
})

View file

@ -0,0 +1,24 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var parseTwitter = require('../helpers/parseTwitter.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
//Text must contain the word tweets and have a handler
return tokens.contain('tweets') && tokens.filter(function(f) { return f.indexOf("#") == 0 || f.indexOf("@") == 0}).length > 0;
}
module.exports = new Command("GetTweets", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var handles = tokens.filter(function(f) { return f.indexOf("#") == 0 || f.indexOf("@") == 0});
handles.forEach(function(handle) {
var handleUrl = (handle[0] == "@")? "https://twitter.com/" + handle.substring(1): "https://twitter.com/hashtag/" + handle.substring(1);
return grabURL(handleUrl).then(function(res) {
return parseTwitter(res.body.toString());
}).then(function(tweets) {
send("The latest tweets from " + handle + ":\n" + tweets.join("\n"));
}).catch(function(error) {
send(error);
});
});
})

View file

@ -0,0 +1,32 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var grabFeedURL = require('../helpers/grabFeedURL.js');
var grabTitles = require('../helpers/grabTitles.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
//needs to have the word update and a URL
return tokens.superContain("update") && tokens.slice(tokens.superContainAt("update") + 1).filter(function(item) {
return item.contains('.');
}).length > 0
}
module.exports = new Command("Feed", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var urls = tokens.slice(tokens.superContainAt("update") + 1).filter(function(item) {
return item.contains('.');
});
send("One second and I'll go check!");
urls.forEach(function(element) {
console.log(element);
return grabURL(element).then(function(res) {
return grabFeedURL(res.meta.finalUrl, res.body.toString());
}).then(function(feedURL) {
return grabTitles(feedURL);
}).then(function(titles) {
send("The latest 5 articles from " + element + " :\n" + titles.join("\n"));
}).catch(function(error) {
send(error);
})
});
})

View file

@ -0,0 +1,22 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var parseWikipedia = require('../helpers/parseWikipedia.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.superContain('what') && tokens.slice(tokens.superContainAt('what') + 1).join('+').length > 0;
}
module.exports = new Command("Wikipedia", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var query = tokens.slice(tokens.superContainAt('what') + 1).join('+');
var origin;
grabURL("https://en.wikipedia.org/w/index.php?search=" + query).then(function(res) {
origin = res.meta.finalUrl;
return parseWikipedia(res.body.toString());
}).then(function(definition) {
send(definition + "\nMore information at " + origin);
}).catch(function(error) {
send(error);
});
})

View file

View file

@ -0,0 +1,125 @@
/***
Keep disabled until major rewrite has gone under way
***/
var Command = require('./Command.js');
var grabTokens = require('../helpers/grabTokens.js');
var greetings = "hello|hi|hey|yo|morning|afternoon|evening";
var wantSomething = /(\w+) (want|wants) ([^.&^\n]+)/i;
var happy = "yay|woo|yess|:D|:\\)"
var url = "link|url";
var condition = function(text) {
}
module.exports = new Command("NaturalSpeech", condition, function(text, send, extra) {
var from = extra.from || "";
var privateMessage = extra.privateMessage || false;
var tokens = grabTokens(text);
/*
Link to codeshare
*/
if (new RegExp(url).test(text) && tokens.contain("codeshare")) {
send("https://hidden-ocean-8102.herokuapp.com/");
}
/*
:( -> It's okay.
*/
else if (tokens.contain(":(")) {
send("It's okay");
}
/*
thank you -> You're welcome :)
*/
else if (tokens.superContain("thank") && (tokens.superContain("rozbot") || privateMessage)) {
send("You're welcome :)");
}
/*
rozbot? -> Yes?
*/
else if (text.toLowerCase() === "rozbot?") {
send("Yes?");
}
/*
Hugs rozbot -> Rozbot hugs [user]
*/
else if ((tokens.superContain("rozbot") || privateMessage) && tokens.superContain("hug")) {
send("Hugs " + from);
}
/*
Woo -> Yeah!
*/
else if (new RegExp(happy, 'i').test(text)) {
send("Yeah!");
}
/*
[user] wants [item] -> Gives [user] [item]
*/
else if (wantSomething.test(text)) {
var responseTokens = wantSomething.exec(text);
var person = (responseTokens[1].toLowerCase() === "i")? from: responseTokens[1];
send("Gives " + person + " " + responseTokens[3]);
}
/*
Who is Brandon? -> Brandon is the most awesome person in the world.
*/
else if ((tokens.contain("who") || tokens.contain("what")) && tokens.contain("brandon") && tokens.contain('rozek')) {
send("Brandon is the most awesome person in the world.");
}
/*
Who is Rozbot? -> A friendly neighborhood IRC bot
*/
else if (tokens.contain('who') || tokens.contain('what') && tokens.superContain("rozbot")&& !tokens.contain('radio')) {
send("A friendly neighborhood IRC bot");
}
/*
What is Brandon up to? -> [Lists projects]
*/
else if ((tokens.contain("how") || tokens.contain("doing") || tokens.contain("up")) && tokens.contain("brandon")) {
send("I'm not sure. He may be doing a variety of things. For example:\n\
working on his site (https://brandonrozek.com)\n\
working on a writer's portfolio (https://toridayton.com\n\
taking pictures for sentenceworthy.com\n\
managing Math I/O\n\
working on his apps codeshare or babbler.\n\
running his radio (https://radio.zeropointshift.com)\n\
Hopefully, he's not working on me. Cuz' I'm perfect.");
}
/*
How are you Rozbot? -> I'm awesome
*/
else if ((tokens.superContain("rozbot") || privateMessage) && tokens.contain("how")) {
send("I'm awesome.");
}
/*
Good morning Rozbot! -> Hello [user]!
*/
else if ((tokens.superContain('rozbot') || privateMessage) && new RegExp(greetings, 'i').test(text)) {
send("Hello " + from + "!");
}
/*
What are you up to Rozbot? -> Currently working on my job
*/
else if ((tokens.superContain("rozbot") || privateMessage) && tokens.superContain("what") && (tokens.contain("up") || tokens.contain("doing"))) {
send("Currently working on my job");
}
/*
What is your job Rozbot? -> Chilling on IRC doing whatever Brandon programs me to do
*/
else if (tokens.superContain("rozbot") && tokens.superContain("what") && tokens.contain("job")) {
send("Chilling on IRC doing whatever Brandon programs me to do.");
}
/*
Start Greenteam meeting -> [instructions for mumble]
*/
else if (tokens.contain("start") && tokens.contain("greenteam") && tokens.contain("meeting")) {
send("Everyone please connect to mumble\n\
Host: zeropointshift.com\n\
Leave port at default\n\
Give yourself a sensible username\n\
Label it whatever you want");
}
})

View file

@ -0,0 +1,15 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.superContain('what') && tokens.contain('radio');
}
module.exports = new Command("OnTheRadio", condition, function(text, send, userData) {
grabURL('https://meldicradio.com/json')
.then(function(response) { return response.body.toString(); })
.then(function(text) { return JSON.parse(text); })
.then(function(json) { send("\"" + json.artist + " - " + json.title + "\" is currently playing on meldicradio.com"); })
.catch(function(error) { send(error); });
});

View file

@ -0,0 +1,25 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var condition = function(text) {
//This is a catch all
return true;
}
module.exports = new Command("DuckDuckGoQuery", condition, function(text, send, userData) {
grabURL("https://duckduckgo.com/?q=" + text.split(' ').join('+') + "&format=json&no_redirect=1&t=rozbot")
.then(function(response) { return response.body.toString(); })
.then(function(text) { return JSON.parse(text); })
.then(function(json) {
if (json.Answer != "") {
send(json.Answer + "\nResults from DuckDuckGo");
return true;
}
if (json.AbstractText != "") {
send(json.AbstractText + "\nMore at " + json.AbstractURL);
return true;
}
if (json.Redirect != "") {
send(json.Redirect);
}
}).catch(function(error) { console.log(error); });
})

19
lib/commands/search.js Normal file
View file

@ -0,0 +1,19 @@
var Command = require('./Command.js');
var grabURL = require('../helpers/grabURL.js');
var parseDuckDuckGo = require('../helpers/parseDuckDuckGo.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.contain('search');
}
module.exports = new Command("Search", condition, function(text, send, userData) {
var tokens = grabTokens(text);
var search = text.substring(text.indexOf('search') + 6);
grabURL("https://duckduckgo.com/html/?q=" + search.split(' ').join('+') + '&t=rozbot')
.then(function(response) { return response.body.toString(); })
.then(function(text) { return parseDuckDuckGo(text) })
.then(function(results) { send("Results for \"" + search + "\":\n" + results.join("\n") + "\nSearch Provided by DuckDuckGo"); })
.catch(function(error) { send(error) });
});

40
lib/commands/timer.js Normal file
View file

@ -0,0 +1,40 @@
var Command = require('./Command.js');
var grabTokens = require('../helpers/grabTokens.js');
var condition = function(text) {
var tokens = grabTokens(text);
return tokens.superContain('timer') && (tokens.superContain('hour') || tokens.superContain('min') || tokens.superContain('sec'))
}
module.exports = new Command('Timer', condition, function(text, send, userData) {
var tokens = grabTokens(text);
var seconds = 0;
if (tokens.superContain('hour')) {
var numHours = Number(tokens[tokens.superContainAt('hour') - 1]);
if (numHours || numHours == 0) {
seconds += numHours * 3600;
} else {
seconds += 3600;
}
}
if (tokens.superContain('min')) {
var numMins = Number(tokens[tokens.superContainAt('min') - 1]);
if (numMins|| numMins == 0) {
seconds += numMins * 60;
} else {
seconds += 60;
}
}
if (tokens.superContain('sec')) {
var numSeconds = Number(tokens[tokens.superContainAt('sec') - 1]);
if (numSeconds || numSeconds == 0) {
seconds += numSeconds;
} else {
seconds += 1;
}
}
send("Timer set for " + seconds + " seconds");
setTimeout(function() {
send("Times up!");
}, seconds * 1000);
});

View file

@ -0,0 +1,39 @@
String.prototype.contains = function(str) {
return this.indexOf(str) != -1;
}
Array.prototype.contain = function(item) {
return this.indexOf(item) != -1;
}
Array.prototype.superContain = function(item) {
for (var i = 0; i < this.length; i++) {
if (this[i].indexOf(item) != -1) {
return true;
}
}
return false;
}
Array.prototype.superContainAt = function(item) {
for (var i = 0; i < this.length; i++) {
if (this[i].indexOf(item) != -1) {
return i;
}
}
return false;
}
String.prototype.from = function(str) {
return this.substring(this.indexOf(str) + str.length);
}
String.prototype.remove = function(str) {
var index = this.indexOf(str);
return this.substring(0, index) + this.substring(index + str.length);
}
String.prototype.removeAll = function(str) {
var newString = this.substring(0);
for (var i = 0; i < arguments.length; i++) {
while (newString.contains(arguments[i])) {
newString = newString.remove(arguments[i]);
}
}
return newString;
}

View file

@ -0,0 +1,27 @@
var promise = require('promise-polyfill');
var cheerio = require('../promise/cheerio.js');
var url = require('url');
module.exports = function(origin, html) {
return new promise(function(resolve, reject) {
cheerio(html).then(function($) {
var link = $('link[rel=alternate]').attr('href');
if (link) {
var feedURL = url.parse(link, true, true);
if (feedURL.hostname === null) {
feedURL = url.parse(url.resolve(origin, feedURL.href), true, true)
}
if (feedURL.protocol === null) {
feedURL = url.parse(url.resolve('http:', feedURL.href), true, true);
}
resolve(feedURL.href);
}
else {
reject("I couldn't find the link >.<");
}
}).catch(function(error) {
console.log(error);
reject("I wasn't able to find the link :/");
})
})
}

22
lib/helpers/grabTitles.js Normal file
View file

@ -0,0 +1,22 @@
var promise = require('promise-polyfill');
var feed = require('../promise/feed.js');
module.exports = function(feedURL) {
return new promise(function(resolve, reject) {
feed(feedURL).then(function(articles) {
var titles = [];
var length = Math.min(5, articles.length);
for (var i = 0; i < length; i++) {
titles.push(articles[i].title + " " + articles[i].link);
}
if (titles.length > 0) {
resolve(titles);
} else {
reject("There are no updates");
}
}).catch(function(error) {
console.log(error);
reject("I couldn't parse the feed :(");
})
});
}

10
lib/helpers/grabTokens.js Normal file
View file

@ -0,0 +1,10 @@
var stopWords = require('./stopWords.js');
module.exports = function(text) {
text = text || "";
return text.split(' ').filter(function(item) {
return stopWords.indexOf(item) === -1;
}).map(function(item) {
return (item.contains("http")) ? item: item.removeAll("?", ".", ",", "!").toLowerCase();
});
}

19
lib/helpers/grabURL.js Normal file
View file

@ -0,0 +1,19 @@
var promise = require('promise-polyfill');
var url = require('url');
var fetch = require('../promise/fetch.js');
module.exports = function(websiteURL) {
return new promise(function(resolve, reject) {
var weburl = url.parse(websiteURL, true, true);
if (weburl.protocol === null) {
weburl = url.parse('http://' + websiteURL);
}
websiteURL = weburl.href;
fetch(websiteURL).then(function(res) {
resolve({meta: res.meta, body: res.body});
}).catch(function(error) {
console.log(error);
reject("Sorry, I wasn't able to grab the page.");
});
});
}

View file

@ -0,0 +1,7 @@
var fsStat = require('../promise/fs-stat.js');
module.exports = function(file) {
return fsStat(file).then(function(stats) {
return stats.mtime;
})
}

View file

@ -0,0 +1,22 @@
var cheerio = require('../promise/cheerio.js');
var promise = require('promise-polyfill');
module.exports = function(html) {
return new promise(function(resolve, reject) {
cheerio(html).then(function($) {
var results = []
var resultsContainer = $('.result__url');
var resultsToShow = Math.min(5, resultsContainer.length - 1);
for (var i = 0; i < resultsToShow; i++) {
results.push(resultsContainer.eq(i).text())
}
if (results.length > 0) {
resolve(results);
} else {
reject("No results were found. [DuckDuckGo]")
}
}).catch(function(error) {
reject(error);
});
});
}

View file

@ -0,0 +1,28 @@
var cheeriop = require('../promise/cheerio.js');
var promise = require('promise-polyfill');
module.exports = function(html, amt) {
return new promise(function(resolve, reject) {
cheeriop(html).then(function($) {
var photos = [];
var pics = $('#photo_grid .item');
var picsToShow = Math.min(amt, pics.length);
if (picsToShow == 1) {
resolve("https://pixabay.com" + $('#photo_grid .item').children().find('img').eq(0).attr('src'));
return;
}
for (var i = 0; i < picsToShow; i++) {
photos.push("https://pixabay.com" + $('#photo_grid .item').children().find('img').eq(i).attr('src'));
}
if (photos.length > 0) {
resolve(photos);
} else {
reject("I looked around everywhere and couldn't find any");
}
}).catch(function(error) {
console.log(error);
reject(error);
})
});
}

View file

@ -0,0 +1,22 @@
var cheerio = require('../promise/cheerio.js');
var promise = require('promise-polyfill');
module.exports = function(html) {
return new promise(function(resolve, reject) {
cheerio(html).then(function($) {
var tweets = [];
var tweetsContainer = $('.tweet');
var tweetsToShow = Math.min(5, tweetsContainer.length - 1);
for (var i = 0; i < tweetsToShow; i++) {
tweets.push($('.tweet').children().find('.fullname').eq(i).text() + " (" + $('.tweet').children().find('.username').eq(i).text() + ")" + ": " + $('.tweet').children().find('.tweet-text').eq(i).text())
}
if (tweets.length > 0) {
resolve(tweets);
} else {
reject("No tweets were found.")
}
}).catch(function(error) {
reject(error);
});
});
}

View file

@ -0,0 +1,17 @@
var cheeriop = require('../promise/cheerio.js');
var promise = require('promise-polyfill');
module.exports = function(html) {
return new promise(function(resolve, reject) {
cheeriop(html).then(function($) {
if ($('.mw-search-nonefound').length > 0) {
reject("");
} else {
resolve($('#mw-content-text').find('p').first().text());
}
}).catch(function(error) {
console.log(error);
reject("");
})
});
}

View file

@ -0,0 +1,18 @@
var cheeriop = require('../promise/cheerio.js');
var promise = require('promise-polyfill');
module.exports = function(html) {
return new promise(function(resolve, reject) {
cheeriop(html).then(function($) {
var response = $('#define').children().find('ul').children().first().text()
if (response) {
resolve(response);
} else {
reject("");
}
}).catch(function(error) {
console.log(error);
reject("");
})
});
}

1
lib/helpers/stopWords.js Normal file
View file

@ -0,0 +1 @@
module.exports = ["a", "about", "above", "across", "after", "afterwards", "again", "against", "all", "almost", "alone", "along", "already", "also", "although", "always", "am", "among", "amongst", "amoungst", "amount", "an", "and", "another", "any", "anyhow", "anyone", "anything", "anyway", "anywhere", "around", "are", "as", "at", "back", "be", "became", "because", "become", "becomes", "becoming", "been", "before", "beforehand", "behind", "being", "below", "beside", "besides", "between", "beyond", "bill", "both", "bottom", "but", "by", "call", "can", "cannot", "cant", "co", "con", "could", "couldnt", "cry", "de", "describe", "detail", "do", "done", "down", "due", "during", "each", "eg", "eight", "either", "eleven", "else", "elsewhere", "empty", "enough", "etc", "even", "ever", "every", "everyone", "everything", "everywhere", "except", "few", "fifteen", "fify", "fill", "find", "fire", "first", "five", "for", "former", "formerly", "forty", "found", "four", "from", "front", "full", "further", "get", "give", "go", "had", "has", "hasnt", "have", "he", "hence", "her", "here", "hereafter", "hereby", "herein", "hereupon", "hers", "herself", "him", "himself", "his", "however", "hundred", "ie", "if", "in", "inc", "indeed", "interest", "into", "is", "it", "its", "itself", "keep", "last", "latter", "latterly", "least", "less", "ltd", "made", "many", "may", "me", "meanwhile", "might", "mill", "mine", "more", "moreover", "most", "mostly", "move", "much", "must", "my", "myself", "name", "namely", "neither", "never", "nevertheless", "next", "nine", "no", "nobody", "none", "noone", "nor", "not", "nothing", "now", "nowhere", "of", "wff", "often", "on", "once", "one", "only", "onto", "or", "other", "others", "otherwise", "our", "ours", "ourselves", "out", "over", "own", "part", "per", "perhaps", "please", "put", "rather", "re", "same", "see", "seem", "seemed", "seeming", "seems", "serious", "several", "she", "should", "show", "side", "since", "sincere", "six", "sixty", "so", "some", "somehow", "someone", "something", "sometime", "sometimes", "somewhere", "still", "such", "system", "take", "ten", "than", "that", "the", "their", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "therefore", "therein", "thereupon", "these", "they", "thickv", "thin", "third", "this", "those", "though", "three", "through", "throughout", "thru", "thus", "to", "together", "too", "top", "toward", "towards", "twelve", "twenty", "two", "un", "under", "until", "up", "upon", "us", "very", "via", "was", "we", "well", "were", "whatever", "whence", "whenever", "whereafter", "whereas", "whereby", "wherein", "whereupon", "wherever", "whether", "which", "while", "whither", "whoever", "whole", "whom", "whose", "will", "with", "within", "without", "would", "yet", "your", "yours", "yourself", "yourselves"];

13
lib/promise/appendFile.js Normal file
View file

@ -0,0 +1,13 @@
var fs = require('fs');
var promise = require('promise-polyfill');
module.exports = function(file, data) {
return new promise(function(resolve, reject) {
fs.appendFile(file, data + "\n", function(error) {
if (error) {
console.log(error);
//reject(error);
}
});
});
}

7
lib/promise/cheerio.js Normal file
View file

@ -0,0 +1,7 @@
var cheerio = require('cheerio').load;
var promise = require('promise-polyfill');
module.exports = function(html) {
return new promise(function(resolve, reject) {
resolve(cheerio(html));
});
}

14
lib/promise/feed.js Normal file
View file

@ -0,0 +1,14 @@
var feed = require('feed-read');
var promise = require('promise-polyfill');
module.exports = function(link) {
return new promise(function(resolve, reject) {
feed(link, function(error, articles) {
if (error) {
reject(error);
} else {
resolve(articles);
}
});
});
}

13
lib/promise/fetch.js Normal file
View file

@ -0,0 +1,13 @@
var fetch = require('fetch').fetchUrl;
var promise = require('promise-polyfill');
module.exports = function(link, options) {
return new promise(function(resolve, reject) {
fetch(link, options, function(error, meta, body) {
if (error) {
reject(error);
} else {
resolve({meta: meta, body: body});
}
});
});
}

8
lib/promise/fs-stat.js Normal file
View file

@ -0,0 +1,8 @@
var fs = require('fs');
var promise = require('promise-polyfill');
module.exports = function(path) {
return new promise(function(resolve, reject) {
resolve(fs.stat(path));
});
}

8
lib/promise/math-eval.js Normal file
View file

@ -0,0 +1,8 @@
var algebrite = require('algebrite');
var promise = require('promise-polyfill');
module.exports = function(expression) {
return new promise(function(resolve, reject) {
resolve(algebrite.eval(expression).toString());
});
}

18
package.json Normal file
View file

@ -0,0 +1,18 @@
{
"name": "rozbot",
"version": "0.1.0",
"description": "An IRC bot created by Brandon Rozek",
"main": "bot.js",
"dependencies": {
"cheerio": "^0.19.0",
"feed-read": "^0.0.1",
"fetch": "^1.0.0",
"algebrite": "^0.2.20",
"promise-polyfill": "^2.1.4"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Brandon Rozek"
}