Last active
February 20, 2019 11:34
-
-
Save LunaSquee/95e849c9d44a4874501f to your computer and use it in GitHub Desktop.
nBot Plugin of Squeebot.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
'use strict'; | |
// IRC bot by LunaSquee (Originally djazz, best poni :3) | |
// This is a plugin for nBot (https://git.mindcraft.si.eu.org/?p=nBot.git) | |
// Before using: npm install gamedig googleapis qs | |
// Have fun! | |
// Modules | |
var net = require('net') | |
var url = require('url') | |
var util = require('util') | |
var readline = require('readline') | |
var gamedig = require('gamedig') | |
var fs = require('fs') | |
var events = require("events") | |
var emitter = new events.EventEmitter() | |
var exec = require("child_process").exec | |
var google = require('googleapis') | |
var qs = require('qs') | |
var path = require('path') | |
var squeeDir = __dirname+'/../squeebot/' | |
var alpaca = require(squeeDir+'alpaca.json') | |
var responses = 'generic.json' | |
var responselist = require(squeeDir+'responselist/'+responses) | |
// useful variables | |
var NICK; // The bot's nickname | |
var PREFIX; // The prefix of commands | |
var relayserver; // Relay server | |
var relayConnections = {}; // Relay connections | |
var calSyncInterval = false; | |
// nBot variables | |
var botObj; | |
var pluginId; | |
var botF; | |
var botInstanceSettings; | |
var settings; | |
var ircChannelUsers; | |
// Google APIs | |
var gCalendar = google.calendar('v3'); | |
// Episode countdown (!nextep) | |
var week = 7*24*60*60*1000; | |
var airDate; | |
// Notes: | |
// Get hostname from sender: data.rawdata[0].split(' ')[0][1]; | |
// rules/infoc: Rules and information for individual channels. | |
// botops: Bot operators with permission levels | |
// ophosts: IMPORTANT! Currently, in order for botops to execute commands, their hostnames MUST be listed here! | |
var squees = { | |
rules:{}, | |
infoc:{}, | |
botops:{"icydiamond":3}, | |
ophosts:{} | |
} | |
// Events | |
var sEvents = []; | |
// Squeebot splash | |
var splash ="\x1b[1;36m____ _ _ \n"+ | |
"/ ___| __ _ _ _ ___ ___| |__ ___ | |_ \n"+ | |
"\\___ \\ / _` | | | |/ _ \\/ _ \\ \'_ \\ / _ \\| __|\n"+ | |
" ___) | (_| | |_| | __/ __/ |_) | (_) | |_ \n"+ | |
"|____/ \\__, |\\__,_|\\___|\\___|_.__/ \\___/ \\__|\n"+ | |
" |_| \x1b[0m" | |
// This is the list of all your commands. | |
// "command":{"action":YOUR FUNCTION HERE, description:COMMAND USAGE(IF NOT PRESENT, WONT SHOW UP IN !commands)} | |
// Action arguments are the following: simplified, nick, chan, message, pretty, target, isMentioned, isPM | |
var commands = { | |
"help":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1]) { | |
if(simplified[1] === "-a") { | |
listCommands(nick, target, 1); | |
return; | |
} | |
var cmdName = (simplified[1].indexOf(PREFIX) === 0 ? simplified[1].substring(1) : simplified[1]).toLowerCase(); | |
if(cmdName in commands) { | |
var cmd = commands[cmdName]; | |
if(cmd.description) { | |
sendPM(target, nick+": \u0002"+PREFIX+cmdName+"\u000f "+cmd.description+("permlevel" in cmd ? " \u0002["+permstring(cmd.permlevel).toUpperCase()+"]" : "")); | |
} else { | |
if(cmd.alias) { | |
var cmd2 = commands[cmd.alias] | |
if(cmd2 != null && cmd2.description) { | |
sendPM(target, nick+": \u0002"+PREFIX+cmdName+"\u000f "+cmd2.description+("permlevel" in cmd2 ? " \u0002["+permstring(cmd2.permlevel).toUpperCase()+"]" : "")+" \u00037[ALIAS FOR \u00033"+cmd.alias+"\u00037]"); | |
return; | |
} | |
} | |
sendPM(target, nick+": \u0002"+PREFIX+cmdName+"\u000f - No description :( "+("permlevel" in cmd ? " \u0002["+permstring(cmd.permlevel).toUpperCase()+"]" : "")); | |
} | |
} else { | |
sendPM(target, nick+": That is not a known command!"); | |
} | |
} else { | |
listCommands(nick, target); | |
} | |
}), description:"[command] - All Commands"}, | |
"cmdsource":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1]) { | |
var cmdName = (simplified[1].indexOf(PREFIX) === 0 ? simplified[1].substring(1) : simplified[1]).toLowerCase(); | |
if(cmdName in commands) { | |
var cmd = commands[cmdName]; | |
if("source" in cmd) { | |
sendPM(target, "Command \u00033"+cmdName+"\u000f is from plugin \u00037"+cmd.source); | |
} else { | |
sendPM(target, "Command \u00033"+cmdName+"\u000f is from plugin \u00037"+pluginId); | |
} | |
} else { | |
sendPM(target, nick+": That is not a known command!"); | |
} | |
} else { | |
listCommands(nick, target); | |
} | |
}), description:"[command] - Source plugin of this command", permlevel: 1}, | |
"squeebot":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
sendPM(target, "Squeebot is a plugin for nBot (by nnnn20430) written by LunaSquee."); | |
if(simplified[1] && simplified[1].toLowerCase()==="source") | |
sendPM(target, nick+", You can see the source here: https://gist.github.com/LunaSquee/95e849c9d44a4874501f"); | |
}), description:"[source] - Squeebot info"}, | |
"info":{"action":(function(simplified, nick, chan, message, pretty, target, mentioned, pm) { | |
if(pm) { | |
sendPM(target, "This command can only be executed in a channel."); | |
} else { | |
var channel = chan.toLowerCase(); | |
if("infoc" in squees) { | |
if(channel in squees.infoc) { | |
sendPM(target, nick+": "+squees.infoc[channel]); | |
return | |
} | |
} | |
sendPM(target, "No information to display for "+chan); | |
} | |
}), description:"- Channel Information"}, | |
"events":{"action":(function(simplified, nick, chan, message, pretty, target, mentioned, pm) { | |
if(simplified[1] && simplified[1].toLowerCase() == "refresh") { | |
synccalendar(11); | |
return; | |
} | |
if (sEvents.length === 0) { | |
sendPM(target, "\u0002Events: \u0002\u00034No events"); | |
return; | |
} | |
var eEvents = []; | |
sEvents.forEach(function(t) { | |
var isRunning = currentRunCheck(t.eventStartTime, t.eventEndTime || 0); | |
if(isRunning === 0) | |
eEvents.push("\u00037"+t.eventName+"\u0003"); | |
else if(isRunning === 1) | |
eEvents.push("\u00033"+t.eventName+"\u0003"); | |
else | |
eEvents.push("\u00034"+t.eventName+"\u0003"); | |
}); | |
sendPM(target, "\u0002Events: \u000f"+eEvents.join(", ")); | |
}), description:"- List events"}, | |
"event":{"action":(function(simplified, nick, chan, message, pretty, target, mentioned, pm) { | |
if(simplified[1] != null) { | |
var specify = 1; | |
if(simplified[1] == '-d') | |
specify = 2; | |
if(parseInt(simplified[specify])) { | |
var valid = sEvents[parseInt(simplified[specify]) - 1]; | |
if(valid) { | |
tellEvent(valid, target, specify === 1); | |
} else { | |
sendPM(target, nick+": No event with that id found!"); | |
} | |
} else if(typeof simplified[specify] == "string") { | |
var amount = 0; | |
sEvents.forEach(function(t) { | |
if(t.eventName.toLowerCase().indexOf(message.split(' ').slice(specify).join(' ').toLowerCase()) === 0) { | |
if(amount > 0) return; | |
tellEvent(t, target, specify === 1); | |
amount += 1; | |
} | |
}); | |
if(amount === 0) { | |
sendPM(target, nick+": No such event found!"); | |
} | |
} | |
} else { | |
sendPM(target, nick+": Not enough arguments! Usage: \u0002!event\u0002 <index/name>"); | |
} | |
}), description:"[-d] <index/name> - Event information"}, | |
"rules":{"action":(function(simplified, nick, chan, message, pretty, target, mentioned, pm) { | |
if(pm) { | |
sendPM(target, "This command can only be executed in a channel."); | |
} else { | |
var channel = chan.toLowerCase(); | |
var t = nick; | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
t = simplified[1]; | |
if("rules" in squees) { | |
if(channel in squees.rules) { | |
sendPM(channel, t+": Channel Rules of "+chan+": "); | |
var rls = squees.rules[channel]; | |
if(typeof rls == "object") { | |
rls.forEach(function(e) { | |
sendPM(channel, "["+(rls.indexOf(e)+1)+"] "+e); | |
}); | |
} else { | |
sendPM(channel, rls); | |
} | |
return; | |
} | |
} | |
sendPM(target, "No rules to display for "+chan); | |
} | |
}), description:"- Channel Rules"}, | |
"yay":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
sendPM(target, simplified[1]+": http://flutteryay.com"); | |
else | |
sendPM(target, nick+": http://flutteryay.com"); | |
})}, | |
"date":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
var date = ''; | |
switch (simplified[1] ? simplified[1].toUpperCase() : null) { | |
case 'UTC': | |
date = new Date().toUTCString(); | |
break; | |
case 'UNIX': | |
date = Math.round(new Date().getTime() / 1000); | |
break; | |
default: | |
date = new Date(); | |
} | |
sendPM(target, date); | |
})}, | |
"squee":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
sendPM(target, simplified[1]+": https://www.youtube.com/watch?v=O1adNgZl_3Q"); | |
else | |
sendPM(target, nick+": https://www.youtube.com/watch?v=O1adNgZl_3Q"); | |
})}, | |
"timetostop":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
sendPM(target, simplified[1]+": https://www.youtube.com/watch?v=2k0SmqbBIpQ"); | |
else | |
sendPM(target, nick+": https://www.youtube.com/watch?v=2k0SmqbBIpQ"); | |
})}, | |
"banned":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
sendPM(target, simplified[1]+": https://derpibooru.org/795478"); | |
else | |
sendPM(target, nick+": https://derpibooru.org/795478"); | |
})}, | |
"request":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
sendPM(target, simplified[1]+": To request a song, simply ask us. Provide a youtube link or just the song's title and artist!"); | |
else | |
sendPM(target, nick+": To request a song, simply ask us. Provide a youtube link or just the song's title and artist!"); | |
})}, | |
"hug":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
sendPMact(target, "hugs "+nick); | |
})}, | |
"episodes":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
sendPM(target, simplified[1]+": List of all MLP:FiM Episodes: http://mlp-episodes.tk/"); | |
else | |
sendPM(target, nick+": List of all MLP:FiM Episodes: http://mlp-episodes.tk/"); | |
}),description:"- List of pony episodes"}, | |
"mc":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
var reqplayers = false; | |
if(simplified[1] === "players") { | |
reqplayers = true; | |
} | |
getGameInfo("minecraft", "minecraft.djazz.se", function(err, msg) { | |
if(err) { | |
sendPM(target, err); | |
return; | |
} | |
sendPM(target, msg); | |
}, reqplayers); | |
}), alias:"minecraft"}, | |
"mumble":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
var requsers = false; | |
if(simplified[1] === "users") { | |
requsers = true; | |
} | |
if(simplified[1] === "download") { | |
sendPM(target, "\u000310[Mumble] \u00033Download Mumble here: \u000312http://wiki.mumble.info/wiki/Main_Page#Download_Mumble"); | |
return; | |
} | |
getGameInfo("mumbleping", "mumble.djazz.se", function(err, msg) { | |
if(err) { | |
sendPM(target, err); | |
return; | |
} | |
sendPM(target, msg); | |
}, requsers); | |
}), description:"[users/download] - Information about our Mumble Server"}, | |
"episode":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
var param = simplified[1]; | |
if(param != null) { | |
var epis = param.match(/^s([0-9]+)e([0-9]+)$/i); | |
if(epis && epis[2]<=26 && epis[1]<=6){ | |
var link = "http://mlp-episodes.tk/#epi"+epis[2]+"s"+epis[1]; | |
sendPM(target, nick+": Watch the episode you requested here: "+link); | |
} else { | |
sendPM(target, nick+": Correct usage !ep s[season number]e[episode number]"); | |
} | |
} else { | |
sendPM(target, nick+": Please provide me with episode number and season, for example: !ep s4e4"); | |
} | |
}),description:"s<Season>e<Episode Number> - Open a pony episode"}, | |
"viewers":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
livestreamViewerCount((function(r, a) { | |
if(r === "offline") | |
r = "\u00034The livestream is offline"; | |
else | |
r = a; | |
sendPM(target, r+" \u00033Livestream: \u000312http://radio.djazz.se/#livestream") | |
}), 0); | |
}),alias: "livestream"}, | |
"np":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
getCurrentSong(function(d, e, i) { | |
if(i) { | |
sendPM(target, "\u00033Now playing: \u000312"+d+" \u00033Listeners: \u000312"+e+" \u00033Click here to tune in: \u000312http://radio.djazz.se/"); | |
} else { | |
sendPM(target, d); | |
} | |
}) | |
}), alias: "radio"}, | |
"l":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
getCurrentSong(function(d, e, i) { | |
if(i) { | |
sendPM(target, "\u00033Listeners: \u000312"+e+" \u00033Tune in: \u000312http://radio.djazz.se/"); | |
} else { | |
sendPM(target, d); | |
} | |
}) | |
}), alias: "listeners"}, | |
"nextep":{"action":(function(simplified, nick, chan, message, pretty, target) { | |
var counter = 0; | |
var now = Date.now(); | |
do { | |
var timeLeft = Math.max(((airDate+week*(counter++)) - now)/1000, 0); | |
} while (timeLeft === 0 && counter < settings.nextepisode.countTimes); | |
if (counter === settings.nextepisode.countTimes) { | |
sendPM(target, "Season "+settings.nextepisode.inSeason+" is over :("); | |
} else { | |
sendPM(target, /*(counter == 1 ? "First" : "Next") + */"Next Season "+settings.nextepisode.inSeason+" episode airs in %s", readableTime(timeLeft, true)); | |
} | |
//commands["event"].action(["event", "episode"], nick, chan, message, pretty, target); | |
}),description:"- Time left until next pony episode."}, | |
"nothing":{description:"- Does absolutely nothing."}, | |
"alpaca":{action: function(simplified, nick, chan, message, pretty, target) { | |
if(simplified[1] && simplified[1] in botObj.publicData.ircChannelUsers[chan]) | |
nick = simplified[1] | |
var rand = Math.floor(Math.random() * alpaca.length) | |
sendPM(target, nick+": http://jocketf.se/c/"+alpaca[rand]) | |
}}, | |
"squees":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(nick != "Diamond" && nick != "IcyDiamond" && nick != "LunaSquee") | |
return sendPM(target, nick+": I don't think so.") | |
if(simplified[1] === "save") { | |
squees_save(target); | |
} else if(simplified[1] === "load") { | |
squees_load(target); | |
} else if(simplified[1] === "add") { | |
if (simplified[2] === "host") { | |
var hostas = message.split(' ').slice(3).join(' '); | |
if(hostas != null) { | |
if(hostas in squees.ophosts) | |
sendPM(target, "Already there!"); | |
else | |
squees.ophosts[hostas] = ''; | |
} else { | |
sendPM(target, "Invalid hostname"); | |
} | |
} | |
} else if(simplified[1] === "del") { | |
if (simplified[2] === "host") { | |
var hostas = message.split(' ').slice(3).join(' '); | |
if(hostas != null) { | |
if(!hostas in squees.ophosts) | |
sendPM(target, "Hostname not in list!"); | |
else | |
delete squees.ophosts[hostas]; | |
} else { | |
sendPM(target, "Invalid hostname"); | |
} | |
} | |
} else if(simplified[1] === "promote") { | |
var nickz = simplified[2]; | |
var level = 0; | |
if(parseInt(simplified[3])) { | |
level = parseInt(simplified[3]); | |
} else { | |
sendPM(target, "Invalid number '"+simplified[3]+"'"); | |
} | |
if(nickz != null) { | |
squees.botops[nickz.toLowerCase()] = level; | |
sendPM(target, "Changed permlevel of user "+nickz+" to "+permstring(level)); | |
} else { | |
sendPM(target, "Invalid nickname"); | |
} | |
} else if(simplified[1] === "demote") { | |
var nickz = simplified[2]; | |
var level = 0; | |
if(parseInt(simplified[3])) { | |
level = parseInt(simplified[3]); | |
} else { | |
sendPM(target, "Invalid number '"+simplified[3]+"'"); | |
} | |
if(nickz != null) { | |
if (nickz.toLowerCase() in squees.botops) { | |
delete squees.botops[nickz.toLowerCase()]; | |
sendPM(target, "Removed user "+nickz+" from list"); | |
} | |
} else { | |
sendPM(target, "Invalid nickname"); | |
} | |
} | |
}), description:"- Permission Management", "permlevel": 3}, | |
"plugin":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(simplified[1] == "load") { | |
botF.botPluginLoad(simplified[2], botInstanceSettings.pluginDir+'/'+simplified[2]+'.js'); | |
botInstanceSettings.plugins.arrayValueAdd(simplified[2]); | |
} else if(simplified[1] == "reload") { | |
if (botObj.pluginData[simplified[2]]) { | |
pluginReload(simplified[2]); | |
} | |
} else if(simplified[1] == "reloadall") { | |
pluginReload(pluginId); | |
for (var plugin in botObj.pluginData) { | |
if (plugin != pluginId && plugin != 'simpleMsg') { | |
pluginReload(plugin); | |
} | |
} | |
} else if(simplified[1] == "unload" || simplified[1] == "remove") { | |
botF.botPluginDisable(simplified[2]); | |
botInstanceSettings.plugins.arrayValueRemove(simplified[2]); | |
} | |
}), description:"<load/reload/reloadall/unload> [plugin] - Plugin management", "permlevel":3}, | |
"binary":{action: (function(simplified, nick, chan, message, data, target, isMentioned, isPM) { | |
var response = '', strArr, i, message = ''; | |
for (i in data.messageARGS) { | |
if (i > 1) { | |
message += ' '+data.messageARGS[i]; | |
} | |
} | |
message = message.substr(1) | |
switch (data.messageARGS[1] ? data.messageARGS[1].toUpperCase() : null) { | |
case 'ENCODE': strArr = message.split(''); | |
for (i in strArr) { | |
response += ' '+('0000000'+parseInt(new Buffer(strArr[i].toString(), 'utf8').toString('hex'), 16).toString(2)).slice(-8); | |
} | |
response=response.substr(1); | |
break; | |
case 'DECODE': message=message.split(' ').join(''); | |
i = 0; | |
while (8*(i+1) <= message.length) { | |
response += new Buffer(parseInt(message.substr(8*i, 8), 2).toString(16), 'hex').toString('utf8'); i++; | |
} | |
response = "Decoded: "+response; | |
} | |
sendPM(target, response); | |
}), description: "<ENCODE/DECODE> <message> - Encode/decode binary (ASCII)"}, | |
"evaljs":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
eval("(function () {"+message.split(" ").slice(1).join(" ")+"})")(); | |
}), description:"<code> - Run javascript code.", "permlevel":3}, | |
"echo":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
sendPM(target, pretty.messageARGS[1].replaceSpecialChars()); | |
}), description:"<msg> - Echo back.", "permlevel":2}, | |
"convertseconds":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(parseInt(simplified[1])) | |
sendPM(target, readableTime(parseInt(simplified[1]), true)); | |
else | |
sendPM(target, "Invalid number"); | |
}), description:"<seconds> - Convert seconds to years days hours minutes seconds."}, | |
"converttime":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(simplified[1] != null) | |
sendPM(target, parseTimeToSeconds(message.substring(PREFIX.length+11-(isPM ? 0 : 1))) + " seconds"); | |
else | |
sendPM(target, "Invalid string"); | |
}), description:"<years>y <weeks>w <days>d <hours>h <minutes>m <seconds>s - Convert ywdhms to seconds."}, | |
"say":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
var channel = pretty.messageARGS[1]; | |
if(channel != null) | |
sendPM(channel, message.split(" ").slice(2).join(" ").replaceSpecialChars()); | |
}), description:"<channel> <msg> - Say in channel as bot.", "permlevel":2}, | |
"act":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
var channel = pretty.messageARGS[1]; | |
if(channel != null) | |
sendPMact(channel, message.split(" ").slice(2).join(" ").replaceSpecialChars()); | |
}), description:"<channel> <msg> - Act in channel as bot.", "permlevel":2}, | |
"permlevel":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(simplified[1] && simplified[1].toLowerCase() in squees.botops) { | |
sendPM(target, simplified[1]+" is "+permstring(squees.botops[simplified[1].toLowerCase()])); | |
} else { | |
sendPM(target, "Not in list."); | |
} | |
})}, | |
"skip":{"action":(function(simplified, nick, chan, message, pretty, target, mentioned, isPM) { | |
if(settings["paraspritekey"] == null) return; | |
var url = "http://radio.djazz.se/api/skip?apikey="+settings.paraspritekey; | |
fetchJSON(url, function(err, res) { | |
if(err) { | |
sendPM(target, "Skip failed."); | |
} else { | |
if(!isPM) { | |
sendPM(target, "Skipped song"); | |
} | |
} | |
}); | |
}),description:"- Skip the current song.", "permlevel":1}, | |
"announce":{"action":(function(simplified, nick, chan, message, pretty, target, mentioned, isPM) { | |
if(settings["paraspritekey"] == null) return; | |
var text = ""; | |
if(!simplified[1]) { | |
sendPM(target, nick+": Not enough parameters!"); | |
return; | |
} | |
var text = message.split(" ").slice(1).join(" "); | |
var url = "http://radio.djazz.se/api/announce?apikey="+settings.paraspritekey+"&message="+encodeURIComponent(text); | |
fetchJSON(url, function(err, res) { | |
if(err) { | |
sendPM(target, "Announce failed."); | |
} else { | |
if(!isPM) { | |
sendPM(target, "Announcement sent!"); | |
} | |
} | |
}); | |
}),description:"[say:]<message> - Play an announcement on radio.", "permlevel":1}, | |
"queue":{"action":(function(simplified, nick, chan, message, pretty, target, mentioned, isPM) { | |
if(settings["paraspritekey"] == null) return; | |
if(!simplified[1]) { | |
sendPM(target, nick+": Not enough parameters!"); | |
return; | |
} | |
var src = message.split(" ").slice(1).join(" "); | |
if(src === "") { | |
sendPM(target, nick+": Error occured!"); | |
return; | |
} | |
var url = "http://radio.djazz.se/api/queue?apikey="+settings.paraspritekey+"&add="+encodeURIComponent(src); | |
fetchJSON(url, function(err, res) { | |
if(err) { | |
sendPM(target, "Queue failed."); | |
} else { | |
if(!isPM) { | |
if(src.indexOf("soundcloud.com") !== -1) { | |
getSoundcloudFromUrl(src, target, true); | |
} else if(src.indexOf("youtu.be/") !== -1) { | |
var det = src.match(/youtu.be\/([^\?\&\#]+)/i)[1]; | |
if(det) { | |
getYoutubeFromVideo(det, target, true); | |
} | |
} else if(src.indexOf("youtube.com/") !== -1) { | |
var det = src.match("[\\?&]v=([^&#]*)"); | |
if(det) { | |
getYoutubeFromVideo(det[1], target, true); | |
} | |
} else { | |
sendPM(target, "Queued!"); | |
} | |
} | |
} | |
}); | |
}),description:"<file/url> - Queue a song.", "permlevel":1}, | |
"sh":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(settings["allowShell"] == false) { | |
sendPM(target, "Using shell is disabled."); | |
return; | |
} | |
if(!simplified[1]) return; | |
var command = message.substring(isPM ? 3 : PREFIX.length+3); | |
exec(command, {shell: '/bin/bash'}, function(error, stdout, stderr) { | |
if(stdout) { | |
sendPM(target, stdout.replace(/\n/g, " ;; ")); | |
} else { | |
mylog(error); | |
} | |
}); | |
}), description:"<command> - icypi shell command.", "permlevel":3}, | |
"icypi":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(settings["allowShell"] == false) { | |
sendPM(target, "Using shell is disabled."); | |
return; | |
} | |
exec("cat /sys/class/thermal/thermal_zone0/temp", {shell: '/bin/bash'}, function(error1, stdout1, stderr1) { | |
if(stdout1) { | |
exec("uptime", {shell: '/bin/bash'}, function(error, stdout, stderr) { | |
if(stdout) { | |
var loadavg = stdout.match(/load average: (\d\.\d+), (\d\.\d+), (\d\.\d+)/).slice(1); | |
var t = stdout.match(/up (.+),? \d+ users?/).slice(1); | |
var uptime = t[t.length-1].substring(0, t[t.length-1].length-2); | |
loadavg = loadstat(loadavg); | |
sendPM(target, "\u000310[icypi]\u000f \u00033uptime:\u000312 "+uptime+" \u000f\u00033load avg:\u000f"+loadavg+" \u00033temp:\u000312 "+(parseInt(stdout1)/1000)+"°C"); | |
} else { | |
mylog(error); | |
} | |
}); | |
} else { | |
mylog(error1); | |
} | |
}); | |
}), description:"- icypi status report."}, | |
"randomsentence":{"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
postJSON("http://watchout4snakes.com/wo4snakes/Random/NewRandomSentence", {}, | |
function(e, c, p) { | |
sendPM(target, c); | |
}); | |
}), description:"- Generate a random sentence."}, | |
"aliases": {"action":(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(!simplified[1]) { | |
sendPM(target, nick+": Please specify command."); | |
return; | |
} | |
if(!commands[simplified[1].toLowerCase()]) { | |
sendPM(target, nick+": That is not a valid command!"); | |
return; | |
} | |
var aliases = []; | |
for(var c in commands) { | |
var cmd = commands[c]; | |
if(cmd["alias"] && cmd["alias"] == simplified[1].toLowerCase()) { | |
aliases.push("\u00033"+c+"\u000f"); | |
} | |
} | |
if(aliases.length === 0) { | |
sendPM(target, nick+": That command has no aliases."); | |
return; | |
} | |
sendPM(target, "Aliases for \u00033"+simplified[1].toLowerCase()+"\u000f: "+aliases.join(", ")); | |
}), description:"<command> - Find aliases for this command."}, | |
"responselist": {action:(function(simplified, nick, chan, message, pretty, target, isMentioned, isPM) { | |
if(simplified[1] == null) | |
return sendPM(target, "Currently using response list "+responselist); | |
if(simplified[1] == 'load') | |
return response_list_load() | |
if(simplified[1] == 'save') | |
return response_list_save() | |
}), permlevel: 3}, | |
"listeners":{"action":(function() {commands['l'].action.apply(null, arguments)}), description: "- Number of people listening to Parasprite Radio"}, | |
"radio":{"action":(function() {commands['np'].action.apply(null, arguments)}), description: "- Current song on Parasprite Radio"}, | |
"livestream":{"action":(function() {commands['viewers'].action.apply(null, arguments)}), description: "- Number of people watching djazz'es Livestream"}, | |
"minecraft":{"action":(function() {commands['mc'].action.apply(null, arguments)}), description: "[players] - Information about our Minecraft Server"}, | |
"ep":{"action":(function() {commands['episode'].action.apply(null, arguments)}), alias: "episode"} | |
}; | |
// PRIVMSG functions such as CTCP handling | |
var privmsgFunc = { | |
ctcpRespond:function(data) { | |
var timestamp; | |
if (new RegExp('\x01VERSION\x01', 'g').exec(data.message) !== null) { | |
botF.ircSendCommandNOTICE("\x01VERSION I'm a plugin for nBot written by LunaSquee.\x01", data.nick); | |
} else if (new RegExp('\x01CLIENTINFO\x01', 'g').exec(data.message) !== null) { | |
botF.ircSendCommandNOTICE("\x01CLIENTINFO VERSION TIME LOCATION PING CLIENTINFO USERINFO SOURCE\x01", data.nick); | |
} else if (new RegExp('\x01USERINFO\x01', 'g').exec(data.message) !== null) { | |
botF.ircSendCommandNOTICE("\x01USERINFO Squeebot\x01", data.nick); | |
} else if (new RegExp('\x01SOURCE\x01', 'g').exec(data.message) !== null) { | |
botF.ircSendCommandNOTICE("\x01SOURCE http://gist.github.com/LunaSquee/95e849c9d44a4874501f\x01", data.nick); | |
} else if (new RegExp('\x01TIME\x01', 'g').exec(data.message) !== null) { | |
botF.ircSendCommandNOTICE("\x01TIME "+new Date()+"\x01", data.nick); | |
} else if (new RegExp('\x01LOCATION\x01', 'g').exec(data.message) !== null) { | |
botF.ircSendCommandNOTICE("\x01LOCATION Equestria(imaginative) Diamond's room(reality)\x01", data.nick); | |
} else if ((timestamp = new RegExp('\x01PING ([^\x01]*)\x01', 'g').exec(data.message)) !== null) { | |
botF.ircSendCommandNOTICE("\x01PING "+timestamp[1]+"\x01", data.nick); | |
} | |
}, | |
}; | |
// Fetch a google calendar | |
function fetchCalendar(calendar, customDescription, timeFrame) { | |
if (settings["googleapikey"] == null) return; | |
if (calendar == null) | |
return mylog("Calendar not found."); | |
var now = Date.now(); | |
gCalendar.events.list({calendarId: calendar, | |
auth: settings.googleapikey, | |
timeMin: new Date(now-10*60*1000).toISOString(), | |
timeMax: new Date(now+timeFrame).toISOString(), | |
singleEvents: true}, function(err, def) { | |
if(err) { | |
mylog("Calendar events failed to fetch:") | |
console.log(err); | |
return; | |
} | |
now = Date.now(); | |
for (var i = 0; i < def.items.length; i++) { | |
var item = prettifyEvent(def.items[i]); | |
if(customDescription != null) { | |
item.description = customDescription; | |
} | |
if(now < item.end.getTime()) { | |
sEvents.push({eventName: item.title, eventStartTime: new Date(item.start)/1000, eventEndTime: new Date(item.end)/1000, description: item.description || ""}); | |
} | |
} | |
sEvents.sort(sortStartTime); | |
}); | |
} | |
// Sync calendars | |
function synccalendar(no) { | |
if(calSyncInterval == false && no == null) | |
return | |
sEvents = []; | |
fetchCalendar(settings.calendars.squeebot, null, 30*24*60*60*1000); | |
fetchCalendar(settings.calendars.parasprite, "An event on Parasprite Radio.", 14*24*60*60*1000); | |
if(no == null) | |
setTimeout(synccalendar, 300000); | |
} | |
// Kill all relay connections and close the server | |
function destroyIrcRelay() { | |
if(relayserver == null) return; | |
for(var con in relayConnections) { | |
var t = relayConnections[con]; | |
t.end(); | |
t.destroy(); | |
} | |
relayserver.close(); | |
} | |
/* | |
=================== | |
NICKNAME UTILITIES! | |
=================== | |
*/ | |
// Check if nick is op on channel | |
function isOpOnChannel(user, channel) { | |
var isUserChanOp = false; | |
var ircChannelUsers = botObj.publicData.ircChannelUsers; | |
if (ircChannelUsers[channel] && ircChannelUsers[channel][user] && ircChannelUsers[channel][user].mode) { | |
if (ircChannelUsers[channel][user].mode.replace(/^(o|q|h|a)$/, "isOp").indexOf("isOp") != -1 ) { isUserChanOp = true; } | |
} | |
return isUserChanOp; | |
} | |
// Check if nick is a bot operator | |
function isGlobalOp(hostsa) { | |
hostsa = hostsa.substring(1).split("!"); | |
if("ophosts" in squees && "botops" in squees) { | |
if(hostsa[1] in squees.ophosts && hostsa[0].toLowerCase() in squees.botops) { | |
return true; | |
} | |
} | |
return false; | |
} | |
// Return the hostname's permission level (nickname!username@hostname) | |
function permlevel(hostsa) { | |
hostsa = (hostsa.indexOf(":") === 0 ? hostsa.substring(1) : hostsa).split("!"); | |
if("ophosts" in squees && "botops" in squees) { | |
if(hostsa[1] in squees.ophosts && hostsa[0].toLowerCase() in squees.botops) { | |
return squees.botops[hostsa[0].toLowerCase()]; | |
} | |
} | |
return 0; | |
} | |
// String representation of a permission level | |
function permstring(level, color) { | |
var str = "" | |
switch(level) { | |
case 1: | |
str = "Helper"; | |
break; | |
case 2: | |
str = "Moderator"; | |
break; | |
case 3: | |
str = "Admin"; | |
break; | |
default: | |
str = "User"; | |
break; | |
} | |
return str; | |
} | |
// Converts prefix to mode | |
function prefixToMode(prefix) { | |
var mode = ""; | |
switch (prefix) { | |
case "~": | |
mode = "q"; | |
break; | |
case "&": | |
mode = "a"; | |
break; | |
case "@": | |
mode = "o"; | |
break; | |
case "%": | |
mode = "h"; | |
break; | |
case "+": | |
mode = "v"; | |
break; | |
default: | |
mode = ""; | |
break; | |
} | |
return mode; | |
} | |
// Converts mode to prefix | |
function modeToPrefix(mode) { | |
var prefix = ""; | |
switch (mode) { | |
case "q": | |
prefix = "~"; | |
break; | |
case "a": | |
prefix = "&"; | |
break; | |
case "o": | |
prefix = "@"; | |
break; | |
case "h": | |
prefix = "%"; | |
break; | |
case "v": | |
prefix = "+"; | |
break; | |
default: | |
prefix = ""; | |
break; | |
} | |
return prefix; | |
} | |
// Converts mode to text | |
function modeToText(mode) { | |
var prefix = ""; | |
switch (mode) { | |
case "q": | |
prefix = "Owner"; | |
break; | |
case "a": | |
prefix = "Admin"; | |
break; | |
case "o": | |
prefix = "Op"; | |
break; | |
case "h": | |
prefix = "Halfop"; | |
break; | |
case "v": | |
prefix = "Voice"; | |
break; | |
default: | |
prefix = "Normal"; | |
break; | |
} | |
return prefix; | |
} | |
/* | |
End of nick utils. | |
Misc. Utilities | |
*/ | |
// Generate random in betweem two ints | |
function getRandomInt(min, max) { | |
return Math.floor(Math.random() * (max - min + 1)) + min; | |
} | |
// Generate random string of characters | |
function uid(len, full) { | |
var buf = [] | |
, chars = (full == null ? 'abcdefghijklmnopqrstuvwxyz' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') | |
, charlen = chars.length; | |
for (var i = 0; i < len; ++i) { | |
buf.push(chars[getRandomInt(0, charlen - 1)]); | |
} | |
return buf.join(''); | |
} | |
// Reload a plugin | |
function pluginReload(plugin) { | |
botF.botPluginDisable(plugin); | |
botF.botPluginLoad(plugin, botInstanceSettings.pluginDir+'/'+plugin+'.js'); | |
} | |
// Sort events by start time | |
function sortStartTime(a, b) { | |
return a.eventStartTime - b.eventEndTime | |
} | |
// Prettify an event object and keep out the unnecessary data | |
function prettifyEvent(item) { | |
var ev = { | |
id: item.id, | |
htmlLink: item.htmlLink, | |
created: new Date(item.created), | |
updated: new Date(item.updated), | |
title: item.summary, | |
location: item.location, | |
description: item.description, | |
start: new Date(item.start.dateTime || item.start.date), | |
end: new Date(item.end.dateTime || item.end.date), | |
sequence: item.sequence, | |
id: item.id | |
} | |
ev.length = (ev.end.getTime()-ev.start.getTime())/1000 | |
return ev; | |
} | |
// Color load averages from uptime shell command | |
function loadstat(loads) { | |
var result = []; | |
for(var i = 0; i<loads.length;i++) { | |
var load = loads[i]; | |
if(parseFloat(load) < 0.75) | |
result.push("\u000312 "+load+"\u000f"); | |
else if(parseFloat(load) < 1) | |
result.push("\u00037 "+load+"\u000f"); | |
else if(parseFloat(load) > 1) | |
result.push("\u00035 "+load+"\u000f"); | |
} | |
return result.join(','); | |
} | |
function parseForMinecraft(message) { | |
return message.replace(/\x0310/g, '§3').replace(/\x0311/g, '§b').replace(/\x0312/g, '§9').replace(/\x0313/g, '§d').replace(/\x0314/g, '§8').replace(/\x0315/g, '§7') | |
.replace(/\x030/g, '§f').replace(/\x031/g, '§0').replace(/\x032/g, '§1').replace(/\x033/g, '§2').replace(/\x034/g, '§c').replace(/\x035/g, '§4').replace(/\x036/g, '§5') | |
.replace(/\x037/g, '§6').replace(/\x031/g, '§e').replace(/\x039/g, '§a').replace(/\x02/g, '§l').replace(/\x0f/g, '§r').replace(/\x1F/g, '§n'); | |
} | |
// Strip IRC color codes from string | |
function stripColors(str) { | |
return str.replace(/(\x03\d{0,2}(,\d{0,2})?)/g, ''); | |
}; | |
// Strip IRC style codes from string | |
function stripStyle(str) { | |
return str.replace(/[\x0F\x02\x16\x1F]/g, ''); | |
}; | |
// Strip IRC formatting from string | |
function stripColorsAndStyle(str) { | |
return stripColors(stripStyle(str)); | |
}; | |
// Seconds into HH:MM:SS | |
function toHHMMSS(numbr) { | |
var sec_num = parseInt(numbr, 10); // don't forget the second param | |
var hours = Math.floor(sec_num / 3600); | |
var minutes = Math.floor((sec_num - (hours * 3600)) / 60); | |
var seconds = sec_num - (hours * 3600) - (minutes * 60); | |
if (hours < 10) {hours = "0"+hours;} | |
if (minutes < 10) {minutes = "0"+minutes;} | |
if (seconds < 10) {seconds = "0"+seconds;} | |
var time = ''; | |
if(parseInt(hours) > 0) | |
time = hours+':'+minutes+':'+seconds; | |
else | |
time = minutes+':'+seconds; | |
return time; | |
} | |
// HH:MM:SS from timestamp | |
function timestamp(unixTimestamp) { | |
var dt = new Date(unixTimestamp * 1000); | |
var hours = dt.getHours(); | |
var minutes = dt.getMinutes(); | |
var seconds = dt.getSeconds(); | |
// the above dt.get...() functions return a single digit | |
// so I prepend the zero here when needed | |
if (hours < 10) | |
hours = '0' + hours; | |
if (minutes < 10) | |
minutes = '0' + minutes; | |
if (seconds < 10) | |
seconds = '0' + seconds; | |
return hours + ":" + minutes + ":" + seconds; | |
} | |
// Add commas to numbers (e.g. 1,234,567; 2,456) | |
function addCommas(nStr) { | |
nStr += ''; | |
var x = nStr.split('.'); | |
var x1 = x[0]; | |
var x2 = x.length > 1 ? '.' + x[1] : ''; | |
var rgx = /(\d+)(\d{3})/; | |
while (rgx.test(x1)) { | |
x1 = x1.replace(rgx, '$1' + ',' + '$2'); | |
} | |
return x1 + x2; | |
} | |
// http://stackoverflow.com/a/22149575 | |
function ytDuration(duration) { | |
var a = duration.match(/\d+/g); | |
if (duration.indexOf('M') >= 0 && duration.indexOf('H') == -1 && duration.indexOf('S') == -1) { | |
a = [0, a[0], 0]; | |
} | |
if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1) { | |
a = [a[0], 0, a[1]]; | |
} | |
if (duration.indexOf('H') >= 0 && duration.indexOf('M') == -1 && duration.indexOf('S') == -1) { | |
a = [a[0], 0, 0]; | |
} | |
duration = 0; | |
if (a.length == 3) { | |
duration = duration + parseInt(a[0]) * 3600; | |
duration = duration + parseInt(a[1]) * 60; | |
duration = duration + parseInt(a[2]); | |
} | |
if (a.length == 2) { | |
duration = duration + parseInt(a[0]) * 60; | |
duration = duration + parseInt(a[1]); | |
} | |
if (a.length == 1) { | |
duration = duration + parseInt(a[0]); | |
} | |
return toHHMMSS(duration.toString()); | |
} | |
// Add a zero in front of single-digit numbers | |
function zf(v) { | |
if (v > 9) { | |
return ""+v; | |
} else { | |
return "0"+v; | |
} | |
} | |
// Convert seconds into years days hours minutes seconds(.milliseconds) | |
function readableTime(timems, ignoreMs) { | |
var time = timems|0; | |
var ms = ignoreMs?'':"."+zf((timems*100)%100|0); | |
if (time < 60) return zf(time)+ms+"s"; | |
else if (time < 3600) return zf(time / 60|0)+"m "+zf(time % 60)+ms+"s"; | |
else if (time < 86400) return zf(time / 3600|0)+"h "+zf((time % 3600)/60|0)+"m "+zf((time % 3600)%60)+ms+"s"; | |
else if (time < 31536000) return (time / 86400|0)+"d "+zf((time % 86400)/3600|0)+"h "+zf((time % 3600)/60|0)+"m "+zf((time % 3600)%60)+"s"; | |
else return (time / 31536000|0)+"y "+zf((time % 31536000) / 86400|0)+"d "+zf((time % 86400)/3600|0)+"h "+zf((time % 3600)/60|0)+"m "+zf((time % 3600)%60)+"s"; | |
} | |
// Convert a time string to seconds (e.g. "1h" -> 3600) written by nnnn20430 | |
function parseTimeToSeconds(string) { | |
var seconds = 0; | |
var match; | |
var secMinute = 1 * 60; | |
var secHour = secMinute * 60; | |
var secDay = secHour * 24; | |
var secWeek = secDay * 7; | |
var secYear = secDay * 365; | |
if((match = string.match('([0-9]+)y')) !== null) { | |
seconds += +match[1]*secYear; | |
} | |
if((match = string.match('([0-9]+)w')) !== null) { | |
seconds += +match[1]*secWeek; | |
} | |
if((match = string.match('([0-9]+)d')) !== null) { | |
seconds += +match[1]*secDay; | |
} | |
if((match = string.match('([0-9]+)h')) !== null) { | |
seconds += +match[1]*secHour; | |
} | |
if((match = string.match('([0-9]+)m')) !== null) { | |
seconds += +match[1]*secMinute; | |
} | |
if((match = string.match('([0-9]+)s')) !== null) { | |
seconds += +match[1]; | |
} | |
return seconds; | |
}; | |
/* | |
End of Misc. Utils. | |
*/ | |
// List all commands that have a description set | |
function listCommands(nick, target, all) { | |
var comms = []; | |
var listofem = []; | |
comms.push("All "+NICK+" commands start with a "+PREFIX+" prefix."); | |
comms.push("Type "+PREFIX+"help <command> for more information on that command."); | |
for(var command in commands) { | |
var obj = commands[command]; | |
if(all === 1) { | |
if("description" in obj) { | |
listofem.push("\u0002\u0003"+("permlevel" in obj ? "7" : "3")+command+"\u000f"); | |
} | |
} else { | |
if("description" in obj && !("permlevel" in obj)) { | |
listofem.push("\u0002\u00033"+command+"\u000f"); | |
} | |
} | |
} | |
comms.push(listofem.join(", ")); | |
sendWithDelay(comms, target, 1000); | |
} | |
// Send an array of messages with a delay | |
function sendWithDelay(messages, target, time) { | |
function sendMessageDelayed(c, arri, timeout) { | |
sendPM(target, arri[c]); | |
c++; | |
if(arri[c] != null) | |
setTimeout(function() {sendMessageDelayed(c, arri, timeout)}, timeout); | |
} | |
sendMessageDelayed(0, messages, time || 1000); | |
} | |
// Grab JSON from an url | |
function fetchJSON(link, callback, extendedHeaders) { | |
var parsed = url.parse(link); | |
var opts = { | |
host: parsed.host, | |
path: parsed.path, | |
"headers":{ | |
"User-Agent": "Squeebot/nBot" | |
} | |
} | |
if(extendedHeaders != null) { | |
for(var ext in extendedHeaders) { | |
var header = extendedHeaders[ext]; | |
opts.headers[ext] = header; | |
} | |
} | |
var httpModule = parsed.protocol === 'https:' ? require('https') : require('http'); | |
httpModule.get(opts, function (res) { | |
if (res.statusCode === 302 || res.statusCode === 301) { | |
fetchJSON.call(this, res.headers.location, callback, extendedHeaders); | |
return; | |
} | |
var data = ''; | |
res.on('data', function (chunk) { | |
data += chunk; | |
}) | |
res.on('end', function () { | |
try { | |
var obj = JSON.parse(data); | |
} | |
catch (err) { | |
callback(err, data); | |
return; | |
} | |
callback(null, obj); | |
}); | |
}).on('error', function (e) { | |
callback(e.message); | |
}); | |
} | |
var getJSON = fetchJSON; // Just for the sake of making sense | |
// POST data to an url, expects a JSON response ("http://host:port/data", {heads: null}, function(error, data, res) { }, {\"x-toast\": true}) | |
function postJSON(link, postdata, callback, headers) { | |
var parsed = url.parse(link); | |
var post_data = qs.stringify(postdata); | |
var post_options = { | |
host: parsed.host, | |
port: parsed.port, | |
path: parsed.path, | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/x-www-form-urlencoded', | |
'Content-Length': Buffer.byteLength(post_data), | |
'User-Agent': 'nBot/Squeebot' | |
} | |
} | |
if(headers != null) { | |
for(var ext in headers) { | |
var header = headers[ext]; | |
post_options.headers[ext] = header; | |
} | |
} | |
var httpModule = parsed.protocol === 'https:' ? require('https') : require('http'); | |
var post_req = httpModule.request(post_options, function(res) { | |
res.setEncoding('utf8'); | |
var data = ""; | |
res.on('data', function (chunk) { | |
data += chunk; | |
}); | |
res.on('end', function() { | |
try{ | |
var obj = JSON.parse(data); | |
} catch (err) { | |
callback("no-json", data, res); | |
return; | |
} | |
callback(null, obj, res); | |
}); | |
}).on("error", function(e) { | |
callback(e.message, null, e); | |
}); | |
post_req.write(post_data); | |
post_req.end(); | |
} | |
// Get current Parasprite Radio song | |
function getCurrentSong(callback) { | |
fetchJSON("http://radio.djazz.se/api/status", function(error, content) { | |
if(error === null) { | |
if(content.meta != null && content.info != null && content.info.online === true) { | |
var xt = content.meta; | |
var theTitle = new Buffer(xt.title, "utf8").toString("utf8"); | |
var artist = xt.artist; | |
if(artist!=null) { | |
theTitle=theTitle+" by "+artist; | |
} | |
callback(theTitle, content.info.listeners, true); | |
return; | |
} else { | |
callback("\u00037Parasprite Radio\u000f is \u00034offline!", "", false); | |
} | |
} else { | |
callback("\u00037Parasprite Radio\u000f is \u00034offline!", "", false); | |
} | |
}); | |
} | |
// Gameserver info (This function makes me puke) | |
function getGameInfo(game, host, callback, additional) { | |
gamedig.query( | |
{ | |
type: game, | |
host: host | |
}, | |
function(state) { | |
if(state.error) callback("\u00034Server is offline!", null); | |
else { | |
switch(game) { | |
case "tf2": | |
if(additional) { | |
callback(null, "\u000310[Team Fortress 2]\u000f " + (typeof(additional) === "object" ? state[additional[0]][additional[1]] : state[additional])); | |
} else { | |
callback(null, "\u000310[Team Fortress 2] \u00033IP: \u000312"+host+" \u00033MOTD: \u000312\""+state.name+"\" \u00033Players: \u000312"+state.raw.numplayers+"/"+state.maxplayers); | |
} | |
break; | |
case "minecraft": | |
if(additional!=null && additional === true) { | |
if(state.players.length > 0) { | |
var players = []; | |
state.players.forEach(function(t) { | |
players.push(t.name); | |
}); | |
callback(null, "\u000310[Minecraft] \u00033Players:\u000f "+players.join(", ")); | |
} else { | |
callback(null, "\u000310[Minecraft] \u00034No players"); | |
} | |
} else { | |
callback(null, "\u000310[Minecraft] \u00033IP: \u000312"+host+" \u00033MOTD: \u000312\""+state.name+"\" \u00033Players: \u000312"+state.raw.numplayers+"/"+state.raw.maxplayers); | |
} | |
break; | |
case "mumbleping": | |
/*if(additional!=null && additional === true) { | |
if(state.players.length > 0) { | |
var players = []; | |
// Sort, show most active first | |
state.players.sort(function (u1, u2) { | |
return u1.idlesecs - u2.idlesecs; | |
}); | |
state.players.forEach(function(t) { | |
var isMuted = t.mute || t.selfMute; | |
var isDeaf = t.deaf || t.selfDeaf; | |
var o = t.name; | |
if (isMuted && isDeaf) { | |
o = "\u00035"+o+"\u000f"; | |
} else if (isMuted) { | |
o = "\u00037"+o+"\u000f"; | |
} else if (isDeaf) { | |
o = "\u000312"+o+"\u000f"; | |
} else { | |
o = "\u00039"+o+"\u000f"; | |
} | |
players.push(o); | |
}); | |
callback(null, "\u000310[Mumble] Users:\u0003 "+players.join(" ")); | |
} else { | |
callback(null, "\u000310[Mumble] \u00034No users "); | |
} | |
} else {*/ | |
callback(null, "\u000310[Mumble] \u00033Address: \u000312"+host+" \u00033Users online: \u000312"+state.players.length); | |
//} | |
break; | |
}; | |
} | |
} | |
); | |
} | |
// Dailymotion information from id | |
function dailymotion(id, target) { | |
fetchJSON("https://api.dailymotion.com/video/"+id+"?fields=id,title,owner,owner.screenname,duration,views_total", function(error, data) { | |
if(error === null) { | |
sendPM(target, "\u0002\u00033Dailymotion\u000f \u000312\""+data.title+"\" \u00033Views: \u000312"+addCommas(data.views_total.toString())+" \u00033Duration: \u000312"+toHHMMSS(data.duration.toString())+" \u00033By \u000312\""+data["owner.screenname"]+"\""); | |
} | |
}); | |
} | |
// Youtube information from id | |
function getYoutubeFromVideo(id, target, isQueue) { | |
if(settings["googleapikey"] == null) return; | |
var g_api_base = "https://www.googleapis.com/youtube/v3/videos?id="+id+"&key="+settings.googleapikey+"&part=snippet,contentDetails,statistics,status&fields=items(id,snippet,statistics,contentDetails)"; | |
fetchJSON(g_api_base, function(error, content) { | |
if(error!=null) return; | |
if("items" in content) { | |
if(content.items.length <= 0) { | |
sendPM(target, "Video not found."); | |
return; | |
} | |
var tw = content.items[0]; | |
sendPM(target, (isQueue ? "\u000310\u0002[QUEUED] \u0002\u0003" : "")+"\u0002You\u00035Tube\u000f \u000312\""+tw.snippet.title+"\" \u00033Views: \u000312"+addCommas(tw.statistics.viewCount.toString())+" \u00033Duration: \u000312"+ytDuration(tw.contentDetails.duration.toString())+" \u00039▲ "+addCommas(tw.statistics.likeCount.toString())+" \u00034▼ "+addCommas(tw.statistics.dislikeCount.toString())+" \u00033By \u000312\""+tw.snippet.channelTitle+"\""); | |
} | |
}); | |
} | |
function DBTagSort(a, b) { | |
var indexasfirst = ["suggestive", "questionable", "explicit", "safe", "grimdark", "semi-grimdark", "grotesque"] | |
var tag = a; | |
if(indexasfirst.indexOf(tag) !== -1) | |
return -1; | |
tag = b; | |
if(indexasfirst.indexOf(tag) !== -1) | |
return 1; | |
} | |
function DBTagConstruct(taglist) { | |
taglist = taglist.sort(DBTagSort); | |
var res = []; | |
var color = "\u00039"; | |
var t = 0; | |
for(var tagindex in taglist) { | |
var tag = taglist[tagindex]; | |
if(tag.indexOf("oc") === 0) { | |
color = "\u000313"; | |
} else if(tag == "suggestive" || tag == "questionable" || tag == "explicit" || tag == "safe" || tag == "grimdark" || tag == "semi-grimdark" || tag == "grotesque") { | |
color = "\u000312"; | |
} else if(tag == "edit" || tag.indexOf("artist:") === 0) { | |
color = "\u00032"; | |
} else if(tag.indexOf("spoiler:") === 0) { | |
color = "\u00037"; | |
} else { | |
color = "\u00039"; | |
} | |
res.push(color+" "+tag+"\u0003"); | |
} | |
if(res.length > 12) { | |
t = res.length - 12; | |
res = res.slice(0, 12); | |
res.push(" \u0002"+t+" more.."); | |
} | |
return "\u00036[\u000f"+res.join(",")+" \u00036]\u000f"; | |
} | |
// Kick on NSFW derpibooru links | |
function derpibooru_handle(id, target, nick) { | |
var derpibooRoot = "https://derpibooru.org/"; | |
fetchJSON(derpibooRoot+id+".json", function(error, content) { | |
if(error == null) { | |
if("tags" in content) { | |
var taglist = content.tags.split(", "); | |
sendPM(target, "\u000312Derpibooru\u00039 >>"+id+" \u00037★ "+addCommas(content.faves.toString())+" \u00039▲ "+addCommas(content.upvotes.toString())+" \u00034▼ "+addCommas(content.downvotes.toString())+" "+DBTagConstruct(taglist)); | |
if(taglist.indexOf("explicit") !== -1) { | |
//sendPM(target, "\u0002\u00034NSFW CONTENT WARNING!\u000f\u00037 Image "+id+" is tagged \u00034\"explicit\"\u00037!"); | |
if(target.indexOf("#") === 0) { | |
botF.ircWriteData("KICK "+target+" "+nick+" :Do not post NSFW images in chat."); | |
} | |
} | |
} | |
} | |
}); | |
} | |
// Fetch soundscloud data | |
function getSoundcloudFromUrl(url, target, isQueue) { | |
if(settings['soundcloudkey'] == null) return; | |
var apibase = "https://api.soundcloud.com"; | |
fetchJSON(apibase+"/resolve?url="+url+"&client_id="+settings.soundcloudkey, function(error, response) { | |
if(error) { | |
mylog("SoundCloud fetch Failed"); | |
console.log(error); | |
} else { | |
if(response.kind === "track") { | |
sendPM(target, (isQueue ? "\u000310\u0002[QUEUED] \u0002\u0003" : "")+"\u00037SoundCloud\u000f \u000312\""+response.title+"\" \u00033▶ \u000312"+addCommas(response.playback_count.toString())+" \u00037♥ "+addCommas(response.favoritings_count.toString())+" \u00033Duration: \u000312"+toHHMMSS(Math.floor(response.duration/1000).toString())+" \u00033By \u000312\""+response.user.username+"\""); | |
} else if(response.kind === "playlist") { | |
sendPM(target, "\u00037SoundCloud\u000f \u000312Playlist \""+response.title+"\" \u00033Tracks: \u000312"+addCommas(response.track_count.toString())+" \u00033Duration: \u000312"+toHHMMSS(Math.floor(response.duration/1000).toString())+" \u00033By \u000312\""+response.user.username+"\""); | |
} | |
} | |
}); | |
} | |
// Separate array objects "name" by commas | |
function spotifyArtists(array) { | |
var d = []; | |
array.forEach(function(e) { | |
d.push(e.name); | |
}); | |
return d.join(", "); | |
} | |
// Fetch spotify song data | |
function getSpotifySongFromID(id, target) { | |
if(id == null) return; | |
fetchJSON("https://api.spotify.com/v1/tracks/"+id, function(error, response) { | |
if(error) { | |
mylog("Spotify fetch Failed"); | |
console.log(error); | |
} else { | |
sendPM(target, "\u00033Spotify\u000f \u000312\""+response.name+"\" \u00033Artists: \u000312"+spotifyArtists(response.artists)+" \u00033Duration: \u000312"+toHHMMSS(Math.floor(response.duration_ms/1000).toString())+(response.album != null ? " \u00033Album: \u000312\""+response.album.name+"\"" : "")); | |
} | |
}); | |
} | |
// See if event is currently running (UTC timestamps) | |
// 0: no, 1: running, 2: over | |
function currentRunCheck(startstamp, endstamp) { | |
var date = new Date(); | |
var currentStamp = Math.floor(new Date(date.toUTCString()).getTime() / 1000); | |
if(endstamp === 0) { | |
if(currentStamp >= startstamp) { | |
return 1; | |
} else { | |
return 0; | |
} | |
} else { | |
if(currentStamp >= startstamp && currentStamp < endstamp) { | |
return 1; | |
} else if (currentStamp > endstamp) { | |
return 2; | |
} else { | |
return 0; | |
} | |
} | |
} | |
// eventData: {eventName: "name", eventStartTime: unix seconds (UTC), eventEndTime: unix seconds (UTC) or 0} | |
function tellEvent(eventData, target, countdown) { | |
if(eventData != null) { | |
var isRunning = currentRunCheck(eventData.eventStartTime, eventData.eventEndTime || 0); | |
var timeLeft = 0; | |
var date = new Date(); | |
var timeNow = Math.floor(new Date(date.toUTCString()).getTime() / 1000); // short dance to get current UTC timestamp | |
if(isRunning === 0) { | |
var timeLeftStamp = countdown ? "in "+readableTime(eventData.eventStartTime - timeNow, true) : new Date(eventData.eventStartTime*1000); | |
sendPM(target, "\u0002Event: \u000f\u00037"+eventData.eventName+"\u000f\u0002 starts "+timeLeftStamp+". \u000f"+eventData.description || ""); | |
} else if(isRunning === 1) { | |
var timeLeftStamp = countdown ? "in "+readableTime(eventData.eventEndTime - timeNow, true) : new Date(eventData.eventEndTime*1000); | |
sendPM(target, "\u0002Event: \u000f\u00033"+eventData.eventName+"\u000f\u0002 ends "+timeLeftStamp+". \u000f"+eventData.description || ""); | |
} else { | |
sendPM(target, "\u0002Event: \u000f\u00034"+eventData.eventName+"\u000f\u0002 is over :("); | |
} | |
} | |
} | |
// Finds urls in string | |
function findUrls(text) { | |
var source = (text || '').toString(); | |
var urlArray = []; | |
var url; | |
var matchArray; | |
var regexToken = /(((ftp|https?):\/\/)[\-\w@:%_\+.~#?,&\/\/=]+)|((mailto:)?[_.\w-]+@([\w][\w\-]+\.)+[a-zA-Z]{2,3})/g; | |
while((matchArray = regexToken.exec(source))!== null) { | |
var token = matchArray[0]; | |
if (token.indexOf("youtube.com/watch") !== -1 || token.indexOf("youtu.be/") !== -1 || token.indexOf("dailymotion.com/video/") !== -1 || | |
token.indexOf("soundcloud.com/") !== -1 || token.indexOf("spotify.com/track/") !== -1 || token.indexOf("derpibooru.org") !== -1 || | |
token.indexOf("derpiboo.ru") !== -1 || token.indexOf("derpicdn.net") !== -1 || token.indexOf("twitter.com/") !== -1 || token.indexOf("lunasqu.ee/") !== -1) { | |
urlArray.push(token); | |
} | |
} | |
return urlArray; | |
} | |
// Livestream viewers | |
function livestreamViewerCount(callback, stream, streamer) { | |
if(stream == 0) { | |
fetchJSON("http://radio.djazz.se/api/status", function(error, content) { | |
if(error===null) { | |
var view = content.livestream; | |
if(view.online==true) { | |
callback(null, "\u00033Viewers: \u000311"+view.viewers); | |
} else { | |
callback("offline", "\u00034The livestream is offline"); | |
} | |
} else { | |
callback(error, "\u00034The livestream is offline"); | |
} | |
}); | |
} | |
} | |
// Handles messages | |
function handleMessage(nick, chan, message, pretty, simplified, isMentioned, isPM) { | |
var target = isPM ? nick : chan; | |
var hirex = new RegExp("(hi|hey|hai|hello|hiya),? "+NICK, 'gim'); | |
var hugrex = new RegExp("\x01ACTION hugs "+NICK, 'gim'); | |
var spotrex = ""; | |
if(simplified[0].indexOf(PREFIX) === 0 && simplified[0].toLowerCase().substring(PREFIX.length) in commands) { | |
var permission = permlevel(pretty.rawdata[0].split(' ')[0]); | |
var command = commands[simplified[0].toLowerCase().substring(PREFIX.length)]; | |
if("permlevel" in command) { | |
if(permission < command.permlevel) { | |
sendPM(target, nick+": You do not have permission to execute this command!"); | |
return; | |
} | |
} | |
if("action" in command) | |
command.action(simplified, nick, chan, message, pretty, target, isMentioned, isPM); | |
} else if(isPM && simplified[0].toLowerCase() in commands) { | |
var permission = permlevel(pretty.rawdata[0].split(' ')[0]); | |
var command = commands[simplified[0].toLowerCase()]; | |
if("permlevel" in command) { | |
if(permission < command.permlevel) { | |
sendPM(target, nick+": You do not have permission to execute this command!"); | |
return; | |
} | |
} | |
if("action" in command) | |
command.action(simplified, nick, chan, message, pretty, target, isMentioned, isPM); | |
} else if(hirex.exec(message) != null) { | |
sendPMSD(target, "Hey "+nick+"!!"); | |
} else if(hugrex.exec(message) != null) { | |
sendPMSD(target, "\x01ACTION hugs "+nick+"\x01"); | |
} else if((spotrex = message.match(/spotify:track:([\S]+)/i)) != null) { | |
getSpotifySongFromID(spotrex[1], target); | |
} else if(findUrls(message).length > 0) { | |
var link = findUrls(message)[0]; | |
if(link.indexOf("soundcloud.com") !== -1) { | |
getSoundcloudFromUrl(link, target); | |
} else if(link.indexOf("youtu.be/") !== -1) { | |
var det = link.match(/youtu.be\/([^\?\&\#]+)/i)[1]; | |
if(det) { | |
getYoutubeFromVideo(det, target); | |
} | |
} else if(link.indexOf("youtube.com/") !== -1) { | |
var det = link.match("[\\?&]v=([^&#]*)"); | |
if(det) { | |
getYoutubeFromVideo(det[1], target); | |
} | |
} else if(link.indexOf("dailymotion.com/video/") !== -1) { | |
var det = link.match("/video/([^&#]*)")[1]; | |
if(det) { | |
dailymotion(det, target); | |
} | |
} else if(link.indexOf("spotify.com/track/") !== -1) { | |
var det = link.match("/track/([^&#]*)")[1]; | |
if(det) { | |
getSpotifySongFromID(det, target); | |
} | |
} else if(link.indexOf("derpiboo") !== -1) { | |
var det = link.match(/derpiboo\.?ru(\.org)?\/(images\/)?(\d+[^#?&])/i); | |
if(det && det[3] != null) { | |
var numbere = parseInt(det[3]); | |
if(numbere) { | |
derpibooru_handle(numbere, target, nick); | |
} | |
} | |
} else if(link.indexOf("derpicdn") !== -1) { | |
var det = link.match(/derpicdn\.net\/img\/?(view)?\/\d+\/\d+\/\d+\/(\d[^_\/?#]+)/i); | |
if(det && det[2] != null) { | |
var numbere = parseInt(det[2]); | |
if(numbere) { | |
derpibooru_handle(numbere, target, nick); | |
} | |
} | |
} else if(link.indexOf("twitter.com/") !== -1) { | |
var det = link.match(/twitter.com\/\w+\/status\/(\d+[^&#?\s\/])/i); | |
if(det) { | |
if("tweety" in botObj.pluginData) { | |
botObj.pluginData.tweety.plugin.sendTweetResponse(det[1], target, 0); | |
} | |
} | |
} | |
} else { | |
let mesgmatcher = message.toLowerCase().replace(/\:|\,|\'|\!|\?|\./g, ' ').trim().split(' ') | |
for(let i in responselist) { | |
let resline = responselist[i] | |
let match = true | |
for(let ti in resline.tags) { | |
let tag = resline.tags[ti] | |
if(mesgmatcher.indexOf(tag) == -1 && match == true) { | |
match = false | |
continue | |
} | |
} | |
let response = '' | |
if(match) { | |
if(resline.responses.length == 0 && resline.execCommand != null) { | |
let commandargs = [resline.execCommand.c] | |
for(let t in resline.execCommand.args) | |
commandargs.push(resline.execCommand.args[t].replace(/\@sender/g, nick)) | |
commands[resline.execCommand.c].action(commandargs, nick, chan, message, pretty, target, isMentioned, isPM) | |
break | |
} else if(resline.responses.length != 0) { | |
let randnum = getRandomInt(0, resline.responses.length-1) | |
response = resline.responses[randnum].replace(/\@sender/g, nick) | |
} else { | |
continue | |
} | |
} else { | |
continue | |
} | |
if(response != '') | |
sendPMSD(target, response) | |
break | |
} | |
} | |
} | |
// Relays irc messages to connected clients | |
function ircRelayMessageHandle(c) { | |
emitter.once('newIrcMessage', function (from, to, message, type) { | |
if (c.writable) { | |
c.write(type+">"+from+':'+to+':'+parseForMinecraft(message)+'\r\n'); | |
ircRelayMessageHandle(c); | |
} | |
}); | |
} | |
// Creates a new relay server | |
function ircRelayServer() { | |
if (!settings.relay.enableRelay) return; | |
relayserver = net.createServer(function (c) { //'connection' listener | |
var pingWait = null, pingTimeout = null; | |
function ping() { | |
clearTimeout(pingWait); | |
pingWait = setTimeout(function () { | |
c.write('ping\r\n'); | |
//info('RELAY: Send ping'); | |
pingTimeout = setTimeout(function () { | |
c.destroy(); | |
info('RELAY: Connection timed out'); | |
if(c.remoteAddress in relayConnections) | |
delete relayConnections[c.remoteAddress]; | |
}, 15*1000); | |
}, 15*1000); | |
} | |
function pong() { | |
//info('RELAY: Got pong'); | |
clearTimeout(pingTimeout); | |
ping(); | |
} | |
var addr = c.remoteAddress; | |
var firstData = true; | |
info('RELAY: Client %s is connecting...', c.remoteAddress); | |
c.setEncoding('utf8'); | |
c.once('end', function() { | |
clearTimeout(timeout); | |
info('RELAY: Client '+addr+' disconnected'); | |
if(addr in relayConnections) | |
delete relayConnections[addr]; | |
}); | |
c.once('error', function (err) { | |
clearTimeout(timeout); | |
info('RELAY: Client '+addr+' errored: '+err); | |
c.destroy(); | |
if(addr in relayConnections) | |
delete relayConnections[addr]; | |
}); | |
c.once('close', function() { | |
clearTimeout(timeout); | |
clearTimeout(pingWait); | |
clearTimeout(pingTimeout); | |
info('RELAY: Client '+addr+' socket closed'); | |
if(addr in relayConnections) | |
delete relayConnections[addr]; | |
}); | |
c.on('data', function (data) { | |
if (firstData) { | |
firstData = false; | |
data = data.trim(); | |
clearTimeout(timeout); | |
if (data === settings.relay.relayPassword) { | |
info('RELAY: Client '+addr+' logged in'); | |
c.write('Password accepted\r\n'); | |
ircRelayMessageHandle(c); | |
relayConnections[addr] = c; | |
ping(); | |
} else { | |
info('RELAY: Client '+addr+' supplied wrong password: %s', data); | |
c.end("Wrong password\r\n"); | |
} | |
} else { | |
if (data.trim() === 'pong') { | |
pong(); | |
} else if (data.trim().indexOf("msg:") === 0) { | |
var da = data.trim(); | |
var dz = da.split(":"); | |
if(dz[0] === "msg" && dz.length > 2) { | |
sendPM(dz[1], da.substring(dz[0].length + dz[1].length + 2)); | |
} else { | |
info("Malformed message from %s: ", addr); | |
mylog(data.trim()); | |
} | |
} | |
} | |
}); | |
var timeout = setTimeout(function () { | |
c.end("You were too slow :I\r\n"); | |
info('RELAY: Client '+c.remoteAddress+' was too slow (timeout during handshake)'); | |
}, 10*1000); | |
}); | |
relayserver.listen(settings.relay.relayPort, function () { | |
info('RELAY: Relay server listening on port %d', settings.relay.relayPort); | |
}); | |
} | |
// Save variables of squees | |
function squees_save(channel) { | |
var json_en = JSON.stringify(squees); | |
var savStart = Date.now() / 1000; | |
if(json_en) { | |
fs.writeFile(squeeDir+'savedvars.json', json_en, function (err) { | |
if (err) return mylog(err); | |
if(channel === false) | |
mylog('Variables object saved. Took '+readableTime(savStart - Date.now() / 1000)); | |
else | |
sendPM(channel, "Squees object saved in "+readableTime(savStart -Date.now() / 1000)); | |
}); | |
} | |
} | |
// Load variables of squees | |
function squees_load(channel) { | |
fs.readFile(squeeDir+'savedvars.json', 'utf8', function (err, data) { | |
if (err) return; | |
squees = JSON.parse(data); | |
if (channel === false) | |
mylog('Variables object loaded.'); | |
else | |
sendPM(channel, "Squees object loaded!"); | |
}); | |
} | |
// Save response list | |
function response_list_save() { | |
let json_en = JSON.stringify(responselist, null, '\t'); | |
if(json_en) { | |
fs.writeFile(squeeDir+'responselist/'+responses, json_en, function (err) { | |
if (err) return; | |
}); | |
} | |
} | |
// Load response list | |
function response_list_load(reslist) { | |
let rtype = reslist || responses | |
let json_en = JSON.stringify(responselist, null, '\t'); | |
if(json_en) { | |
fs.readFile(squeeDir+'responselist/'+rtype, 'utf8', function (err, data) { | |
if (err) return; | |
responselist = JSON.parse(data); | |
responses = rtype; | |
}) | |
} | |
} | |
// Log to console | |
function mylog() { | |
botF.debugMsg.apply(botF, Array.prototype.slice.call(arguments)); | |
} | |
// Log to console #2 | |
function info() { | |
arguments[0] = "\x1b[1;35m --\x1b[0m "+arguments[0]; | |
mylog(util.format.apply(null, arguments)); | |
} | |
// Send a PM with a human-like delay | |
function sendPMSD(target) { | |
var message = util.format.apply(null, Array.prototype.slice.call(arguments, 1)); | |
setTimeout((function() {sendPM(target, message)}), (Math.floor(Math.random() * 3) + 2 ) * 1000); | |
} | |
// Send a PRIVMSG | |
function sendPM(target) { | |
var message = util.format.apply(null, Array.prototype.slice.call(arguments, 1)); | |
if(settings.stripColors === true) | |
message = stripColorsAndStyle(message); | |
if(target.indexOf("#") === 0 && emitter) | |
emitter.emit('newIrcMessage', NICK, target, message, "PRIVMSG"); | |
botF.ircSendCommandPRIVMSG(message, target); | |
} | |
// Send a NOTICE | |
function sendNOTICE(target) { | |
var message = util.format.apply(null, Array.prototype.slice.call(arguments, 1)); | |
if(settings.stripColors === true) | |
message = stripColorsAndStyle(message); | |
botF.ircSendCommandNOTICE(message, target); | |
} | |
// Send a PRIVMSG \x01ACTION | |
function sendPMact(target) { | |
var message = '\u0001ACTION '+util.format.apply(null, Array.prototype.slice.call(arguments, 1))+'\u0001'; | |
if(settings.stripColors === true) | |
message = stripColorsAndStyle(message); | |
botF.ircSendCommandPRIVMSG(message, target); | |
} | |
var SettingsConstructor = function (modified) { | |
var settings, attrname; | |
if (this!==SettingsConstructor) { | |
settings = { | |
prefix: '!', | |
googleapikey: null, | |
soundcloudkey: null, | |
paraspritekey: null, | |
stripColors: false, | |
allowShell: false, | |
nBotLoggerOverride: true, | |
nextepisode: { | |
date: [2016, 2, 26, 16, 0, 0], | |
countTimes: 26, | |
inSeason: 6 | |
}, | |
googleauth: { | |
client_id: null, | |
client_secret: null, | |
redirect: "" | |
}, | |
relay: { | |
enableRelay: false, | |
relayPort: 1234, | |
relayPassword: "" | |
} | |
}; | |
for (attrname in modified) {settings[attrname]=modified[attrname];} | |
return settings; | |
} | |
}; | |
// Reserved functions | |
// Add listeners to simpleMsg plugin | |
function utilizeSimpleMsg() { | |
var simpleMsg = botObj.pluginData.simpleMsg.plugin; | |
/* Unused listeners | |
simpleMsg.msgListenerAdd(pluginId, 'TOPIC', function (data) {}); | |
simpleMsg.msgListenerAdd(pluginId, 'RPL_NAMREPLY', function (data) {}); | |
simpleMsg.msgListenerAdd(pluginId, 'NOTICE', function (data) {}); | |
simpleMsg.msgListenerAdd(pluginId, '+MODE', function (data) {}); | |
simpleMsg.msgListenerAdd(pluginId, '-MODE', function (data) {}); | |
*/ | |
simpleMsg.msgListenerAdd(pluginId, 'PRIVMSG', function (data) { | |
for(var bft in privmsgFunc) | |
privmsgFunc[bft](data); | |
var simplified = data.message.replace(/\:/g, ' ').replace(/\,/g, ' ').replace(/\./g, ' ').replace(/\?/g, ' ').trim().split(' '); | |
var isMentioned = simplified.indexOf(NICK) !== -1; | |
if(data.to.indexOf("#") === 0) { | |
handleMessage(data.nick, data.to, data.message, data, simplified, isMentioned, false); | |
if(new RegExp('\x01ACTION ', 'g').exec(data.message) !== null) | |
emitter.emit('newIrcMessage', data.nick, data.to, data.message.replace('\x01ACTION ', '').replace('\x01', ''), "ACTION"); | |
else | |
emitter.emit('newIrcMessage', data.nick, data.to, data.message, "PRIVMSG"); | |
} else { | |
handleMessage(data.nick, "", data.message, data, simplified, isMentioned, true); | |
} | |
}); | |
simpleMsg.msgListenerAdd(pluginId, 'NICK', function (data) { | |
emitter.emit('newIrcMessage', data.nick, "", " is now known as "+data.newnick, "NICK"); | |
botF.debugMsg("\x1b[1;36m["+timestamp(new Date().getTime()/1000)+"]\x1b[1;35m --\x1b[0m "+data.nick+" is now known as "+data.newnick); | |
}); | |
simpleMsg.msgListenerAdd(pluginId, 'JOIN', function (data) { | |
emitter.emit('newIrcMessage', data.nick, data.channel, " has joined ", "JOIN"); | |
botF.debugMsg("\x1b[1;36m["+timestamp(new Date().getTime()/1000)+"]\x1b[1;32m -->\x1b[0m "+data.nick+" has joined "+data.channel); | |
}); | |
simpleMsg.msgListenerAdd(pluginId, 'KICK', function (data) { | |
emitter.emit('newIrcMessage', data.nick, data.channel, " was kicked by "+data.by+" ("+data.reason+")", "KICK"); | |
botF.debugMsg("\x1b[1;36m["+timestamp(new Date().getTime()/1000)+"]\x1b[1;31m <--\x1b[0m "+data.nick+" was kicked by "+data.by+" from "+data.channel+" ("+data.reason+")"); | |
}); | |
simpleMsg.msgListenerAdd(pluginId, 'PART', function (data) { | |
emitter.emit('newIrcMessage', data.nick, data.channel, " has left ", "PART"); | |
botF.debugMsg("\x1b[1;36m["+timestamp(new Date().getTime()/1000)+"]\x1b[1;31m <--\x1b[0m "+data.nick+" has left "+data.channel+" "+(data.reason == null ? data.reason : "")); | |
}); | |
simpleMsg.msgListenerAdd(pluginId, 'QUIT', function (data) { | |
emitter.emit('newIrcMessage', data.nick, "", " has quit ("+data.reason+")", "QUIT"); | |
botF.debugMsg("\x1b[1;36m["+timestamp(new Date().getTime()/1000)+"]\x1b[1;31m <--\x1b[0m "+data.nick+" has quit ("+data.reason+")"); | |
}); | |
simpleMsg.msgListenerAdd(pluginId, 'RAW', function (data) { | |
var nick = data[1][0]; | |
var args = data[3]; | |
if (data[2] === 'PRIVMSG' && args[1] && args[1].indexOf("\u0001ACTION ") === 0) { | |
var action = args[1].substr(8); | |
action = action.substring(0, action.length-1); | |
emitter.emit('newIrcMessage', nick, args[0], action, "ACTION"); | |
} | |
}); | |
//plugin is ready | |
exports.ready = true; | |
botF.emitBotEvent('botPluginReadyEvent', pluginId); | |
} | |
// Handle "botEvent" from bot (botEvent is used for irc related activity) | |
module.exports.botEvent = function (event) { | |
if(event.eventName == "botPluginDisableEvent") { | |
if(event.eventData == pluginId) { | |
destroyIrcRelay(); | |
calSyncInterval = false; | |
} else { | |
for(var t in commands) { | |
var command = commands[t]; | |
if("source" in command) { | |
if(command.source == event.eventData) { | |
mylog("\x1b[1;35m -!-\x1b[0m "+event.eventData+" Unloaded, command \""+t+"\" removed from "+pluginId+"."); | |
delete commands[t]; | |
} | |
} | |
} | |
} | |
} else if(event.eventName == "botReceivedNum005") { | |
botF.ircWriteData("MODE "+botInstanceSettings.botName+" +IB"); | |
} else if(event.eventName == "botPluginReadyEvent") { | |
if (event.eventData == 'simpleMsg') { | |
utilizeSimpleMsg(); | |
} | |
} | |
}; | |
// Functions available from outside the plugin | |
module.exports.plugin = { | |
commandAdd: function(plugin, commandName, action, description, perlevel) { | |
if(commandName in commands) | |
return null; | |
commands[commandName] = {source: plugin, action: action}; | |
if(perlevel != null) | |
commands[commandName].permlevel = perlevel; | |
if(description != null) | |
commands[commandName].description = description; | |
mylog("\x1b[1;35m -!-\x1b[0m "+plugin+" Added command \""+commandName+"\" to "+pluginId+"."); | |
return commands[commandName]; | |
}, | |
isGlobalOp: isGlobalOp, | |
isOpOnChannel: isOpOnChannel, | |
permlevel: permlevel, | |
sendPM: sendPM, | |
sendPMSD: sendPMSD, | |
sendNOTICE: sendNOTICE, | |
fetchJSON: fetchJSON, | |
postJSON: postJSON, | |
readableTime: readableTime, | |
parseTimeToSeconds: parseTimeToSeconds | |
}; | |
module.exports.ready = false; | |
//main function called when plugin is loaded | |
module.exports.main = function (passedData) { | |
// Update variables | |
botObj = passedData.botObj; | |
pluginId = passedData.id; | |
botF = botObj.publicData.botFunctions; | |
botInstanceSettings = botObj.publicData.settings; | |
settings = botInstanceSettings.pluginsSettings[pluginId]; | |
ircChannelUsers = botObj.publicData.ircChannelUsers; | |
// If plugin settings are not defined, define them | |
if (settings === undefined) { | |
settings = new SettingsConstructor(); | |
botInstanceSettings.pluginsSettings[pluginId] = settings; | |
botF.botSettingsSave(); | |
} | |
NICK = botInstanceSettings.botName; | |
PREFIX = settings.prefix; | |
// Set up episode countdown | |
var tr = settings.nextepisode; | |
airDate = Date.UTC(tr.date[0], tr.date[1], tr.date[2], tr.date[3], tr.date[4], tr.date[5]); | |
// Load bot variables | |
squees_load(false); | |
// Create IRC Relay server | |
ircRelayServer(); | |
calSyncInterval = true; | |
synccalendar(); | |
// Plugin is ready | |
botF.emitBotEvent('botPluginReadyEvent', pluginId); | |
console.log(splash); | |
if(settings.nBotLoggerOverride) { | |
botObj.publicData.externalObjects.instanceBotEventHandleObj['PRIVMSG'] = function(connection, data) { | |
var nick = data[1][0], | |
to = data[4][0], | |
message = data[5]||data[4][1]; | |
if(message.indexOf("\x01ACTION") === 0) | |
mylog('\x1b[1;36m['+timestamp(new Date().getTime()/1000)+']\x1b[1;34m['+to+']\x1b[0m \x1b[1;92m* \x1b[0m'+nick+'\x1b[0m '+message.substring(8)); | |
else | |
mylog('\x1b[1;36m['+timestamp(new Date().getTime()/1000)+']\x1b[1;34m['+to+']\x1b[0m \x1b[1;92m<\x1b[0m'+nick+'\x1b[1;92m>\x1b[0m '+message); | |
} | |
botObj.publicData.externalObjects.instanceBotEventHandleObj['NOTICE'] = function(connection, data) { | |
var nick = data[1][0], | |
to = data[4][0], | |
message = data[5]||data[4][1]; | |
mylog('\x1b[1;36m['+timestamp(new Date().getTime()/1000)+']\x1b[1;33m[NOTICE('+to+')]\x1b[0m \x1b[1;92m<\x1b[0m'+nick+'\x1b[1;32m>\x1b[0m '+message); | |
} | |
} | |
//check and utilize dependencies | |
if (botObj.pluginData.simpleMsg && botObj.pluginData.simpleMsg.ready) | |
utilizeSimpleMsg(); | |
if (require.cache && require.cache[path.resolve(squeeDir+'responselist/'+responses)]) | |
delete require.cache[path.resolve(squeeDir+'responselist/'+responses)]; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jshint node: true*/ | |
/*jshint evil: true*/ | |
// This is a plugin for nBot (https://git.mindcraft.si.eu.org/?p=nBot.git) | |
// Before using: npm install node-twitter-api html-entities | |
// Have fun! | |
// ~ LunaSquee | |
"use strict"; | |
//reserved nBot variables | |
var botObj; | |
var pluginId; | |
var botF; | |
var botV; | |
var settings; | |
var pluginSettings; | |
var ircChannelUsers; | |
//variables | |
var http = require('http'); | |
var net = require('net'); | |
var fs = require('fs'); | |
var util = require('util'); | |
var events = require('events'); | |
var exec = require('child_process').exec; | |
var path = require('path'); | |
var Entities = require('html-entities').AllHtmlEntities; | |
var entities = new Entities(); | |
var twitterAPI = require('node-twitter-api'); | |
var twitter; | |
var twitterData = {}; | |
var twitClient; | |
var twitClientSec; | |
var twitStreams = {} | |
var pluginDisabled = false; | |
//settings constructor | |
var SettingsConstructor = function (modified) { | |
var settings, attrname; | |
if (this!==SettingsConstructor) { | |
settings = { | |
enableTweetTrack: false, | |
tweetTrack: {"userid": ["#channel"]}, | |
authinfo: { | |
app: null, | |
app_secret: null, | |
client: null, | |
client_secret: null | |
} | |
}; | |
for (attrname in modified) {settings[attrname]=modified[attrname];} | |
return settings; | |
} | |
}; | |
function addCommas(nStr) { | |
nStr += ''; | |
var x = nStr.split('.'); | |
var x1 = x[0]; | |
var x2 = x.length > 1 ? '.' + x[1] : ''; | |
var rgx = /(\d+)(\d{3})/; | |
while (rgx.test(x1)) { | |
x1 = x1.replace(rgx, '$1' + ',' + '$2'); | |
} | |
return x1 + x2; | |
} | |
var TwitterTracker = function(userid, channels) { | |
this.stream = null | |
this.live = false | |
this.closeRequested = false | |
this.reconnTries = 0 | |
this.channels = channels | |
this.userid = userid | |
this.user_handle = null | |
this.recvData = function(error, data) { | |
this.reconnTries = 0 | |
if(error) { | |
console.log('\x1b[1;35m --\x1b[0m Twitter stream of ['+userid+'] errored!') | |
console.log(error) | |
} else { | |
if("id_str" in data) { | |
if(this.user_handle == null) | |
this.user_handle = data.user.screen_name | |
if(data.in_reply_to_status_id === null && data.in_reply_to_user_id === null) { | |
if(data.text.indexOf("RT") === 0 && data.user.screen_name != this.user_handle) | |
return | |
channels.forEach(function(u) { | |
pluginObj.sendTweetResponse(data.id_str, u, 1) | |
}) | |
} | |
} | |
} | |
} | |
this.recvFail = function(e) { | |
var self = this | |
console.log('\x1b[1;35m --\x1b[0m Twitter stream of ['+userid+'] ended!') | |
self.stream = null | |
self.live = false | |
if (self.closeRequested == false && pluginDisabled == false) { | |
if(self.reconnTries >= 3) { | |
console.log("\x1b[1;35m --\x1b[0m Max reconnect tries reached! Gave up.") | |
self.closeRequested = true | |
return | |
} | |
self.reconnTries += 1 | |
console.log("\x1b[1;35m --\x1b[0m Twitter stream reconnecting in 5s") | |
setTimeout(function() { | |
self.init() | |
}, 5000) | |
} | |
} | |
this.init = function() { | |
console.log('\x1b[1;35m --\x1b[0m Twitter stream for '+userid+' starting, reporting on '+channels.length+' channels') | |
var self = this | |
this.live = true | |
twitter.users('show', {user_id: self.userid}, twitClient, twitClientSec, function(error, data, response) { | |
if(error) { | |
self.user_handle = null | |
} else { | |
self.user_handle = data.screen_name | |
} | |
}) | |
this.stream = twitter.getStream('filter', {follow: userid}, twitClient, twitClientSec, function(e, d) { | |
self.recvData(e, d) | |
}, function(e) { | |
self.recvFail(e) | |
}) | |
} | |
this.kill = function() { | |
this.closeRequested = true | |
if(this.stream) { | |
this.stream.end() | |
this.stream.destroy() | |
} | |
} | |
} | |
//main plugin object | |
var pluginObj = { | |
sendTweetResponse: function(tweetId, target, showTwo) { | |
twitter.statuses("show", {id:tweetId}, twitClient, twitClientSec, function(err, data){ | |
if(err) { | |
botF.ircSendCommandPRIVMSG("Status fetch failed!", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("\u000310Twitter\u0003 \u0002@"+data.user.screen_name+"\u0002: "+entities.decode(data.text).replace(/\n/g, ' ').trim(), target); | |
if(showTwo == 1) | |
botF.ircSendCommandPRIVMSG("\u0002Link to tweet:\u0002 https://twitter.com/"+data.user.screen_name+"/status/"+data.id_str, target); | |
} | |
}); | |
}, | |
twitStreamsInit: function() { | |
console.log('\x1b[1;35m --\x1b[0m Twitter streams initiating') | |
for(var trackUID in pluginSettings.tweetTrack) { | |
var channels = pluginSettings.tweetTrack[trackUID] | |
if(twitStreams[trackUID] != null) | |
twitStreams[trackUID].kill() | |
twitStreams[trackUID] = new TwitterTracker(trackUID, channels) | |
twitStreams[trackUID].init() | |
} | |
}, | |
sendTweet: function(nick, msg, target) { | |
if('tokens-'+nick.toLowerCase() in twitterData) { | |
var dats = twitterData['tokens-'+nick.toLowerCase()]; | |
var etr = {status:msg}; | |
var tester; | |
if((tester = msg.match(/R:(\d+[^\w\s]*)/)) != null) { | |
etr.in_reply_to_status_id = tester[1]; | |
etr.status = etr.status.replace(tester[0], ''); | |
} | |
twitter.statuses("update", etr, dats.acc, dats.accsec, function(err, data){ | |
if(err) { | |
botF.ircSendCommandPRIVMSG("Status update failed!", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("Success! https://twitter.com/"+data.user.screen_name+"/status/"+data.id_str, target); | |
} | |
}); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
}, | |
displayUser: function(screen_name, target) { | |
twitter.users('show', {screen_name: screen_name}, twitClient, twitClientSec, function(error, data, response) { | |
if(error) { | |
botF.ircSendCommandPRIVMSG("No such user!", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("\u0002@"+data["screen_name"]+"\u0002 ("+data["name"]+"): "+entities.decode(data["description"]).replace(/\n/g, ' ').trim(), target); | |
botF.ircSendCommandPRIVMSG("\u00033Tweets: \u000312"+addCommas(data["statuses_count"])+" \u00033Following: \u000312"+addCommas(data["friends_count"])+" \u00033Followers: \u000312"+addCommas(data["followers_count"])+"\u000f", target); | |
} | |
}); | |
}, | |
initCommands: function() { | |
var manePlugin = botObj.pluginData.squeebot.plugin; | |
manePlugin.commandAdd(pluginId, "tw", function(simplified, nick, chan, message, pretty, target, mentioned, isPM) { | |
if(simplified[1] != null) { | |
var msg = message.split(' ').slice(1).join(' '); | |
pluginObj.sendTweet(nick, msg, target); | |
} | |
}); | |
manePlugin.commandAdd(pluginId, "twitter", function(simplified, nick, chan, message, pretty, target, mentioned, isPM) { | |
var isOp = manePlugin.permlevel(pretty.rawdata[0].split(' ')[0]) >= 2; | |
if(simplified[1] === "status" && simplified[2] != null) { | |
if(!isOp) { | |
botF.ircSendCommandPRIVMSG(nick+": You do not have permission to execute this command!", target); | |
return; | |
} | |
var msg = message.split(' ').slice(2).join(' '); | |
twitter.statuses("update", {status:msg}, twitClient, twitClientSec, function(err, data){ | |
if(err) { | |
botF.ircSendCommandPRIVMSG("Status update failed!", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("Success! https://twitter.com/"+data.user.screen_name+"/status/"+data.id_str, target); | |
} | |
}); | |
} else if(simplified[1] === "tweet" && simplified[2] != null) { | |
var msg = message.split(' ').slice(2).join(' '); | |
pluginObj.sendTweet(nick, msg, target); | |
} else if(simplified[1] === "display" && simplified[2] != null) { | |
pluginObj.sendTweetResponse(simplified[2], target, 1); | |
} else if(simplified[1] === "stream" && simplified[2] != null) { | |
if(!isOp) { | |
botF.ircSendCommandPRIVMSG(nick+": You do not have permission to execute this command!", target); | |
return; | |
} | |
if(simplified[2] == "end") { | |
if(simplified[3] == null) { | |
botF.ircSendCommandPRIVMSG("Ending all twitter streams..", target); | |
for(var s in twitStreams) { | |
var t = twitStreams[s] | |
t.kill() | |
delete twitStreams[s] | |
} | |
return | |
} | |
var stream = twitStreams[simplified[3]] | |
if(stream) { | |
botF.ircSendCommandPRIVMSG("Ending twitter stream..", target) | |
stream.kill() | |
delete twitStreams[simplified[3]] | |
} | |
} else if(simplified[2] == "start") { | |
if(simplified[3] == null) { | |
botF.ircSendCommandPRIVMSG("Starting all twitter streams..", target) | |
pluginObj.twitStreamsInit() | |
return | |
} | |
var str = simplified[3] | |
if(pluginSettings.tweetTrack[str]) { | |
twitStreams[str] = new TwitterTracker(str, pluginSettings.tweetTrack[str]) | |
twitStreams[str].init() | |
} | |
} else if(simplified[2] == "list") { | |
var list = [] | |
var i | |
for(i in twitStreams) { | |
list.push((twitStreams[i].live == false ? "\u00034 " : "\u00033 ")+i) | |
} | |
botF.ircSendCommandPRIVMSG("Streams currently running:"+list.join(','), target) | |
} else if(simplified[2] == "listall") { | |
var list = [] | |
var i | |
for(i in pluginSettings.tweetTrack) { | |
if(twitStreams[i]) | |
list.push((twitStreams[i].live == false ? "\u00034 " : "\u00033 ")+i) | |
else | |
list.push("\u00037 "+i) | |
} | |
botF.ircSendCommandPRIVMSG("Streams available:"+list.join(','), target) | |
} else if(simplified[2] == "status") { | |
if(simplified[3] == null){ | |
botF.ircSendCommandPRIVMSG("Invalid target", target) | |
return | |
} | |
var str = twitStreams[simplified[3]] | |
if(str == null) { | |
botF.ircSendCommandPRIVMSG("Invalid target", target) | |
return | |
} | |
botF.ircSendCommandPRIVMSG("Twitter stream ["+str.userid+"]"+(str.user_handle != null ? " (\u0002@"+str.user_handle+"\u0002)" : "")+" is "+(str.live == false ? "\u00034Offline" : "\u00033Online")+"\u000f broadcasting to: "+str.channels.join(', '), target) | |
} | |
} else if(simplified[1] == "admin") { | |
if(!isOp) { | |
botF.ircSendCommandPRIVMSG(nick+": You do not have permission to execute this command!", target); | |
return; | |
} | |
if(nick.toLowerCase() in twitterData) { | |
botF.ircSendCommandPRIVMSG(nick+": Please log out before using admin account!", target); | |
return; | |
} | |
twitter.verifyCredentials(pluginSettings.authinfo.client, pluginSettings.authinfo.client_secret, function(error, data, response) { | |
if (error) { | |
botF.ircSendCommandPRIVMSG(nick+": Admin account tokens failed to verify!", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("You are now logged in as @"+data["screen_name"]+" ("+data["name"]+")!", target); | |
twitterData[nick.toLowerCase()] = data; | |
twitterData['tokens-'+nick.toLowerCase()] = {acc:pluginSettings.authinfo.client, accsec:pluginSettings.authinfo.client_secret}; | |
} | |
}); | |
} else if(simplified[1] == "auth") { | |
if(simplified[2] != null) { | |
if(simplified[2] == "cancel") { | |
if('reqtokens-'+nick.toLowerCase() in twitterData) { | |
delete twitterData['reqtokens-'+nick.toLowerCase()]; | |
botF.ircSendCommandPRIVMSG("Authentication cancelled.", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not currently in authentication process.", target); | |
} | |
return; | |
} | |
if('reqtokens-'+nick.toLowerCase() in twitterData) { | |
var tokens = twitterData['reqtokens-'+nick.toLowerCase()]; | |
twitter.getAccessToken(tokens.req, tokens.reqsec, simplified[2], function(error, accessToken, accessTokenSecret, results) { | |
if (error) { | |
console.log(error); | |
botF.ircSendCommandPRIVMSG("An error occured while verifying.", target); | |
} else { | |
twitter.verifyCredentials(accessToken, accessTokenSecret, function(error, data, response) { | |
if (error) { | |
botF.ircSendCommandPRIVMSG("An error occured while trying to verify.", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("You are now logged in as @"+data["screen_name"]+" ("+data["name"]+")!", target); | |
botF.ircSendCommandPRIVMSG("Use '!twitter tweet <tweet>' to tweet as yourself.", target); | |
twitterData['tokens-'+nick.toLowerCase()] = {acc:accessToken, accsec:accessTokenSecret}; | |
twitterData[nick.toLowerCase()] = data; | |
delete twitterData['reqtokens-'+nick.toLowerCase()]; | |
console.log(data["screen_name"]+" verified for "+nick); | |
} | |
}); | |
} | |
}); | |
} | |
} else { | |
twitter.getRequestToken(function(error, requestToken, requestTokenSecret, results){ | |
if (error) { | |
console.log("Error getting OAuth request token : " + error); | |
botF.ircSendCommandPRIVMSG("An error occured while trying to get you a token.", target); | |
} else { | |
twitterData['reqtokens-'+nick.toLowerCase()] = {req: requestToken, reqsec: requestTokenSecret}; | |
botF.ircSendCommandPRIVMSG("Please authenticate yourself: https://twitter.com/oauth/authenticate?oauth_token="+requestToken, target); | |
botF.ircSendCommandPRIVMSG("Enter your pin by doing !twitter auth yourPINHere", target); | |
} | |
}); | |
} | |
} else if(simplified[1] == "authed") { | |
if(nick.toLowerCase() in twitterData) { | |
var datr = twitterData['tokens-'+nick.toLowerCase()]; | |
twitter.verifyCredentials(datr.acc, datr.accsec, function(error, data, response) { | |
if (error) { | |
botF.ircSendCommandPRIVMSG("An error occured while trying to verify.", target); | |
botF.ircSendCommandPRIVMSG("If this error presists, run !twitter logout and reauthenticate.", target); | |
} else { | |
twitterData[nick.toLowerCase()] = data; | |
botF.ircSendCommandPRIVMSG("You're successfully authenticated as @"+twitterData[nick.toLowerCase()]["screen_name"]+" ("+twitterData[nick.toLowerCase()]["name"]+").", target); | |
} | |
}); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
} else if(simplified[1] == "user") { | |
if(simplified[2] == null) { | |
if(nick.toLowerCase() in twitterData) { | |
var datr = twitterData['tokens-'+nick.toLowerCase()]; | |
twitter.verifyCredentials(datr.acc, datr.accsec, function(error, data, response) { | |
if (error) { | |
botF.ircSendCommandPRIVMSG("An error occured while trying to verify.", target); | |
botF.ircSendCommandPRIVMSG("If this error presists, run !twitter logout and reauthenticate.", target); | |
} else { | |
twitterData[nick.toLowerCase()] = data; | |
var xdata = twitterData[nick.toLowerCase()]; | |
botF.ircSendCommandPRIVMSG("\u0002@"+xdata["screen_name"]+"\u0002 ("+xdata["name"]+"): "+entities.decode(xdata["description"]).replace(/\n/g, ' ').trim(), target); | |
botF.ircSendCommandPRIVMSG("\u00033Tweets: \u000312"+addCommas(xdata["statuses_count"])+" \u00033Following: \u000312"+addCommas(xdata["friends_count"])+" \u00033Followers: \u000312"+addCommas(xdata["followers_count"])+"\u000f", target); | |
} | |
}); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
} else { | |
pluginObj.displayUser(simplified[2].replace(/^\@/, ''), target); | |
} | |
} else if(simplified[1] == "retweet") { | |
if(simplified[2]!=null && simplified[2].match(/\d+/g) != null) { | |
var id = simplified[2].match(/\d+/g)[0]; | |
if('tokens-'+nick.toLowerCase() in twitterData) { | |
var datr = twitterData['tokens-'+nick.toLowerCase()]; | |
twitter.statuses("retweet", {id:id}, datr.acc, datr.accsec, function(err, data){ | |
if(err) { | |
botF.ircSendCommandPRIVMSG("Failed to retweet tweet!", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("Success! https://twitter.com/"+data.user.screen_name+"/status/"+data.id_str, target); | |
} | |
}); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
} else { | |
botF.ircSendCommandPRIVMSG("Invalid ID parameter!", target); | |
} | |
} else if(simplified[1] == "like") { | |
if(simplified[2]!=null && simplified[2].match(/\d+/g) != null) { | |
var id = simplified[2].match(/\d+/g)[0]; | |
if('tokens-'+nick.toLowerCase() in twitterData) { | |
var datr = twitterData['tokens-'+nick.toLowerCase()]; | |
twitter.favorites("create", {id:id}, datr.acc, datr.accsec, function(err, data){ | |
if(err) { | |
botF.ircSendCommandPRIVMSG("Failed to like tweet!", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("Success! https://twitter.com/"+data.user.screen_name+"/status/"+data.id_str, target); | |
} | |
}); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
} else { | |
botF.ircSendCommandPRIVMSG("Invalid ID parameter!", target); | |
} | |
} else if(simplified[1] == "follow") { | |
if(simplified[2]!=null) { | |
var iud = simplified[2].replace(/^\@/, ''); | |
if('tokens-'+nick.toLowerCase() in twitterData) { | |
var datr = twitterData['tokens-'+nick.toLowerCase()]; | |
twitter.friendships("create", {screen_name:iud}, datr.acc, datr.accsec, function(err, data){ | |
if(err) { | |
botF.ircSendCommandPRIVMSG("Failed to follow user!", target); | |
console.log(err); | |
} else { | |
botF.ircSendCommandPRIVMSG("Successfully followed @"+data.screen_name+" ("+data.name+")!", target); | |
} | |
}); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
} else { | |
botF.ircSendCommandPRIVMSG("Missing screen name!", target); | |
} | |
} else if(simplified[1] == "unfollow") { | |
if(simplified[2]!=null) { | |
var iud = simplified[2].replace(/^\@/, ''); | |
if('tokens-'+nick.toLowerCase() in twitterData) { | |
var datr = twitterData['tokens-'+nick.toLowerCase()]; | |
twitter.friendships("destroy", {screen_name:iud}, datr.acc, datr.accsec, function(err, data){ | |
if(err) { | |
botF.ircSendCommandPRIVMSG("Failed to unfollowed user!", target); | |
console.log(err); | |
} else { | |
botF.ircSendCommandPRIVMSG("Successfully unfollowed @"+data.screen_name+" ("+data.name+")!", target); | |
} | |
}); | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
} else { | |
botF.ircSendCommandPRIVMSG("Missing screen name!", target); | |
} | |
} else if(simplified[1] == "logout") { | |
if(nick.toLowerCase() in twitterData) { | |
botF.ircSendCommandPRIVMSG("Logging you out..", target); | |
delete twitterData[nick.toLowerCase()]; | |
delete twitterData['tokens-'+nick.toLowerCase()]; | |
} else { | |
botF.ircSendCommandPRIVMSG("You're not authenticated!", target); | |
} | |
} else if(simplified[1] == "help") { | |
botF.ircSendCommandPRIVMSG("\u00033Commands: \u00037status, stream, admin, \u00033tweet, auth, authed, logout, display, like, retweet, follow, unfollow, user", target); | |
} else { | |
botF.ircSendCommandPRIVMSG("Invalid command!", target); | |
} | |
}, "<command> [<args>] - twitter integration"); | |
//plugin is ready | |
exports.ready = true; | |
botF.emitBotEvent('botPluginReadyEvent', pluginId); | |
} | |
}; | |
//exports | |
module.exports.plugin = pluginObj; | |
module.exports.ready = false; | |
//reserved functions | |
//reserved functions: handle "botEvent" from bot (botEvent is used for irc related activity) | |
module.exports.botEvent = function (event) { | |
//event is a object with properties "eventName" and "eventData" | |
switch (event.eventName) { | |
case 'botPluginDisableEvent': if (event.eventData == pluginId) { | |
pluginDisabled = true; | |
twitterData = {}; | |
for(var str in twitStreams) { | |
var a = twitStreams[str] | |
a.kill() | |
delete twitStreams[str] | |
} | |
} break; | |
case 'botPluginReadyEvent': if (event.eventData == "squeebot") { | |
pluginObj.initCommands(); | |
} break; | |
} | |
}; | |
//reserved functions: main function called when plugin is loaded | |
module.exports.main = function (passedData) { | |
//update variables | |
botObj = passedData.botObj; | |
pluginId = passedData.id; | |
botF = botObj.publicData.botFunctions; | |
botV = botObj.publicData.botVariables; | |
settings = botObj.publicData.settings; | |
pluginSettings = settings.pluginsSettings[pluginId]; | |
ircChannelUsers = botObj.publicData.ircChannelUsers; | |
//if plugin settings are not defined, define them | |
if (pluginSettings === undefined) { | |
pluginSettings = new SettingsConstructor(); | |
settings.pluginsSettings[pluginId] = pluginSettings; | |
botF.botSettingsSave(); | |
} | |
twitter = new twitterAPI({ | |
consumerKey: pluginSettings.authinfo.app, | |
consumerSecret: pluginSettings.authinfo.app_secret, | |
callback: 'oob' | |
}) | |
twitter.verifyCredentials(pluginSettings.authinfo.client, pluginSettings.authinfo.client_secret, function(error, data, response) { | |
if (error) { | |
console.log("\x1b[1;35m --\x1b[0m Twitter credentials are invalid!") | |
} else { | |
console.log("\x1b[1;35m --\x1b[0m Twitter credentials are valid! Twitter module ready") | |
twitClient = pluginSettings.authinfo.client | |
twitClientSec = pluginSettings.authinfo.client_secret | |
twitterData[settings.botName] = data | |
if(pluginSettings.enableTweetTrack) { | |
pluginObj.twitStreamsInit() | |
} | |
} | |
}) | |
botF.emitBotEvent('botPluginReadyEvent', pluginId); | |
if (botObj.pluginData.squeebot && botObj.pluginData.squeebot.ready) | |
pluginObj.initCommands() | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment