From e2d03753106ac80efe4ce562be4dff1a4086e2da Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 10 Apr 2015 10:14:08 -0400 Subject: [PATCH] tweaks --- lib/cytubebot.js | 2 +- lib/database.js | 582 +++++++++++++------------- lib/utils.js | 1036 +++++++++++++++++++++++----------------------- 3 files changed, 810 insertions(+), 810 deletions(-) diff --git a/lib/cytubebot.js b/lib/cytubebot.js index 1e63ece..a66810e 100644 --- a/lib/cytubebot.js +++ b/lib/cytubebot.js @@ -463,7 +463,7 @@ CytubeBot.prototype.getQuote = function(nick) { // server - The input from config.json CytubeBot.prototype.getSocketURL = function(server) { var bot = this - var defaultReg = new RegEx("(https?:\/\/)?(.*:\d*)") + var defaultReg = /(https?:\/\/)?(.*:\d*)/ if (server.match(defaultReg)) { this.logger.syslog.log("!~~~! Found socketIO info in config") diff --git a/lib/database.js b/lib/database.js index 6645e15..c0edd67 100644 --- a/lib/database.js +++ b/lib/database.js @@ -4,44 +4,44 @@ var async = require("async") module.exports = { init: function(logger, maxVideoLength) { - var db = new Database(logger, maxVideoLength) - return db - } + var db = new Database(logger, maxVideoLength) + return db + } } function Database(logger, maxVideoLength) { - this.db = new sqlite3.Database("./cytubebot.db") - this.logger = logger - this.maxVideoLength = maxVideoLength - this.createTables() + this.db = new sqlite3.Database("./cytubebot.db") + this.logger = logger + this.maxVideoLength = maxVideoLength + this.createTables() } // Creates the tables if they do not exist Database.prototype.createTables = function() { - this.db.serialize() - this.db.run("CREATE TABLE IF NOT EXISTS users(uname TEXT, blacklisted TEXT, block TEXT, primary key(uname))") - this.db.run("CREATE TABLE IF NOT EXISTS chat(timestamp INTEGER, username TEXT, msg TEXT, channel TEXT)") - this.db.run("CREATE TABLE IF NOT EXISTS " + - "videos(type TEXT, id TEXT, duration_ms INTEGER, title TEXT, flags INTEGER, primary key(type, id))") - this.db.run("CREATE TABLE IF NOT EXISTS video_stats(type TEXT, id TEXT, uname TEXT)") - this.db.run("CREATE TABLE IF NOT EXISTS user_count(timestamp INTEGER, count INTEGER, primary key(timestamp, count))") - this.db.run("CREATE TABLE IF NOT EXISTS version(key TEXT, value TEXT, PRIMARY KEY(key))") - - this.updateTables() + this.db.serialize() + this.db.run("CREATE TABLE IF NOT EXISTS users(uname TEXT, blacklisted TEXT, block TEXT, primary key(uname))") + this.db.run("CREATE TABLE IF NOT EXISTS chat(timestamp INTEGER, username TEXT, msg TEXT, channel TEXT)") + this.db.run("CREATE TABLE IF NOT EXISTS " + + "videos(type TEXT, id TEXT, duration_ms INTEGER, title TEXT, flags INTEGER, primary key(type, id))") + this.db.run("CREATE TABLE IF NOT EXISTS video_stats(type TEXT, id TEXT, uname TEXT)") + this.db.run("CREATE TABLE IF NOT EXISTS user_count(timestamp INTEGER, count INTEGER, primary key(timestamp, count))") + this.db.run("CREATE TABLE IF NOT EXISTS version(key TEXT, value TEXT, PRIMARY KEY(key))") + + this.updateTables() }; // Updates the tables as needed Database.prototype.updateTables = function() { - var self = this - this.getVersion(function(version) { - if (!version) { - var update = self.db.prepare("INSERT INTO version(key, value) VALUES (?, ?)", ['dbversion', '1']) - update.run(function() { - self.db.run("ALTER TABLE users ADD rank INTEGER") - self.db.parallelize() - }) - } - }) + var self = this + this.getVersion(function(version) { + if (!version) { + var update = self.db.prepare("INSERT INTO version(key, value) VALUES (?, ?)", ['dbversion', '1']) + update.run(function() { + self.db.run("ALTER TABLE users ADD rank INTEGER") + self.db.parallelize() + }) + } + }) }; // Sets a flag on a video @@ -50,12 +50,12 @@ Database.prototype.updateTables = function() { // flags - The flag, should be 1 // title - Title of the video Database.prototype.flagVideo = function(type, id, flags, title) { - this.logger.syslog.log("*** Flagging video: " + title + " with flag: " + flags) + this.logger.syslog.log("*** Flagging video: " + title + " with flag: " + flags) - var stmt = this.db.prepare("UPDATE videos SET flags = ? WHERE type = ? AND id = ?", [flags, type, id]) - stmt.run() + var stmt = this.db.prepare("UPDATE videos SET flags = ? WHERE type = ? AND id = ?", [flags, type, id]) + stmt.run() - stmt.finalize() + stmt.finalize() }; // WARNING - This is experimental @@ -67,49 +67,49 @@ Database.prototype.flagVideo = function(type, id, flags, title) { // callback - The callback function, sends a chatMsg with how many videos // we deleted Database.prototype.deleteVideos = function(like, callback) { - var db = this - this.logger.syslog.log("*** Deleting videos where title like " + like) - var before = 0 - var after = 0 - var videoIds = {} - - var getAfter = function() { - db.getVideosCount(function(num) { - after = num - callback(before - after) - }) - } - - var deleteVideos = function() { - for (var i = 0; i < videoIds.length; i++) { - var stmt1 = db.db.prepare("DELETE FROM videos WHERE id = ? " + - "AND type = ?", [videoIds[i]["id"], videoIds[i]["type"]]) - var stmt2 = db.db.prepare("DELETE FROM video_stats WHERE id = ? AND type = ?", [videoIds[i]["id"], videoIds[i]["type"]]) - - stmt1.run() - stmt2.run() - } - getAfter() - } - - var getVideoIds = function() { - db.db.all("SELECT id, type FROM videos WHERE title LIKE ? AND flags = 0", (like), function(err, rows) { - if (err) - return - videoIds = rows - deleteVideos() - }) - } - - var start = function() { - db.getVideosCount(function(num) { - before = num - getVideoIds() - }) - } - - // Lets get on the ride - this.db.serialize(start()) + var db = this + this.logger.syslog.log("*** Deleting videos where title like " + like) + var before = 0 + var after = 0 + var videoIds = {} + + var getAfter = function() { + db.getVideosCount(function(num) { + after = num + callback(before - after) + }) + } + + var deleteVideos = function() { + for (var i = 0; i < videoIds.length; i++) { + var stmt1 = db.db.prepare("DELETE FROM videos WHERE id = ? " + + "AND type = ?", [videoIds[i]["id"], videoIds[i]["type"]]) + var stmt2 = db.db.prepare("DELETE FROM video_stats WHERE id = ? AND type = ?", [videoIds[i]["id"], videoIds[i]["type"]]) + + stmt1.run() + stmt2.run() + } + getAfter() + } + + var getVideoIds = function() { + db.db.all("SELECT id, type FROM videos WHERE title LIKE ? AND flags = 0", (like), function(err, rows) { + if (err) + return + videoIds = rows + deleteVideos() + }) + } + + var start = function() { + db.getVideosCount(function(num) { + before = num + getVideoIds() + }) + } + + // Lets get on the ride + this.db.serialize(start) }; // Inserts a chatMsg into the chat table @@ -118,10 +118,10 @@ Database.prototype.deleteVideos = function(like, callback) { // nick - The user who said it // room - The room in which it was said Database.prototype.insertChat = function(msg, time, nick, room) { - var stmt = this.db.prepare("INSERT INTO chat VALUES(?, ?, ?, ?)", [time, nick, msg, room]) - stmt.run() + var stmt = this.db.prepare("INSERT INTO chat VALUES(?, ?, ?, ?)", [time, nick, msg, room]) + stmt.run() - stmt.finalize() + stmt.finalize() }; // Inserts a video into the database @@ -131,29 +131,29 @@ Database.prototype.insertChat = function(msg, time, nick, room) { // dur - The duration of the video // nick - The user who added the video Database.prototype.insertVideo = function(site, vid, title, dur, nick) { - this.logger.syslog.log("*** Inserting: " + title + " into the database") + this.logger.syslog.log("*** Inserting: " + title + " into the database") - var stmt1 = this.db.prepare("INSERT OR IGNORE INTO videos VALUES(?, ?, ?, ?, ?)", [site, vid, dur * 1000, title, 0]) - var stmt2 = this.db.prepare("INSERT INTO video_stats VALUES(?, ?, ?)", [site, vid, nick]) + var stmt1 = this.db.prepare("INSERT OR IGNORE INTO videos VALUES(?, ?, ?, ?, ?)", [site, vid, dur * 1000, title, 0]) + var stmt2 = this.db.prepare("INSERT INTO video_stats VALUES(?, ?, ?)", [site, vid, nick]) - stmt1.run() - stmt1.finalize() + stmt1.run() + stmt1.finalize() - stmt2.run() - stmt2.finalize() + stmt2.run() + stmt2.finalize() }; // Inserts a user into the user table // username - The user we are adding // rank - The users rank Database.prototype.insertUser = function(username, rank) { - if (!username) - return + if (!username) + return - var stmt = this.db.prepare("INSERT OR IGNORE INTO users VALUES (?, 'false', 'false', ?)", [username, rank]) - stmt.run() + var stmt = this.db.prepare("INSERT OR IGNORE INTO users VALUES (?, 'false', 'false', ?)", [username, rank]) + stmt.run() - stmt.finalize() + stmt.finalize() }; // Sets the blacklisted flag on the user table @@ -161,186 +161,186 @@ Database.prototype.insertUser = function(username, rank) { // flag - The flag to set // callback - The callback function Database.prototype.insertUserBlacklist = function(username, flag, callback) { - this.logger.syslog.log("Setting blacklist: " + flag + " on user: " + username) + this.logger.syslog.log("Setting blacklist: " + flag + " on user: " + username) - var stmt = this.db.prepare("UPDATE users SET blacklisted = ? WHERE uname = ?", [flag, username]) - stmt.run(callback) + var stmt = this.db.prepare("UPDATE users SET blacklisted = ? WHERE uname = ?", [flag, username]) + stmt.run(callback) }; // Sets the block column of user // user - The user // flag - The value Database.prototype.insertUserBlock = function(username, flag, callback) { - this.logger.syslog.log("*** Setting block: " + flag + " on user: " + username) - var stmt = this.db.prepare("UPDATE users SET block = ? WHERE uname = ?", [flag, username]) + this.logger.syslog.log("*** Setting block: " + flag + " on user: " + username) + var stmt = this.db.prepare("UPDATE users SET block = ? WHERE uname = ?", [flag, username]) - stmt.run(callback) + stmt.run(callback) }; // Handles changes to a user's rank // user - The user whose rank we are changing // rank - The rank to set Database.prototype.insertUserRank = function(username, rank) { - var stmt = this.db.prepare("UPDATE users SET rank = ? WHERE uname = ?", [rank, username]) - stmt.run() + var stmt = this.db.prepare("UPDATE users SET rank = ? WHERE uname = ?", [rank, username]) + stmt.run() }; // Inserts the usercount, from a usercount frame // count - The number of users at timestamp // timestamp - The time the frame was sent Database.prototype.insertUsercount = function(count, timestamp) { - var stmt = this.db.prepare("INSERT INTO user_count VALUES(?, ?)", [timestamp, count]) - stmt.run() + var stmt = this.db.prepare("INSERT INTO user_count VALUES(?, ?)", [timestamp, count]) + stmt.run() }; // Gets all the users with a blacklist // callback - The callback function Database.prototype.getAllBlacklistedUsers = function(callback) { - var stmt = this.db.prepare("SELECT uname FROM users WHERE blacklisted = '1'") - var users = [] - - stmt.all(function(err, rows) { - if (rows) { - for (var i = 0; i < rows.length; i++) { - users.push(rows[i]["uname"]) - } - callback(users) - } - }) + var stmt = this.db.prepare("SELECT uname FROM users WHERE blacklisted = '1'") + var users = [] + + stmt.all(function(err, rows) { + if (rows) { + for (var i = 0; i < rows.length; i++) { + users.push(rows[i]["uname"]) + } + callback(users) + } + }) }; // Gets all the blocked users Database.prototype.getAllBlockedUsers = function(callback) { - var stmt = this.db.prepare("SELECT uname FROM users WHERE block = '1'") - var users = [] - - stmt.all(function(err, rows) { - if (rows) { - for (var i = 0; i < rows.length; i++) { - users.push(rows[i]["uname"]) - } - callback(users) - } - }) + var stmt = this.db.prepare("SELECT uname FROM users WHERE block = '1'") + var users = [] + + stmt.all(function(err, rows) { + if (rows) { + for (var i = 0; i < rows.length; i++) { + users.push(rows[i]["uname"]) + } + callback(users) + } + }) }; // Gets the usercounts for the average users chart // Basically ported from naoko // callback - The callback function Database.prototype.getAverageUsers = function(callback) { - var select_cls = "SELECT STRFTIME('%s', STRFTIME('%Y-%m-%dT%H:00', timestamp/1000, 'UNIXEPOCH'))*1000 AS timestamp," + - " CAST(ROUND(AVG(count)) AS INTEGER) AS count FROM user_count " - var group_cls = " GROUP BY STRFTIME('%Y%m%d%H', timestamp/1000, 'UNIXEPOCH')" - var sql = select_cls + group_cls - - var stmt = this.db.prepare(sql) - var returnData = [] - - stmt.all(function(err, rows) { - if (err) - return - - // Format data for google charts - for (var i = 0; i < rows.length; i++) { - returnData.push([rows[i]["timestamp"], rows[i]["count"]]) - } - callback(null, returnData) - }) + var select_cls = "SELECT STRFTIME('%s', STRFTIME('%Y-%m-%dT%H:00', timestamp/1000, 'UNIXEPOCH'))*1000 AS timestamp," + + " CAST(ROUND(AVG(count)) AS INTEGER) AS count FROM user_count " + var group_cls = " GROUP BY STRFTIME('%Y%m%d%H', timestamp/1000, 'UNIXEPOCH')" + var sql = select_cls + group_cls + + var stmt = this.db.prepare(sql) + var returnData = [] + + stmt.all(function(err, rows) { + if (err) + return + + // Format data for google charts + for (var i = 0; i < rows.length; i++) { + returnData.push([rows[i]["timestamp"], rows[i]["count"]]) + } + callback(null, returnData) + }) }; // Gets the amount of messages by each user // Used for the chat stats chart // callback - The callback function Database.prototype.getChatStats = function(callback) { - var select_cls = "SELECT username, count(*) as count FROM chat " - var group_cls = " GROUP BY username ORDER BY count(*) DESC" - var sql = select_cls + group_cls - var stmt = this.db.prepare(sql) - var returnData = [] - - stmt.all(function(err, rows) { - if (err) - return - - // Format data for google charts - for (var i = 0; i < rows.length; i++) { - if (rows[i]["username"] !== "") - returnData.push([rows[i]["username"], rows[i]["count"]]) - } - callback(null, returnData) - }) + var select_cls = "SELECT username, count(*) as count FROM chat " + var group_cls = " GROUP BY username ORDER BY count(*) DESC" + var sql = select_cls + group_cls + var stmt = this.db.prepare(sql) + var returnData = [] + + stmt.all(function(err, rows) { + if (err) + return + + // Format data for google charts + for (var i = 0; i < rows.length; i++) { + if (rows[i]["username"] !== "") + returnData.push([rows[i]["username"], rows[i]["count"]]) + } + callback(null, returnData) + }) }; // Does ANALYZE on the database // Used to get the counts of videos, users, and chat // callback - The callback function Database.prototype.getGeneralStats = function(callback) { - var self = this - var stmt = "ANALYZE" - var stmt2 = "SELECT stat FROM sqlite_stat1 WHERE tbl = 'users' OR tbl = 'videos' OR tbl = 'chat'" - - this.db.serialize(function() { - self.db.run(stmt) - self.db.all(stmt2, function(err, rows) { - if (rows) - callback(rows) - }) - }) + var self = this + var stmt = "ANALYZE" + var stmt2 = "SELECT stat FROM sqlite_stat1 WHERE tbl = 'users' OR tbl = 'videos' OR tbl = 'chat'" + + this.db.serialize(function() { + self.db.run(stmt) + self.db.all(stmt2, function(err, rows) { + if (rows) + callback(rows) + }) + }) }; // Gets the 10 most popular videos // Used for the popular videos chart // callback - The callback function Database.prototype.getPopularVideos = function(callback) { - var select_cls = "SELECT videos.type, videos.id, videos.title, videos.flags & 1, count(*) AS count FROM videos, video_stats" - var where_cls = " WHERE video_stats.type = videos.type AND video_stats.id = videos.id AND NOT videos.flags & 2 " - var group_cls = " GROUP BY videos.type, videos.id ORDER BY count(*) DESC LIMIT 10" - var sql = select_cls + where_cls + group_cls - - var stmt = this.db.prepare(sql) - - var returnData = [] - - stmt.all(function(err, rows) { - if (err) - return - - // Format data for google charts - for (var i = 0; i < rows.length; i++) { - returnData.push([rows[i]["type"], rows[i]["id"], rows[i]["title"], - rows[i]["flags"], rows[i]["count"] - ]) - } - callback(null, returnData) - }) + var select_cls = "SELECT videos.type, videos.id, videos.title, videos.flags & 1, count(*) AS count FROM videos, video_stats" + var where_cls = " WHERE video_stats.type = videos.type AND video_stats.id = videos.id AND NOT videos.flags & 2 " + var group_cls = " GROUP BY videos.type, videos.id ORDER BY count(*) DESC LIMIT 10" + var sql = select_cls + where_cls + group_cls + + var stmt = this.db.prepare(sql) + + var returnData = [] + + stmt.all(function(err, rows) { + if (err) + return + + // Format data for google charts + for (var i = 0; i < rows.length; i++) { + returnData.push([rows[i]["type"], rows[i]["id"], rows[i]["title"], + rows[i]["flags"], rows[i]["count"] + ]) + } + callback(null, returnData) + }) }; // Gets a chat message // If nick is given, it will select a quote from that user // If no nick is given, it will select a random quote // nick - The username we are getting a quote for -// callback - The callback function +// callback - The callback function Database.prototype.getQuote = function(nick, callback) { - nick = nick.split(" ")[0] - var stmt = {} - - if (nick) { - stmt = this.db.prepare("SELECT username, msg, timestamp FROM chat WHERE " + - "username = ? COLLATE NOCASE ORDER BY RANDOM() LIMIT 1", [nick]) - - stmt.get(function(err, row) { - if (row) - return callback(row) - }) - return callback(0) - } - - stmt = "SELECT username, msg, timestamp FROM chat WHERE msg NOT LIKE '/me%' " + - "AND msg NOT LIKE '$%' ORDER BY RANDOM() LIMIT 1" - this.db.get(stmt, function(err, row) { - if (row) - callback(row) - }) + nick = nick.split(" ")[0] + var stmt = {} + + if (nick) { + stmt = this.db.prepare("SELECT username, msg, timestamp FROM chat WHERE " + + "username = ? COLLATE NOCASE ORDER BY RANDOM() LIMIT 1", [nick]) + + stmt.get(function(err, row) { + if (row) + return callback(row) + }) + return callback(0) + } + + stmt = "SELECT username, msg, timestamp FROM chat WHERE msg NOT LIKE '/me%' " + + "AND msg NOT LIKE '$%' ORDER BY RANDOM() LIMIT 1" + this.db.get(stmt, function(err, row) { + if (row) + callback(row) + }) }; @@ -350,70 +350,70 @@ Database.prototype.getQuote = function(nick, callback) { // room - The room the bot is currently in // callback - The callback function Database.prototype.getStats = function(room, callback) { - var self = this - - // Lets go on another ride - async.parallel({ - userVideoStats: self.getVideoStats.bind(self), - userChatStats: self.getChatStats.bind(self), - popularVideos: self.getPopularVideos.bind(self), - averageUsers: self.getAverageUsers.bind(self) - }, function(err, results) { - if (err) - return - - results["room"] = room - callback(results) - }) + var self = this + + // Lets go on another ride + async.parallel({ + userVideoStats: self.getVideoStats.bind(self), + userChatStats: self.getChatStats.bind(self), + popularVideos: self.getPopularVideos.bind(self), + averageUsers: self.getAverageUsers.bind(self) + }, function(err, results) { + if (err) + return + + results["room"] = room + callback(results) + }) }; // Checks whether a user is blacklisted // username - The user we are checking // callback - The callback function Database.prototype.getUserBlacklist = function(username, callback) { - var stmt = this.db.prepare("SELECT blacklisted FROM users WHERE uname = ?", [username]) + var stmt = this.db.prepare("SELECT blacklisted FROM users WHERE uname = ?", [username]) - stmt.get(function(err, row) { - if (typeof row !== "undefined") { - callback(row["blacklisted"]) - } - }) + stmt.get(function(err, row) { + if (typeof row !== "undefined") { + callback(row["blacklisted"]) + } + }) }; // Selects the autodelete column for user // username - The user we are looking up // callback - Callback function Database.prototype.getUserBlock = function(username, callback) { - var stmt = this.db.prepare("SELECT block FROM users WHERE uname = ?", [username]) + var stmt = this.db.prepare("SELECT block FROM users WHERE uname = ?", [username]) - stmt.get(function(err, row) { - if (typeof row !== "undefined") { - callback(row["block"]) - } - }) + stmt.get(function(err, row) { + if (typeof row !== "undefined") { + callback(row["block"]) + } + }) }; // Gets a user's rank // Callback - callback function Database.prototype.getUserRank = function(username, callback) { - var stmt = this.db.prepare("SELECT rank FROM users WHERE uname = ?", [username]) + var stmt = this.db.prepare("SELECT rank FROM users WHERE uname = ?", [username]) - stmt.get(function(err, row) { - if (typeof row !== "undefined") - callback(row["rank"]) - }) + stmt.get(function(err, row) { + if (typeof row !== "undefined") + callback(row["rank"]) + }) }; // Gets the database version Database.prototype.getVersion = function(callback) { - var stmt = this.db.prepare("SELECT value FROM version WHERE key = 'dbversion'") - - stmt.get(function(err, row) { - if (row === undefined) - callback(null) - else - callback(row) - }) + var stmt = this.db.prepare("SELECT value FROM version WHERE key = 'dbversion'") + + stmt.get(function(err, row) { + if (row === undefined) + callback(null) + else + callback(row) + }) }; // Used by the addRandom() method @@ -422,54 +422,54 @@ Database.prototype.getVersion = function(callback) { // num - The number of videos we are getting // callback - The callback function Database.prototype.getVideos = function(num, callback) { - if (!num) - num = 1 + if (!num) + num = 1 - var stmt = this.db.prepare("SELECT type, id, duration_ms FROM videos " + - "WHERE flags = 0 AND duration_ms < ? AND (type = 'yt' OR type = 'dm' OR type = 'vm') " + - "ORDER BY RANDOM() LIMIT ?", [this.maxVideoLength, num]) + var stmt = this.db.prepare("SELECT type, id, duration_ms FROM videos " + + "WHERE flags = 0 AND duration_ms < ? AND (type = 'yt' OR type = 'dm' OR type = 'vm') " + + "ORDER BY RANDOM() LIMIT ?", [this.maxVideoLength, num]) - stmt.all(function(err, rows) { - callback(rows) - }) + stmt.all(function(err, rows) { + callback(rows) + }) }; // Gets the number of videos in the database // callback - The callback function Database.prototype.getVideosCount = function(callback) { - var self = this + var self = this - this.db.get("SELECT count(*) AS count FROM videos", function(err, row) { - if (err) - return self.logger.errlog.log(err) + this.db.get("SELECT count(*) AS count FROM videos", function(err, row) { + if (err) + return self.logger.errlog.log(err) - callback(row["count"]) - }) + callback(row["count"]) + }) }; // Gets the number of videos added by each user // Used by the video by user chart // callback - The callback function Database.prototype.getVideoStats = function(callback) { - var select_cls = "SELECT uname, count(*) AS count FROM video_stats vs, videos v " - var where_cls = " WHERE vs.type = v.type AND vs.id = v.id AND NOT v.flags & 2 " - var group_cls = " GROUP BY uname ORDER BY count(*) DESC" - var sql = select_cls + where_cls + group_cls - var stmt = this.db.prepare(sql) - var returnData = [] - - stmt.all(function(err, rows) { - if (err) - return - - // Format data for google charts - for (var i = 0; i < rows.length; i++) { - if (rows[i]["uname"] !== "") - returnData.push([rows[i]["uname"], rows[i]["count"]]) - } - - callback(null, returnData) - }) + var select_cls = "SELECT uname, count(*) AS count FROM video_stats vs, videos v " + var where_cls = " WHERE vs.type = v.type AND vs.id = v.id AND NOT v.flags & 2 " + var group_cls = " GROUP BY uname ORDER BY count(*) DESC" + var sql = select_cls + where_cls + group_cls + var stmt = this.db.prepare(sql) + var returnData = [] + + stmt.all(function(err, rows) { + if (err) + return + + // Format data for google charts + for (var i = 0; i < rows.length; i++) { + if (rows[i]["uname"] !== "") + returnData.push([rows[i]["uname"], rows[i]["count"]]) + } + + callback(null, returnData) + }) }; // Gets the flag of a video @@ -477,12 +477,12 @@ Database.prototype.getVideoStats = function(callback) { // id - The ID of the video we are looking up // callback - The callback function Database.prototype.getVideoFlag = function(type, id, callback) { - var stmt = this.db.prepare("SELECT flags FROM videos videos WHERE type = ? AND id = ?", [type, id]) - - stmt.get(function(err, row) { - if (row) - callback(row) - else - callback(0) - }) -}; \ No newline at end of file + var stmt = this.db.prepare("SELECT flags FROM videos videos WHERE type = ? AND id = ?", [type, id]) + + stmt.get(function(err, row) { + if (row) + callback(row) + else + callback(0) + }) +}; diff --git a/lib/utils.js b/lib/utils.js index 35cd6aa..59afbc4 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,526 +1,526 @@ var utils = { - // Checks to see if a user is in the userlist - // Returns true if it is, or false if it isn't - // bot - Reference to the bot - // user - User to find - "userInUserlist": function(bot, user) { - for (var u in bot.userlist) { - if (bot.userlist[u]["name"] === user) - return true - } - return false - }, - - // Looks for user, returning the user index - // bot - Reference to the bot - // user - User to find - "findUser": function(bot, user) { - for (var u in bot.userlist) { - if (bot.userlist[u]["name"].toLowerCase() === user.toLowerCase()) - return u - } - }, - - // Looks for user, returning the user object - // bot - Reference to the bot - // user - User to find - "getUser": function(bot, user) { - for (var u in bot.userlist) { - if (bot.userlist[u]["name"].toLowerCase() === user.toLowerCase()) - return bot.userlist[u] - } - }, - - // Checks if the video is on the playlist - // Returns true if it is, false if it isn't - // bot - Reference to the bot - // video - The video to look for - "isOnPlaylist": function(bot, video) { - for (var i = 0; i < bot.playlist.length; i++) { - if (bot.playlist[i]["media"]["id"] === video["item"]["media"]["id"]) { - return true - } - } - }, - - // Finds the video from a UID - // Returns the object if we find it - // bot - Reference to the bot - // uid - UID of the video we are looking for - "getVideoFromUID": function(bot, uid) { - for (var i = 0; i < bot.playlist.length; i++) { - if (bot.playlist[i]["uid"] === uid) - return bot.playlist[i] - } - }, - - // Finds the index(s) of a video using a video object - // Compares using the ids - // Returns an array containing indices and the uid - // bot - Reference to the bot - "findIndexOfVideoFromVideo": function(bot, video) { - var returnData = [] - for (var i = 0; i < bot.playlist.length; i++) { - var vid = { - "uid": 0, - "index": 0 - } - if (bot.playlist[i]["media"]["id"] === video["media"]["id"]) { - vid["uid"] = bot.playlist[i]["uid"] - vid["index"] = i - returnData.push(vid) - } - } - return returnData - }, - - // Finds the index of a video using the UID - // Returns the index - // bot - Reference to the bot - // uid - UID of the video we are looking for - "findIndexOfVideoFromUID": function(bot, uid) { - for (var i = 0; i < bot.playlist.length; i++) { - if (bot.playlist[i]["uid"] === uid) - return i - } - }, - - // Finds all videos added by a user - // Returns an array of UIDs - // bot - Reference to the bot - // name - The name of the user we are finding videos for - "findVideosAddedByUser": function(bot, name) { - if (!name) - return - var returnUIDs = [] - for (var i = 0; i < bot.playlist.length; i++) { - if (bot.playlist[i]["queueby"].toLowerCase() === name.toLowerCase()) - returnUIDs.push(bot.playlist[i]["uid"]) - } - return returnUIDs - }, - - // Finds all videos that match title - // Returns a list of uids - // bot - Reference to the bot - // title - The title we are trying to match - "findVideosFromTitle": function(bot, title) { - if (!title) - return [] - - RegExEsc = function(str) { - return String(str).replace(/[\\\[\].()|{}$+*?!:^,#<-]/g, '\\$&').replace(/\x08/g, '\\x08'); - }; - - title = ".*" + RegExEsc(title) + ".*" - var returnUIDs = [] - var reg = new RegExp(title, "ig") - for (var i = 0; i < bot.playlist.length; i++) { - if (bot.playlist[i]["media"]["title"].match(reg)) - returnUIDs.push(bot.playlist[i]["uid"]) - } - return returnUIDs - }, - - // Filters an incoming chatMsg - // or database quote of HTML entities and htmltags - // bot - Reference to the bot - // msg - The message to filter - "filterMsg": function(bot, msg) { - msg = msg.replace(/'/g, "'") - msg = msg.replace(/&/g, "&") - msg = msg.replace(/</g, "<") - msg = msg.replace(/>/g, ">") - msg = msg.replace(/"/g, "\"") - msg = msg.replace(/(/g, "\(") - msg = msg.replace(/)/g, "\)") - msg = msg.replace(/(<([^>]+)>)/ig, "") - msg = msg.replace(/^[ \t]+/g, "") - - return msg - }, - - // Generic loop for uids - // bot - Reference to the bot - // data - Meant to be an object with members: - // kind - The function we want to use. eg sendMoveMedia - // num: The number or "all" - // uids: The uids of the videos - "genericUIDLoop": function(bot, data) { - if (!data) - return - - var kind = data["kind"] - var num = data["num"] - var uids = data["uids"] - - if (!bot[kind]) - return bot.logger.errlog.log("!~~~! genericUIDLoop No such method: " + kind) - - if (!num) { - // We should use the first uid - bot[kind](uids[0]) - } else if (num === "all") { - // We should use all the uids - for (var i = 0; i < uids.length; i++) { - bot[kind](uids[i]) - } - } else { - // We should use num uids - for (var i = 0; i < num; i++) { - if (i > uids.length) - break - bot[kind](uids[i]) - } - } - }, - - // Used by $bump - // Used to determine what to bump - // Returns an object containing the number to bump and the uids - // bot - Reference to the bot - // bumpData - The data from bump in chatcommands - "parseBumpData": function(bot, bumpData) { - if (!bumpData) - return bot.sendChatMsg("Incorrect format") - - var splitData = bumpData.split(" ") - - var bumpKind = splitData.splice(0, 1)[0] - var bumpAmount = splitData[splitData.length - 1] - var num = 0 - var uids = [] - - if (bumpAmount) { - if (bumpAmount.toLowerCase() === "all") { - num = "all" - splitData.splice(splitData.length - 1, 1) - } else if (!isNaN(parseInt(bumpAmount))) { - num = bumpAmount - splitData.splice(splitData.length - 1, 1) - } - } - - // We don't have enough info to continue - if (splitData.length === 0 || !splitData[0]) - return bot.sendChatMsg("Incorrect format") - - if (bumpKind === "-user") - uids = utils.findVideosAddedByUser(bot, splitData[0]).reverse() - else if (bumpKind === "-title") - uids = utils.findVideosFromTitle(bot, splitData.join(" ")).reverse() - - return { - kind: "sendMoveMedia", - num: num, - uids: uids - } - }, - - // Used by $delete - // Parses the data given to delete - // Returns an object containing items needed for - // the generic uid loop - // bot - Reference to the bot - // deleteData - The data from $delete - "parseDeleteData": function(bot, deleteData) { - var userData = deleteData["userData"].split(" ") - var name = "" - var num = 0 - - // If delete is called with a number or no args, - // we assume the caller wants to delete their own videos - if (!userData || userData.length === 1) { - if (userData[0] && !isNaN(parseInt(userData[0])) || userData[0] && userData[0] === "all") { - name = deleteData["username"] - num = userData[0] - } else if (userData[0] && isNaN(parseInt(userData[0]))) { - name = userData[0] - } else { - name = deleteData["username"] - } - } else { - name = userData[0] - num = userData[userData.length - 1] - } - - var uids = utils.findVideosAddedByUser(bot, name) - - if (!num) - num = 1 - else if (num.toLowerCase() === "all") - num = uids.length - - var returnData = { - kind: "deleteVideo", - name: name, - num: num, - uids: uids.reverse() - } - - return returnData - }, - - // Parses a link from $add - // Used to send queue frames via addVideo - // bot - Reference to the bot - // url - the URL of the video we are going to parse - "parseMediaLink": function(bot, url) { - if (typeof url != "string") { - return { - id: null, - type: null - } - } - url = url.trim() - - // JWPlayer - if (url.indexOf("jw:") === 0) { - return { - id: url.substring(3), - type: "jw" - } - } - - // RTMP server - if (url.indexOf("rtmp://") === 0) { - return { - id: url, - type: "rt" - } - } - - var m - // YouTube - if ((m = url.match(/youtube\.com\/watch\?v=([^&#]+)/))) { - return { - id: m[1], - type: "yt" - } - } - - // Short YouTube link - if ((m = url.match(/youtu\.be\/([^&#]+)/))) { - return { - id: m[1], - type: "yt" - } - } - - // YouTube playlist - if ((m = url.match(/youtube\.com\/playlist\?list=([^&#]+)/))) { - return { - id: m[1], - type: "yp" - } - } - - // Twitch.tv - if ((m = url.match(/twitch\.tv\/([^&#]+)/))) { - return { - id: m[1], - type: "tw" - } - } - - // Justin.tv - if ((m = url.match(/justin\.tv\/([^&#]+)/))) { - return { - id: m[1], - type: "jt" - } - } - - // livestream.com - if ((m = url.match(/livestream\.com\/([^&#]+)/))) { - return { - id: m[1], - type: "li" - } - } - - // ustream.tv - if ((m = url.match(/ustream\.tv\/([^&#]+)/))) { - return { - id: m[1], - type: "us" - } - } - - // Vimeo.com - if ((m = url.match(/vimeo\.com\/([^&#]+)/))) { - return { - id: m[1], - type: "vi" - } - } - - // dailymotion.com - if ((m = url.match(/dailymotion\.com\/video\/([^&#]+)/))) { - return { - id: m[1], - type: "dm" - } - } - - // imgur.com - // Because people actually use this (not) - if ((m = url.match(/imgur\.com\/a\/([^&#]+)/))) { - return { - id: m[1], - type: "im" - } - } - - // soundcloud.com - if ((m = url.match(/soundcloud\.com\/([^&#]+)/))) { - return { - id: url, - type: "sc" - } - } - - // Google drive links - if ((m = url.match(/docs\.google\.com\/file\/d\/([^\/]*)/))) { - return { - id: m[1], - type: "gd" - } - } - - var temp = url.split("?")[0] - if (temp.match(/^http:\/\//)) { - if (temp.match(/\.(mp4|flv|webm|og[gv]|mp3|mov)$/)) { - return { - id: url, - type: "fi" - } - } - } - - return { - id: null, - type: null - } - }, - - // Used by $userlimit - // Handles changes to bot.stats.userlimit - // userlimitData - Object containing the match - // and a callback function - "parseUserlimit": function(bot, userlimitData) { - var match = userlimitData["match"] - var callback = userlimitData["callback"] - var isTrue = true - var isFalse = false - var num = 0 - - // Both params were given - if (typeof match[1] !== "undefined" && typeof match[2] !== "undefined") { - isTrue = (match[1] === "true") - isFalse = (match[1] === "false") - - num = parseInt(match[2]) - - if (isTrue) { - bot.stats["userLimit"] = isTrue - } else if (isFalse) { - bot.stats["userLimit"] = !isFalse - } - if (!isNaN(num)) - bot.stats["userLimitNum"] = num - } else if (typeof match[1] !== "undefined" && match[2] === "") { - // Boolean given - isTrue = (match[1] === "true") - isFalse = (match[1] === "false") - - if (isTrue) { - bot.stats["userLimit"] = isTrue - } else if (isFalse) { - bot.stats["userLimit"] = !isFalse - } - } else if (typeof match[0] !== "undefined") { - num = parseInt(match[0]) - if (!isNaN(num)) - bot.stats["userLimitNum"] = num - } - - return callback() - }, - - // Used by $forecast - // Parses and returns the forecast string - // bot - Reference to the bot - // forecastData - Data from the api call to weatherunderground - "parseForecastData": function(bot, forecastData) { - var parsedJSON = forecastData["json"] - var tomorrow = forecastData["tomorrow"] - var returnStrings = [] - - var forecast = { - "todayDay": parsedJSON["forecast"]["txt_forecast"]["forecastday"][0], - "todayNight": parsedJSON["forecast"]["txt_forecast"]["forecastday"][1], - "tomorrowDay": parsedJSON["forecast"]["txt_forecast"]["forecastday"][2], - "tomorrowNight": parsedJSON["forecast"]["txt_forecast"]["forecastday"][3] - } - - var location = parsedJSON["current_observation"]["display_location"]["full"] - - if (tomorrow) { - if ((location.split(", ")[1]).length != 2) { - returnStrings.push("Location: " + - location + " Tomorrow: " + - forecast["tomorrowDay"]["fcttext_metric"]) - - returnStrings.push("Tomorrow Night: " + - forecast["tomorrowNight"]["fcttext_metric"]) - } else { - returnStrings.push("Location: " + - location + " Tomorrow: " + - forecast["tomorrowDay"]["fcttext"]) - - returnStrings.push("Tomorrow Night: " + - forecast["tomorrowNight"]["fcttext"]) - } - } else { - if ((location.split(", ")[1]).length != 2) { - returnStrings.push("Location: " + - location + " Today: " + - forecast["todayDay"]["fcttext_metric"]) - - returnStrings.push("Tonight: " + - forecast["todayNight"]["fcttext_metric"]) - } else { - returnStrings.push("Location: " + - location + " Today: " + - forecast["todayDay"]["fcttext"]) - - returnStrings.push("Tonight: " + - forecast["todayNight"]["fcttext"]) - } - } - return returnStrings - }, - - // Loops through the bot's waitingFunctions - // looking for one that matches function - // fun - Contains the type of function we are looking for - "loopThroughWaiting": function(bot, fun) { - for (var i = 0; i < bot.waitingFunctions.length; i++) { - if (bot.waitingFunctions[i][fun]) { - bot.waitingFunctions[i]["fun"](function() { - bot.waitingFunctions.splice(i, 1) - }) - } - } - } + // Checks to see if a user is in the userlist + // Returns true if it is, or false if it isn't + // bot - Reference to the bot + // user - User to find + "userInUserlist": function(bot, user) { + for (var u in bot.userlist) { + if (bot.userlist[u]["name"] === user) + return true + } + return false + }, + + // Looks for user, returning the user index + // bot - Reference to the bot + // user - User to find + "findUser": function(bot, user) { + for (var u in bot.userlist) { + if (bot.userlist[u]["name"].toLowerCase() === user.toLowerCase()) + return u + } + }, + + // Looks for user, returning the user object + // bot - Reference to the bot + // user - User to find + "getUser": function(bot, user) { + for (var u in bot.userlist) { + if (bot.userlist[u]["name"].toLowerCase() === user.toLowerCase()) + return bot.userlist[u] + } + }, + + // Checks if the video is on the playlist + // Returns true if it is, false if it isn't + // bot - Reference to the bot + // video - The video to look for + "isOnPlaylist": function(bot, video) { + for (var i = 0; i < bot.playlist.length; i++) { + if (bot.playlist[i]["media"]["id"] === video["item"]["media"]["id"]) { + return true + } + } + }, + + // Finds the video from a UID + // Returns the object if we find it + // bot - Reference to the bot + // uid - UID of the video we are looking for + "getVideoFromUID": function(bot, uid) { + for (var i = 0; i < bot.playlist.length; i++) { + if (bot.playlist[i]["uid"] === uid) + return bot.playlist[i] + } + }, + + // Finds the index(s) of a video using a video object + // Compares using the ids + // Returns an array containing indices and the uid + // bot - Reference to the bot + "findIndexOfVideoFromVideo": function(bot, video) { + var returnData = [] + for (var i = 0; i < bot.playlist.length; i++) { + var vid = { + "uid": 0, + "index": 0 + } + if (bot.playlist[i]["media"]["id"] === video["media"]["id"]) { + vid["uid"] = bot.playlist[i]["uid"] + vid["index"] = i + returnData.push(vid) + } + } + return returnData + }, + + // Finds the index of a video using the UID + // Returns the index + // bot - Reference to the bot + // uid - UID of the video we are looking for + "findIndexOfVideoFromUID": function(bot, uid) { + for (var i = 0; i < bot.playlist.length; i++) { + if (bot.playlist[i]["uid"] === uid) + return i + } + }, + + // Finds all videos added by a user + // Returns an array of UIDs + // bot - Reference to the bot + // name - The name of the user we are finding videos for + "findVideosAddedByUser": function(bot, name) { + if (!name) + return + var returnUIDs = [] + for (var i = 0; i < bot.playlist.length; i++) { + if (bot.playlist[i]["queueby"].toLowerCase() === name.toLowerCase()) + returnUIDs.push(bot.playlist[i]["uid"]) + } + return returnUIDs + }, + + // Finds all videos that match title + // Returns a list of uids + // bot - Reference to the bot + // title - The title we are trying to match + "findVideosFromTitle": function(bot, title) { + if (!title) + return [] + + RegExEsc = function(str) { + return String(str).replace(/[\\\[\].()|{}$+*?!:^,#<-]/g, '\\$&').replace(/\x08/g, '\\x08') + } + + title = ".*" + RegExEsc(title) + ".*" + var returnUIDs = [] + var reg = new RegExp(title, "ig") + for (var i = 0; i < bot.playlist.length; i++) { + if (bot.playlist[i]["media"]["title"].match(reg)) + returnUIDs.push(bot.playlist[i]["uid"]) + } + return returnUIDs + }, + + // Filters an incoming chatMsg + // or database quote of HTML entities and htmltags + // bot - Reference to the bot + // msg - The message to filter + "filterMsg": function(bot, msg) { + msg = msg.replace(/'/g, "'") + msg = msg.replace(/&/g, "&") + msg = msg.replace(/</g, "<") + msg = msg.replace(/>/g, ">") + msg = msg.replace(/"/g, "\"") + msg = msg.replace(/(/g, "\(") + msg = msg.replace(/)/g, "\)") + msg = msg.replace(/(<([^>]+)>)/ig, "") + msg = msg.replace(/^[ \t]+/g, "") + + return msg + }, + + // Generic loop for uids + // bot - Reference to the bot + // data - Meant to be an object with members: + // kind - The function we want to use. eg sendMoveMedia + // num: The number or "all" + // uids: The uids of the videos + "genericUIDLoop": function(bot, data) { + if (!data) + return + + var kind = data["kind"] + var num = data["num"] + var uids = data["uids"] + + if (!bot[kind]) + return bot.logger.errlog.log("!~~~! genericUIDLoop No such method: " + kind) + + if (!num) { + // We should use the first uid + bot[kind](uids[0]) + } else if (num === "all") { + // We should use all the uids + for (var i = 0; i < uids.length; i++) { + bot[kind](uids[i]) + } + } else { + // We should use num uids + for (var i = 0; i < num; i++) { + if (i > uids.length) + break + bot[kind](uids[i]) + } + } + }, + + // Used by $bump + // Used to determine what to bump + // Returns an object containing the number to bump and the uids + // bot - Reference to the bot + // bumpData - The data from bump in chatcommands + "parseBumpData": function(bot, bumpData) { + if (!bumpData) + return bot.sendChatMsg("Incorrect format") + + var splitData = bumpData.split(" ") + + var bumpKind = splitData.splice(0, 1)[0] + var bumpAmount = splitData[splitData.length - 1] + var num = 0 + var uids = [] + + if (bumpAmount) { + if (bumpAmount.toLowerCase() === "all") { + num = "all" + splitData.splice(splitData.length - 1, 1) + } else if (!isNaN(parseInt(bumpAmount))) { + num = bumpAmount + splitData.splice(splitData.length - 1, 1) + } + } + + // We don't have enough info to continue + if (splitData.length === 0 || !splitData[0]) + return bot.sendChatMsg("Incorrect format") + + if (bumpKind === "-user") + uids = utils.findVideosAddedByUser(bot, splitData[0]).reverse() + else if (bumpKind === "-title") + uids = utils.findVideosFromTitle(bot, splitData.join(" ")).reverse() + + return { + kind: "sendMoveMedia", + num: num, + uids: uids + } + }, + + // Used by $delete + // Parses the data given to delete + // Returns an object containing items needed for + // the generic uid loop + // bot - Reference to the bot + // deleteData - The data from $delete + "parseDeleteData": function(bot, deleteData) { + var userData = deleteData["userData"].split(" ") + var name = "" + var num = 0 + + // If delete is called with a number or no args, + // we assume the caller wants to delete their own videos + if (!userData || userData.length === 1) { + if (userData[0] && !isNaN(parseInt(userData[0])) || userData[0] && userData[0] === "all") { + name = deleteData["username"] + num = userData[0] + } else if (userData[0] && isNaN(parseInt(userData[0]))) { + name = userData[0] + } else { + name = deleteData["username"] + } + } else { + name = userData[0] + num = userData[userData.length - 1] + } + + var uids = utils.findVideosAddedByUser(bot, name) + + if (!num) + num = 1 + else if (num.toLowerCase() === "all") + num = uids.length + + var returnData = { + kind: "deleteVideo", + name: name, + num: num, + uids: uids.reverse() + } + + return returnData + }, + + // Parses a link from $add + // Used to send queue frames via addVideo + // bot - Reference to the bot + // url - the URL of the video we are going to parse + "parseMediaLink": function(bot, url) { + if (typeof url != "string") { + return { + id: null, + type: null + } + } + url = url.trim() + + // JWPlayer + if (url.indexOf("jw:") === 0) { + return { + id: url.substring(3), + type: "jw" + } + } + + // RTMP server + if (url.indexOf("rtmp://") === 0) { + return { + id: url, + type: "rt" + } + } + + var m + // YouTube + if ((m = url.match(/youtube\.com\/watch\?v=([^&#]+)/))) { + return { + id: m[1], + type: "yt" + } + } + + // Short YouTube link + if ((m = url.match(/youtu\.be\/([^&#]+)/))) { + return { + id: m[1], + type: "yt" + } + } + + // YouTube playlist + if ((m = url.match(/youtube\.com\/playlist\?list=([^&#]+)/))) { + return { + id: m[1], + type: "yp" + } + } + + // Twitch.tv + if ((m = url.match(/twitch\.tv\/([^&#]+)/))) { + return { + id: m[1], + type: "tw" + } + } + + // Justin.tv + if ((m = url.match(/justin\.tv\/([^&#]+)/))) { + return { + id: m[1], + type: "jt" + } + } + + // livestream.com + if ((m = url.match(/livestream\.com\/([^&#]+)/))) { + return { + id: m[1], + type: "li" + } + } + + // ustream.tv + if ((m = url.match(/ustream\.tv\/([^&#]+)/))) { + return { + id: m[1], + type: "us" + } + } + + // Vimeo.com + if ((m = url.match(/vimeo\.com\/([^&#]+)/))) { + return { + id: m[1], + type: "vi" + } + } + + // dailymotion.com + if ((m = url.match(/dailymotion\.com\/video\/([^&#]+)/))) { + return { + id: m[1], + type: "dm" + } + } + + // imgur.com + // Because people actually use this (not) + if ((m = url.match(/imgur\.com\/a\/([^&#]+)/))) { + return { + id: m[1], + type: "im" + } + } + + // soundcloud.com + if ((m = url.match(/soundcloud\.com\/([^&#]+)/))) { + return { + id: url, + type: "sc" + } + } + + // Google drive links + if ((m = url.match(/docs\.google\.com\/file\/d\/([^\/]*)/))) { + return { + id: m[1], + type: "gd" + } + } + + var temp = url.split("?")[0] + if (temp.match(/^http:\/\//)) { + if (temp.match(/\.(mp4|flv|webm|og[gv]|mp3|mov)$/)) { + return { + id: url, + type: "fi" + } + } + } + + return { + id: null, + type: null + } + }, + + // Used by $userlimit + // Handles changes to bot.stats.userlimit + // userlimitData - Object containing the match + // and a callback function + "parseUserlimit": function(bot, userlimitData) { + var match = userlimitData["match"] + var callback = userlimitData["callback"] + var isTrue = true + var isFalse = false + var num = 0 + + // Both params were given + if (typeof match[1] !== "undefined" && typeof match[2] !== "undefined") { + isTrue = (match[1] === "true") + isFalse = (match[1] === "false") + + num = parseInt(match[2]) + + if (isTrue) { + bot.stats["userLimit"] = isTrue + } else if (isFalse) { + bot.stats["userLimit"] = !isFalse + } + if (!isNaN(num)) + bot.stats["userLimitNum"] = num + } else if (typeof match[1] !== "undefined" && match[2] === "") { + // Boolean given + isTrue = (match[1] === "true") + isFalse = (match[1] === "false") + + if (isTrue) { + bot.stats["userLimit"] = isTrue + } else if (isFalse) { + bot.stats["userLimit"] = !isFalse + } + } else if (typeof match[0] !== "undefined") { + num = parseInt(match[0]) + if (!isNaN(num)) + bot.stats["userLimitNum"] = num + } + + return callback() + }, + + // Used by $forecast + // Parses and returns the forecast string + // bot - Reference to the bot + // forecastData - Data from the api call to weatherunderground + "parseForecastData": function(bot, forecastData) { + var parsedJSON = forecastData["json"] + var tomorrow = forecastData["tomorrow"] + var returnStrings = [] + + var forecast = { + "todayDay": parsedJSON["forecast"]["txt_forecast"]["forecastday"][0], + "todayNight": parsedJSON["forecast"]["txt_forecast"]["forecastday"][1], + "tomorrowDay": parsedJSON["forecast"]["txt_forecast"]["forecastday"][2], + "tomorrowNight": parsedJSON["forecast"]["txt_forecast"]["forecastday"][3] + } + + var location = parsedJSON["current_observation"]["display_location"]["full"] + + if (tomorrow) { + if ((location.split(", ")[1]).length != 2) { + returnStrings.push("Location: " + + location + " Tomorrow: " + + forecast["tomorrowDay"]["fcttext_metric"]) + + returnStrings.push("Tomorrow Night: " + + forecast["tomorrowNight"]["fcttext_metric"]) + } else { + returnStrings.push("Location: " + + location + " Tomorrow: " + + forecast["tomorrowDay"]["fcttext"]) + + returnStrings.push("Tomorrow Night: " + + forecast["tomorrowNight"]["fcttext"]) + } + } else { + if ((location.split(", ")[1]).length != 2) { + returnStrings.push("Location: " + + location + " Today: " + + forecast["todayDay"]["fcttext_metric"]) + + returnStrings.push("Tonight: " + + forecast["todayNight"]["fcttext_metric"]) + } else { + returnStrings.push("Location: " + + location + " Today: " + + forecast["todayDay"]["fcttext"]) + + returnStrings.push("Tonight: " + + forecast["todayNight"]["fcttext"]) + } + } + return returnStrings + }, + + // Loops through the bot's waitingFunctions + // looking for one that matches function + // fun - Contains the type of function we are looking for + "loopThroughWaiting": function(bot, fun) { + for (var i = 0; i < bot.waitingFunctions.length; i++) { + if (bot.waitingFunctions[i][fun]) { + bot.waitingFunctions[i]["fun"](function() { + bot.waitingFunctions.splice(i, 1) + }) + } + } + } } // Matches the command with a function function handle(bot, command, data) { - if (command in utils) - return utils[command](bot, data) + if (command in utils) + return utils[command](bot, data) } -exports.handle = handle \ No newline at end of file +exports.handle = handle