Bots Home
|
Create an App
Lulu's Little Helper
Author:
testbro
Description
Source Code
Launch Bot
Current Users
Created by:
Testbro
var _APPNAME = "Lulu's Little Helper"; String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); } String.prototype.padL = function (length) { // optional param: paddingChar (default=" ") var pad = arguments.length > 1 ? arguments[1] : ' '; return this.length < length ? (pad + this).padL(length, pad) : this.substr(0, length); } String.prototype.padR = function (length) { // optional param: paddingChar (default=" ") var pad = arguments.length > 1 ? arguments[1] : ' '; return this.length < length ? (this + pad).padR(length, pad) : this.substr(0, length); } String.prototype.padC = function (length) { // optional param: paddingChar (default=" ") var pad = arguments.length > 1 ? arguments[1] : ' '; if (this.length >= length) return this.substr(0, length); if (this.length + 1 == length) return this + pad; else return (pad + this + pad).padC(length, pad); } String.prototype.mapReplace = function (map) { // optional param: replaceFullOnly (default="false) var replaceFullOnly = arguments.length > 1 ? arguments[1] : false; var regexp = []; for (var key in map) { regexp.push(RegExp.escape(key)); } regexp = regexp.join('|'); if (replaceFullOnly) { regexp = '\\b(?:' + regexp + ')\\b'; } regexp = new RegExp(regexp, 'gi'); return this.replace(regexp, function (match) { return map[match.toLowerCase()]; }); } String.isString = function (o) { return (typeof o == 'string' || o instanceof String); } RegExp.escape= function(s) { return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); }; Number.prototype.getOrdinal = function() { switch(this % 100) { case 11: case 12: case 13: return this + "th"; } switch(this % 10) { case 1: return this + "st";; case 2: return this + "nd"; case 3: return this + "rd"; } return this + "th"; } Function.isFunction = function (o) { return !!(o && o.constructor && o.call && o.apply); } var utility = { getPredefinedColor : function (name) { switch (name.toLowerCase()) { case 'black': return '#000'; case 'white': return '#fff'; case 'yellow': return '#fe3'; case 'pink': return '#f0e'; case 'purple': return '#609'; case 'orange': return User.Color.ORANGE.getColor(); case 'red': return User.Color.RED.getColor(); case 'green': return User.Color.GREEN.getColor(); case 'blue': return User.Color.BLUE.getColor(); case 'cyan': return User.Color.CYAN.getColor(); case 'grey': case 'gray': return User.Color.GREY.getColor(); default: return '#000'; } }, securityCheck : function (user, checks, prefix) { if (user.isBroadcaster()) return true; for (var i = 0 ; i < checks.length ; i++) { if (user.is(checks[i]) && sys.settings.get(prefix + checks[i]).getValue()) { return true; } }; return false; }, getTimeDifference : function (time1) { var time2 = arguments.lenght > 1 ? arguments[1] : new Date(); if (time2 < time1) { var t = time1; time1 = time2; time2 = t; } var d = (time2 - time1) / 1000; if (d < 60) { return Math.floor(d) + "s" } d /= 60; var m = Math.floor(d % 60); var h = Math.floor(d / 60); var str = ''; if (h) str += h + 'h '; str += m + 'm' return str; } } utility.Interval = function (callback, interval) { var roundedInt = Math.ceil(interval / 1000) * 1000; var active = false; var left = 0; var fun = function () { if (active) { var total = left + roundedInt; var runs = Math.floor(total / interval); left = total % interval; for (; runs ; runs--) { callback(this); } cb.setTimeout(fun, roundedInt); } } this.start = function () { if (!active) { left = 0; cb.setTimeout(fun, roundedInt); } active = true; } this.stop = function () { active = false; } this.isRunning = function () { return active; } } utility.Timeout = function (callback, interval) { interval = Math.ceil(interval / 1000) * 1000; var active = false; var fun = function () { if (active) callback(this); } this.start = function () { if (!active) { cb.setTimeout(fun, interval); } active = true; } this.stop = function () { active = false; } this.isRunning = function () { return active; } } var Module = function (name, rawData) { var internalSettings = ('internalSettings' in rawData) ? rawData.internalSettings : []; var externalSettings = ('externalSettings' in rawData) ? rawData.externalSettings : []; var filters = ('filters' in rawData) ? rawData.filters : []; var commands = ('commands' in rawData) ? rawData.commands : {}; var handlers = { enter : [], leave : [], message : [], subject : [], tip : [], setting : {} } if ('handlers' in rawData) { if ('enter' in rawData.handlers) handlers.enter = rawData.handlers.enter; if ('leave' in rawData.handlers) handlers.leave = rawData.handlers.leave; if ('message' in rawData.handlers) handlers.message = rawData.handlers.message; if ('subject' in rawData.handlers) handlers.subject = rawData.handlers.subject; if ('tip' in rawData.handlers) handlers.tip = rawData.handlers.tip; if ('setting' in rawData.handlers) handlers.setting = rawData.handlers.setting; } handlers.message.unshift(function (message) { if (!message.original) { message.original = message.getMessage().trim(); } if (message.original[0] =='/') { message.setHidden(true); var params = message.original.substring(1).split(/[ \t]/); var command = params.shift().toLowerCase(); if (command in commands) { var consumedBy = message.getConsumedBy(); if (consumedBy) { var debug = _APPNAME + ' (module "' + name + '"): The command "/' + command + '" is disabled because it is already provided by '; if (consumedBy.name == _APPNAME && consumedBy.slot == cb.slot) { if (String.isString(consumedBy.consumed)) debug += 'the module "' + consumedBy.consumed + '".'; else debug += 'another module of this app.' } else { debug += 'the '; if (consumedBy.slot == 0) debug += 'app '; else debug += 'bot '; debug += '"' + consumedBy.name + '" ' if (String.isString(consumedBy.consumed)) debug += '(module "' + consumedBy + ') '; if (consumedBy.slot != 0) debug += 'in slot ' + consumedBy.slot; debug += '. ' } sys.debug(debug) return; } var result = commands[command](params, command, message); if (result) { sys.debug(message.getUser().getName() + ' executed command "/' + command + '"'); message.consume(); } else { sys.debug(message.getUser().getName() + ' tried to execute command "/' + command + ''); cb.sendNotice("Insufficient Privileges to execute " + message.getMessage() + ".", message.getUser().getName(), sys.settings.get('security_bg').getValue(), sys.settings.get('security_fg').getValue(), sys.settings.get('security_w' ).getValue()); } } } }); handlers.message.unshift(function (message) { filters.forEach(function (filter) { var result = filter(message); if (result === true) { message.setHidden(false); } if (result === false) { message.setHidden(true); } }); }); this.handleMessage = function (message) { handlers.message.forEach(function (handler) { handler(message); }); } this.handleLeave = function (user) { handlers.leave.forEach(function(handler) { handler(user); }); } this.handleEnter = function (user) { handlers.enter.forEach(function(handler) { handler(user); }); } this.handleTip = function (tip) { handlers.tip.forEach(function(handler) { handler(tip); }); } this.handleSubject = function (newS, oldS) { var add = ''; handlers.subject.forEach(function(handler){ add += handler(newS, oldS); }); return add; } this.getName = function () { return name; } this.init = function () { internalSettings.forEach(function (setting) { sys.settings.registerOption(setting); }); externalSettings.forEach(function (setting) { sys.settings.registerOption(setting, true); }); if ('init' in rawData) rawData.init(); } this.getTipOptions = function (u) { if ('getTipOptions' in rawData) return rawData.getTipOptions(u); else return []; } this.update = function (setting) { if (Function.isFunction(handlers.setting)) { handlers.setting(setting); } else if (Function.isFunction(handlers.setting[setting.getName()])) { handlers.setting[setting.getName()](setting); } } !function (that) { var addThis = function (s) { s.addObserver(that) } internalSettings.forEach(addThis); externalSettings.forEach(addThis); }(this); Module[name] = this; } var Message = function (rawData) { if (!rawData['X-BBT-COMPAT']) rawData['X-BBT-COMPAT'] = {}; rawData['X-BBT-COMPAT']['APP#SLOT#'+cb.slot] = { slot : cb.slot, name : _APPNAME, consumed : null } var user = new User(rawData); var time = new Date(); this.getColor = function () { return rawData.c; } this.getBackground = function () { return "background" in rawData ? rawData.background : '#ffffff';; } this.getFont = function () { return rawData.f; } this.getMessage = function () { return rawData.m; } this.isHidden = function () { return "X-Spam" in rawData ? rawData['X-Spam'] : false; } this.getUser = function () { return user; } this.setColor = function (c) { // TODO: check for valid HTML color rawData.c = c; } this.setBackground = function (c) { // TODO: check for valid HTML color rawData.background = c; } this.setFont = function (f) { // TODO: check for valid font rawData.f = f; } this.setMessage = function (m) { rawData.m = m; } this.setHidden = function (h) { rawData['X-Spam'] = !!h; // !! is quick'n'dirty booelan typecast } this.consume = function () { rawData['X-BBT-COMPAT']['APP#SLOT#'+cb.slot].consumed = (arguments.length > 0) ? arguments [0] : (true); } this.getConsumedBy = function () { for (var key in rawData['X-BBT-COMPAT']) { var compatData = rawData['X-BBT-COMPAT'][key]; if (!compatData.consumed) continue; return compatData; } return null; } this.getRaw = function () { return rawData; } this.getTime = function () { return time; } } var Tip = function (rawData) { var amount = rawData.amount; var message = rawData.message; var to = rawData.to_user; // currently unused, we only see tips to the broadcaster anyway. I trust CB in this. var user = new User({ user : rawData.from_user, gender : rawData.from_user_gender, in_fanclub : rawData.from_user_in_fanclub, is_mod : rawData.from_user_is_mod, has_tokens : rawData.from_has_tokens, tipped_recently : rawData.from_user_tipped_recently }); var time = new Date(); this.getAmount = function () { return amount; } this.getMessage = function () { return message; } this.getUser = function () { return user; } this.getTime = function () { return time; } } var User = function () { var tipsLast = {} var tipsTotal = {} var tipsHigh = {} var entered = {} var left = {} var chatLast = {} var ht = { user : null, amount : 0 } new Module('_u', { handlers : { enter : [ function (u) { entered[u.getName().toLowerCase()] = new Date(); } ], leave : [ function (u) { left[u.getName().toLowerCase()] = new Date(); } ], message : [ function (m) { chatLast[m.getUser().getName().toLowerCase()] = m; } ], tip : [ function (t) { var username = t.getUser().getName().toLowerCase(); tipsLast[username] = t; if (!(username in tipsTotal)) { tipsTotal[username] = 0; } tipsTotal[username] += t.getAmount(); if (!(username in tipsHigh) || tipsHigh[username].getAmount() < t.getAmount()) { tipsHigh[username] = t; } } ] } }); return function (rawData) { var name = rawData.user; var gender = (function (g) { switch (g.toLowerCase()) { case 'm' : return User.Gender.MALE; case 'f' : return User.Gender.FEMALE; case 's' : return User.Gender.SHEMALE; case 'c' : return User.Gender.COUPLE; default: sys.log("Invalid gender code found"); return ''; } })(rawData.gender); var fanclub = rawData.in_fanclub; var mod = rawData.is_mod; var token = rawData.has_tokens; var tipper = rawData.tipped_recently; this.getName = function () { return name; } this.getGender = function () { return gender; } this.isFanclub = function () { return fanclub; } this.isMod = function () { return mod; } this.isBroadcaster = function () { return name == cb.room_slug; } this.hasTokens = function () { return token; } this.isHighTipper = function () { return tipper; } this.is = function (color) { if (!(color instanceof User.Color)) color = User.Color.fromName(color); switch (color) { case User.Color.ORANGE: return this.isBroadcaster(); case User.Color.RED: return this.isMod(); case User.Color.GREEN: return this.isFanclub(); case User.Color.CYAN: return this.hasTokens(); case User.Color.BLUE: return this.isHighTipper(); case User.Color.GREY: return true; default: return false; } } this.isOnly = function (color) { if (!(color instanceof User.Color)) color = User.Color.fromName(color); switch (color) { case User.Color.ORANGE: return this.isBroadcaster(); // no additional checks. Doesn't make any sense to check if a broadcaster // has tokens or is a mod, fanclub member or high tipper. case User.Color.RED: return this.isMod() && !this.isBroadcaster() && !this.isFanclub() && !this.hasToken() && !this.isHighTipper(); case User.Color.GREEN: return this.isFanclub() && !this.isBroadcaster() && !this.isMod() && !this.hasToken() && !this.isHighTipper(); case User.Color.CYAN: return this.hasTokens() && !this.isBroadcaster() && !this.isMod() && !this.isFanclub() && !this.isHighTipper(); case User.Color.BLUE: return this.isHighTipper() && !this.isBroadcaster() && !this.isMod() && !this.isFanclub() && !this.hasTokens(); case User.Color.GREY: return !this.hasTokens() && !this.isHighTipper() && !this.isBroadcaster() && !this.isMod() && !this.isFanclub() default: return false; } } this.getColor = function () { if (this.is(User.Color.ORANGE)) return User.Color.ORANGE; if (this.is(User.Color.RED )) return User.Color.RED; if (this.is(User.Color.GREEN )) return User.Color.GREEN; if (this.is(User.Color.BLUE )) return User.Color.BLUE; if (this.is(User.Color.CYAN )) return User.Color.CYAN; return User.Color.GREY; } this.getEnter = function () { var name = this.getName().toLowerCase(); if (name in entered) return entered[name]; return null; } this.getLeave = function () { var name = this.getName().toLowerCase(); if (name in left) return left[name]; return null; } this.getLastChat = function () { var name = this.getName().toLowerCase(); if (name in chatLast) return chatLast[name]; return null; } this.getLastTip = function () { var name = this.getName().toLowerCase(); if (name in tipsLast) return tipsLast[name]; return null; } this.getHighestTip = function () { var name = this.getName().toLowerCase(); if (name in tipsHigh) return tipsHigh[name]; return null; } this.getTipTotal = function () { var name = this.getName().toLowerCase(); if (name in tipsTotal) return tipsTotal[name]; return 0; } this.getLastSeen = function () { var lastSeen = null; if (this.getEnter() > lastSeen) lastSeen = this.getEnter(); if (this.getLeave() > lastSeen) lastSeen = this.getLeave(); if (this.getLastChat() && this.getLastChat().getTime() > lastSeen) lastSeen = this.getLastChat().getTime(); if (this.getLastTip() && this.getLastTip().getTime() > lastSeen ) lastSeen = this.getLastTip().getTime(); return lastSeen; } this.isTipper = function () { return this.getLastTip() != null; } User.Archive.add(this); } }(); User.Archive = new function () { var archive = {} this.add = function (user) { if (user instanceof User) archive[user.getName().toLowerCase()] = user; } this.get = function (name) { if (name instanceof User) name = name.getName(); name = name.toLowerCase(); if (name in archive) return archive[name]; else return null; } this.getAll = function () { return archive.slice(0); // shallow copy instead of reference to prevent archive manipulation } } User.Gender = function (name, code, personal, possessive) { this.getCode = function () { return code; } this.getName = function () { return name; } this.getPersonalPronoun = function () { return personal; } this.getPossessivePronoun = function () { return possessive; } } User.Gender.MALE = new User.Gender('male' , 'm', 'he' , 'his' ); User.Gender.FEMALE = new User.Gender('female' , 'f', 'she' , 'her' ); User.Gender.SHEMALE = new User.Gender('transsexual', 's', '(s)he', 'his/her'); User.Gender.COUPLE = new User.Gender('a couple' , 'c', 'they' , 'their' ); User.Gender.INVALID = new User.Gender('unknown' , '' , 'he' , 'his' ); User.Gender.fromName = function (name) { switch (name.split(/[\s_]/)[0].trim().toLowerCase()) { case 'm' : case 'male' : return User.Gender.MALE; case 'f' : case 'female' : return User.Gender.FEMALE; case 's' : case 'shemale' : case 'trans' : case 'transsexual' : return User.Gender.SHEMALE; case 'a' : case 'c' : case 'couple' : return User.Gender.COUPLE; default : return User.Gender.INVALID; } } User.Color = function (name,code,color) { this.getName = function() {return name }; this.getCode = function() {return code }; this.getColor = function() {return color}; } User.Color.ORANGE = new User.Color('broadcaster' , 'orange', '#DC5500'); User.Color.RED = new User.Color('moderator' , 'red' , '#DC0000'); User.Color.GREEN = new User.Color('fanclub member', 'green' , '#090' ); User.Color.BLUE = new User.Color('high tipper' , 'blue' , '#009' ); User.Color.CYAN = new User.Color('token owner' , 'cyan' , '#69A' ); User.Color.GREY = new User.Color('basic user' , 'grey' , '#494949'); User.Color.INVALID = new User.Color('unknown' , '' , '#000' ); User.Color.fromName = function (name) { switch (name.split(/[\s_]/)[0].trim().toLowerCase()) { case 'broadcasters': case 'broadcaster' : case 'oranges' : case 'orange' : return User.Color.ORANGE; case 'moderators' : case 'moderator' : case 'mods' : case 'mod' : case 'reds' : case 'red' : return User.Color.RED; case 'members' : case 'member' : case 'fanclub' : case 'greens' : case 'green' : return User.Color.GREEN; case 'high' : case 'tippers' : case 'tipper' : case 'darkblues' : case 'darkblue' : case 'bluess' : case 'blues' : case 'blue' : return User.Color.BLUE; case 'tokens' : case 'token' : case 'lightblues' : case 'lightblue' : case 'cyans' : case 'cyan' : return User.Color.CYAN; case 'tokenless' : case 'user' : case 'greys' : case 'grays' : case 'grey' : case 'gray' : case 'all' : return User.Color.GREY; default : return User.Color.INVALID; } } var Setting = function (name, def) { var val = (name in cb.settings) ? cb.settings[name] : (arguments.length > 2) ? arguments [2] : def; var observers = []; this.getValue = function () { return val; } this.getName = function () { return name; } this.getDefault = function () { return def; } this.setValue = function (v) { val = v; this.notify(); return true; } this.getCBObject = function () { return {}; } this.addObserver = function (o) { if ('update' in o && observers.indexOf(o) == -1) { observers.push(o); } } this.removeObserver = function (o) { var index = observers.indexOf(o); if (index != -1) observers.splice(index, 1); } this.notify = function () { var that = this; observers.forEach(function (o) { o.update(that); }); } }; Setting.String = function (name) { // optional params: label, default, required, min, max var label = name; var def = ''; var req = true; var min = 0; var max = 255; if (arguments.length > 1) label = arguments[1]; if (arguments.length > 2) def = arguments[2]; if (arguments.length > 3) req = arguments[3]; if (arguments.length > 4) min = arguments[4]; if (arguments.length > 5) max = arguments[5]; var val = def; Setting.call(this, name, def); this.setValue = function (v) { v = v.toString(); if (v.length > max || v.length < min) { return false; } else { val = v; this.notify(); return true; } } this.getValue = function () { return val; } this.getCBObject = function () { return { name : name, type : 'str', label : label, required : req, defaultValue : def, minLength : min, maxLength : max } } if (name in cb.settings) this.setValue(cb.settings[name]); } Setting.Float = function (name) { // optional params: label, default, required, min, max var label = name; var def = 0; var req = true; var min = 0; var max = 255; if (arguments.length > 1) label = arguments[1]; if (arguments.length > 2) def = arguments[2]; if (arguments.length > 3) req = arguments[3]; if (arguments.length > 4) min = arguments[4]; if (arguments.length > 5) max = arguments[5]; var val = def; Setting.call(this, name, def); this.setValue = function (v) { v = parseFloat(v.toString().replace(',', '.')); if (isNaN(v) || v > max || v < min) { return false; } else { val = v; this.notify(); return true; } } this.getValue = function () { return val; } this.getCBObject = function () { return { name : name, type : 'str', label : label, required : req, defaultValue : def, minLength : 1 } } if (name in cb.settings) { // CB does not checks for floats, not implemented. so invalid values at load time are possible. var returnValue = this.setValue(cb.settings[name]); if (!returnValue) { cb.sendNotice('Invalid value for ' + (label != name ? '"' + label + '" (' + name + ')' : name) + ' found. ' + 'Please use "/set ' + name + ' VALUE" to set a new value (replace "VALUE" by the new value). ' + 'Valid values are any decimal nubmer between ' + min + ' and ' + max + '.', cb.room_slug, '#e99', '#300'); } } } Setting.Int = function (name) { // optional params: label, default, required, min, max var label = name; var def = 0; var req = true; var min = 0; var max = 999; if (arguments.length > 1) label = arguments[1]; if (arguments.length > 2) def = arguments[2]; if (arguments.length > 3) req = arguments[3]; if (arguments.length > 4) min = arguments[4]; if (arguments.length > 5) max = arguments[5]; var val = def; Setting.call(this, name, def); this.setValue = function (v) { v = parseInt(v); if(isNaN(v) || v > max || v < min) { return false; } else { val = v; this.notify(); return true; } } this.getValue = function () { return val; } this.getCBObject = function () { return { name : name, type : 'int', label : label, required : req, defaultValue : def, minValue : min, maxValue : max } } if (name in cb.settings) this.setValue(cb.settings[name]); } Setting.Choice = function (name, options) { // optional params: label, default, required var label = name; var def = options[0]; var req = true; var opt = options if (arguments.length > 2) label = arguments[2]; if (arguments.length > 3) def = arguments[3]; if (arguments.length > 4) req = arguments[4]; var val = def; Setting.call(this, name, def); this.addOption = function (o) { if (opt.indexOf(o) == -1) opt.push(o); } this.removeOption = function (o) { var index = opt.indexOf(o); if (index != -1) opt.splice(index,1); } this.setValue = function (v) { if (opt.indexOf(v) == -1) return false; val = v; this.notify(); return true; } this.getValue = function () { return val; } this.addOption(def); this.getCBObject = function () { var o = { name : name, type : 'choice', label : label, required : req, defaultValue : def } for (var i = 0 ; i < opt.length ; i++) { o['choice'+(i+1)] = opt[i]; } return o; } if (name in cb.settings) this.setValue(cb.settings[name]); } Setting.Bool = function (name) { // optional params: label, default, required var label = name; var def = false; var req = true; if (arguments.length > 1) label = arguments[1]; if (arguments.length > 2) def = arguments[2]; if (arguments.length > 3) req = arguments[3]; var val = def; Setting.call(this, name, def); this.setValue = function (v) { val = ['false', '0', 'off', 'no', 'n', 'f', 0, false].indexOf(v) == -1 this.notify(); return true; } this.getValue = function () { return val; } this.getCBObject = function () { return o = { name : name, type : 'choice', label : label, required : req, defaultValue : def ? 'yes' : 'no', choice1 : 'yes', choice2 : 'no' }; } if (name in cb.settings) this.setValue(cb.settings[name]); } var sys = new function () { var modules = {}; var topic = ''; this.isApp = function () { return cb.slot == 0; } this.setSubject = function () { if (!this.isApp()) { this.debug('Running as a bot. setSubject is not available.'); return; } var oldTopic = topic; var t = topic = (arguments.length > 0) ? arguments[0] : topic; for (var moduleName in modules) { var add = modules[moduleName].handleSubject(topic, oldTopic); if (add) t+= ' ' + add; } cb.changeRoomSubject(t); this.log('Subject changed to "' + t + '" (was "' + oldTopic + '")'); } this.getSubject = function () { if (!this.isApp()) { this.debug('Running as a bot. getSubject is not available.'); return ''; } return topic; } this.loadModule = function (module) { if (!(module instanceof Module)) { if (module in Module) module = Module[module]; else return false; } modules[module.getName()] = module; module.init(); return true; } this.unloadModule = function (module) { if (module instanceof Module) { module = Module.getName(); } if (module == null || !(module in modules)) { return false; } delete modules[module]; return true; } //NOTE: messages parsed by parseMessage are not visible in chat or passed to other bots. this.parseMessage = function (message) { // optional: user, color, background, font. if (message instanceof Message){ message = message.getRaw(); } else if (message instanceof Object && !(message instanceof String)) { // most likely raw CB message, just pass along. } else { message = { m : message.toString(), c : arguments.length > 2 ? arguments[2] : User.Color.GREY.getColor(), f : arguments.length > 4 ? arguments[4] : 'default', }; if (arguments.length > 3) m.background = arguments[3]; var user = arguments.length > 1 ? (arguments[1] instanceof User ? arguments[1] : User.Archive.get(arguments[1]) ) : null; if (user) { message.user = user.getName(); message.gender = user.getGender().getCode(); message.in_fanclub = user.isFanclub(); message.has_tokens = user.hasTokens(); message.is_mod = user.isMod(); message.tipped_recently = user.isHighTipper(); } else { message.user = arguments.length > 1 ? arguments[1] : cb.rooms_slug; message.gender = ''; message.in_fanclub = false; message.has_tokens = false; message.is_mod = false; message.tipped_recently = false; } } cb._translate_handler(message); } this.log = function (message) { cb.log (_APPNAME + ': ' + message); } this.debug = function (message) { if (sys.settings.get('debug_mode').getValue()) this.log(message); } this.init = function () { cb.onEnter(function (u) { var user = new User(u); for (var moduleName in modules) { modules[moduleName].handleEnter(user); } }); cb.onLeave(function (u) { var user = new User(u); for (var moduleName in modules) { modules[moduleName].handleLeave(user); } }); cb.onMessage(function (m) { var message = new Message(m); for (var moduleName in modules) { modules[moduleName].handleMessage(message); } return m; }); cb.onTip(function (t) { var tip = new Tip(t); for (var moduleName in modules) { modules[moduleName].handleTip(tip); } }); cb.tipOptions(function (u) { var options = {}; var moduleCount = 0; for (var moduleName in modules) { options[moduleName] = modules[moduleName].getTipOptions(u); if (options[moduleName].length > 0) moduleCount++; } if (moduleCount == 0) return; var outputObject = {label : 'Select', options : []}; for (var moduleName in options) { options[moduleName].forEach(function (option) { outputObject.options.push({label: (moduleCount > 1 ? '[' + moduleName + ']: ' : '') + option}); }); } return outputObject; }); if (this.isApp()) { cb.onDrawPanel(this.panel.draw); } this.loadModule(new Module('_s', { internalSettings : [ new Setting('security_bg', '#800'), new Setting('security_fg', '#fff'), new Setting.Choice('security_w', ['bold', 'bolder', 'normal']), new Setting('success_bg', '#9e9'), new Setting('success_fg', '#030'), new Setting.Choice('success_w', ['normal', 'bolder', 'bold']), new Setting('warning_bg', '#fc3'), new Setting('warning_fg', '#630'), new Setting.Choice('warning_w', ['normal', 'bolder', 'bold']), new Setting('failure_bg', '#e99'), new Setting('failure_fg', '#300'), new Setting.Choice('failure_w', ['normal', 'bolder', 'bold']) ] })); this.loadModule('_u'); if (this.isApp()) { this.loadModule(new Module('_app', { externalSettings : [ new Setting.String("subject", "Room Subject", cb.room_slug + "'s Room", true), new Setting.Bool("security_topic_mod", "Mods can change room subject", false, false) ], commands : { topic : function (p,c,m){ if (!(m.getUser().isBroadcaster()) && !(m.getUser().isMod() && sys.settings.get('security_topic_mod').getValue())) { return false; } sys.setSubject(p.join(' ')); return true; } } })); this.setSubject(this.settings.get('subject').getValue()); } } }(); sys.settings = new function () { var s = {}; this.registerOption = function (option) { // optinal parameters: registerToCB (default false)) var name = option.getName(); s[name] = option; if (arguments.length > 1 && arguments[1]) { if (!Array.isArray(cb.settings_choices)) cb.settings_choices = []; var found = false; for (var i = 0 ; i < cb.settings_choices.length ; i++) { if (cb.settings_choices[i].name == name) { found=true; break; } }; if (!found) cb.settings_choices.push(option.getCBObject()); } } this.get = function (name) { if (!(name in s)) { s[name] = new Setting(name, ''); } return s[name]; } }(); sys.panel = new function () { var PanelContent = function () { var label = ""; var value = ""; var type = 1; var setLabel = function (l) { if (l == null) { type = 1; label = ''; } else { type = 2; label = l; } } var setValue = function (v) { if (v == null) v = ''; value = v } this.getType = function () { if (!sys.isApp()) { sys.debug('Running as a bot. App panel is not available.'); return; } return type; } this.getLabel = function () { if (!sys.isApp()) { sys.debug('Running as a bot. App panel is not available.'); return; } return label; } this.getValue = function () { if (!sys.isApp()) { sys.debug('Running as a bot. App panel is not available.'); return; } return value; } this.setLabel = function (l) { if (!sys.isApp()) { sys.debug('Running as a bot. App panel is not available.'); return; } setLabel(l); if (arguments.length > 1 ? arguments[1] : true) sys.panel.repaint(); } this.clearLabel = function () { if (!sys.isApp()) { sys.debug('Running as a bot. App panel is not available.'); return; } this.setLabel(null, arguments.length > 0 ? arguments[0] : true); } this.setValue = function (v) { if (!sys.isApp()) { sys.debug('Running as a bot. App panel is not available.'); return; } setValue(v); if (arguments.length > 1 ? arguments[1] : true) sys.panel.repaint(); } this.setData = function (data) { if (!sys.isApp()) { sys.debug('Running as a bot. App panel is not available.'); return; } if (Array.isArray(data)) { switch (data.length) { case 0: setValue(""); setLabel(null); break; case 1: setValue(data[0]); setLabel(null); break; default: setValue(data[1]); setLabel(data[0]); break; } } else { setValue(data); setLabel(null); } if (arguments.length > 1 ? arguments[1] : true) sys.panel.repaint(); return; } } this[0] = new PanelContent(); this[1] = new PanelContent(); this[2] = new PanelContent(); this.draw = (function (that) { // CB assigns the cb object to this when calling callbacks. So we need a copy. return function () { var panelConfig = 0; for (var i = 0 ; i < 3 ; i++) { panelConfig += (that[i].getType() == 2 ? 1 : 0) << i; } switch (panelConfig) { case 0: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_11_21_31"'); return { template : '3_rows_11_21_31', row1_value : that[0].getValue(), row2_value : that[1].getValue(), row3_value : that[2].getValue() } case 1: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_12_21_31"'); return { template : '3_rows_12_21_31', row1_label : that[0].getLabel(), row1_value : that[0].getValue(), row2_value : that[1].getValue(), row3_value : that[2].getValue() } case 2: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_12_22_31"'); return { template : '3_rows_12_22_31', row1_label : that[0].getValue(), row1_value : '', row2_label : that[1].getLabel(), row2_value : that[1].getValue(), row3_value : that[2].getValue() } case 3: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_12_22_31"'); return { template : '3_rows_12_22_31', row1_label : that[0].getLabel(), row1_value : that[0].getValue(), row2_label : that[1].getLabel(), row2_value : that[1].getValue(), row3_value : that[2].getValue() } case 4: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_of_labels"'); return { template : '3_rows_of_labels', row1_label : that[0].getValue(), row1_value : '', row2_label : that[1].getValue(), row2_value : '', row3_label : that[2].getLabel(), row3_value : that[2].getValue() } case 5: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_of_labels"'); return { template : '3_rows_of_labels', row1_label : that[0].getLabel(), row1_value : that[0].getValue(), row2_label : that[1].getValue(), row2_value : '', row3_label : that[2].getLabel(), row3_value : that[2].getValue() } case 6: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_of_labels"'); return { template : '3_rows_of_labels', row1_label : that[0].getValue(), row1_value : '', row2_label : that[1].getLabel(), row2_value : that[1].getValue(), row3_label : that[2].getLabel(), row3_value : that[2].getValue() } case 7: sys.log("Re-Drawing Panel. Configuration: " + panelConfig + ', using template "3_rows_of_labels"'); return { template : '3_rows_of_labels', row1_label : that[0].getLabel(), row1_value : that[0].getValue(), row2_label : that[1].getLabel(), row2_value : that[1].getValue(), row3_label : that[2].getLabel(), row3_value : that[2].getValue() } } }; })(this); this.repaint = function () { sys.log('Panel refresh called'); cb.drawPanel(); } }(); new Module('allCaps', { externalSettings : [ new Setting.Bool("security_toggleAllCaps_mod", "[Permissions]: Mods can turn all caps messages on/off", true, false), new Setting.Choice("allcaps_mode", ['no', 'yes', 'everybody'], "[All-Caps Messages]: Convert messages in all-caps to lowercase", 'yes') ], handlers : { message : [ function (m) { if (sys.settings.get('allcaps_mode').getValue() == 'no') return; if ((m.getUser().isMod() || m.getUser().isBroadcaster()) && sys.settings.get('allcaps_mode').getValue() != 'everybody') return; var message = m.getMessage(); if (/^>?[:;xXB]'?-?'?[PDXC\)\()\\\/]$/.test(message)) return; // exclude common emoticons if (/^:[\w-]+$/.test(message)) return; // exclude grapic only messages if (message.toUpperCase() == message) { m.setMessage(message.toLowerCase()); } } ] }, commands : { allcaps : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_toggleAllCaps_')) { return false; } if (p.length == 0) { var mode = sys.settings.get('allcaps_mode').getValue(); if (mode == 'everybody') mode = 'on for everybody'; if (mode == 'yes') mode = 'on for regular users'; if (mode == 'no') mode = 'off'; cb.sendNotice('All-Caps to lowercase message conversion is ' + mode, m.getUser().getName()); return true; } switch (p.shift()) { case 'false': case '0': case 'off': case 'no': case 'n': case 'f': sys.settings.get('allcaps_mode').setValue('no'); cb.sendNotice("'All-Caps to lowercase message conversion turned off", m.getUser().getName(), sys.settings.get('success_bg').getValue(), sys.settings.get('success_fg').getValue(), sys.settings.get('success_w').getValue()); return true; case 'all': case 'everyone': case 'everybody': sys.settings.get('allcaps_mode').setValue('everybody'); cb.sendNotice("'All-Caps to lowercase message conversion turned on for everybody", m.getUser().getName(), sys.settings.get('success_bg').getValue(), sys.settings.get('success_fg').getValue(), sys.settings.get('success_w').getValue()); return true; default: sys.settings.get('allcaps_mode').setValue('yes'); cb.sendNotice("'All-Caps to lowercase message conversion turned on for regular users", m.getUser().getName(), sys.settings.get('success_bg').getValue(), sys.settings.get('success_fg').getValue(), sys.settings.get('success_w').getValue()); return true; } } } }); new Module('noGraphics', { externalSettings : [ new Setting.Bool('security_graphics_mod', '01 - [Permissions]: Mods can change graphic settings' , true), new Setting.Bool('graphics_mod' , '02 - [Graphics]: Mods can use graphics in chat' , true), new Setting.Bool('graphics_fanclub' , '03 - [Graphics]: Fanclub members can use graphics in chat' , true), new Setting.Bool('graphics_token' , '04 - [Graphics]: Users with tokens can use graphics in chat', true), new Setting.Bool('graphics_grey' , '05 - [Graphics]: Greys can use graphics in chat' , false) ], handlers : { message : [ function (m) { if (!utility.securityCheck(m.getUser(), ['mod','fanclub','token','grey'], 'graphics_')) { var message = m.getMessage(); message = message.replace(/:/g, ':\u200B'); m.setMessage(message); } } ] }, commands : { graphics : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_graphics_')) { return false; } var type = p.shift() || ''; var setting = null; var name = ''; switch (type) { case 'moderators' : case 'moderator' : case 'mods' : case 'mod' : case 'reds' : case 'red' : setting = sys.settings.get('graphics_mod'); name = 'moderators'; break; case 'members' : case 'member' : case 'fanclub' : case 'greens' : case 'green' : setting = sys.settings.get('graphics_fanclub'); name = 'fanclub members'; break; case 'tokens' : case 'token' : case 'lightblues' : case 'lightblue' : case 'cyans' : case 'cyan' : setting = sys.settings.get('graphics_token'); name = 'users with tokens'; break; case 'tokenless' : case 'user' : case 'greys' : case 'grays' : case 'grey' : case 'gray' : case 'all' : setting = sys.settings.get('graphics_grey'); name = 'greys'; break; } if (!setting) { var message = 'Graphic settings:\n'; message += 'Moderators: '; message += (sys.settings.get('graphics_mod' ).getValue() ? 'on' : 'off') + '\n'; message += 'Fanclub Members: '; message += (sys.settings.get('graphics_fanclub').getValue() ? 'on' : 'off') + '\n'; message += 'Users with tokens: '; message += (sys.settings.get('graphics_token' ).getValue() ? 'on' : 'off') + '\n'; message += 'Greys: '; message += (sys.settings.get('graphics_grey' ).getValue() ? 'on' : 'off'); cb.sendNotice(message, m.getUser().getName()); return true; } if (p.length < 1) { var message = 'Graphic settings for ' + name + ': '; message += setting.getValue() ? 'on' : 'off'; cb.sendNotice(message, m.getUser().getName()); return true; } var value = p.shift(); if(setting.setValue(value)) { var message = 'Graphic settings for ' + name + ' have been set to: '; message += setting.getValue() ? 'on' : 'off'; cb.sendNotice(message, m.getUser().getName(), sys.settings.get('success_bg').getValue(), sys.settings.get('success_fg').getValue(), sys.settings.get('success_w').getValue()); } else { var message = '"' + value + '" is not a valid value. Use one of on/true/1 or off/false/0'; cb.sendNotice(message, m.getUser().getName(), sys.settings.get('failure_bg').getValue(), sys.settings.get('failure_fg').getValue(), sys.settings.get('failure_w').getValue()); } return true; } } }); new Module('wordCensor', new function () { var censoredWords = Object.create(null); var parseCensoredWords = function (string) { var censoredWords = Object.create(null); string.split(/\s*[,;]\s*/).forEach(function(censoredWord){ if (censoredWord) { censoredWords[censoredWord.toLowerCase()] = "".padL(censoredWord.length, '*'); } }); return censoredWords; } var silencedUsers = Object.create(null); var silence = function (user) { if (user instanceof User) user = user.getName(); silencedUsers[user.toLowerCase()] = true; } var unsilence = function (user) { if (user instanceof User) user = user.getName(); delete silencedUsers[user.toLowerCase()]; } var isSilenced = function (user) { if (user instanceof User) user = user.getName(); return (user.toLowerCase() in silencedUsers); } var sendChange = function (message) { // optional param: include mods (default: security_wordCensor_mod) var mods = arguments.length > 1 ? arguments[1] : sys.settings.get('security_wordCensor_mod').getValue(); var bg = sys.settings.get ('wordCensor_notice_bg').getValue(); var fg = sys.settings.get ('wordCensor_notice_fg').getValue(); var w = sys.settings.get ('wordCensor_notice_w' ).getValue(); cb.sendNotice(message, cb.room_slug, bg, fg, w); if (mods) { cb.sendNotice(message, '', bg, fg, w, 'red'); } } var sendSuccess = function (message, user) { if (user instanceof User) user = user.getName(); var bg = sys.settings.get ('success_bg').getValue(); var fg = sys.settings.get ('success_fg').getValue(); var w = sys.settings.get ('success_w' ).getValue(); cb.sendNotice(message, user, bg, fg, w); } var sendWarning = function (message, user) { if (user instanceof User) user = user.getName(); var bg = sys.settings.get ('warning_bg').getValue(); var fg = sys.settings.get ('warning_fg').getValue(); var w = sys.settings.get ('warning_w' ).getValue(); cb.sendNotice(message, user, bg, fg, w); } var sendFailure = function (message, user) { if (user instanceof User) user = user.getName(); var bg = sys.settings.get ('failure_bg').getValue(); var fg = sys.settings.get ('failure_fg').getValue(); var w = sys.settings.get ('failure_w' ).getValue(); cb.sendNotice(message, user, bg, fg, w); } var sendNotice = function (message, user) { if (user instanceof User) user = user.getName(); var bg = sys.settings.get ('wordCensor_notice_bg').getValue(); var fg = sys.settings.get ('wordCensor_notice_fg').getValue(); var w = sys.settings.get ('wordCensor_notice_w' ).getValue(); cb.sendNotice(message, user, bg, fg, w); } this.internalSettings = [ new Setting.String('wordCensor_notice_fg', '[Censored Words]: default text color' , '#800' , true), new Setting.String('wordCensor_notice_bg', '[Censored Words]: default text highlight', '#eef' , true), new Setting.Choice('wordCensor_notice_w' , ['normal', 'bolder', 'bold'], '[Censored Words]: default text weight' , 'normal', true) ] this.externalSettings = [ new Setting.String('wordCensor_words', '[Censored Words]: Words to Censor. Spaces in censored terms are allowed, separate terms by a semicolon ("example;foo bar;test")',"delete space;c2c;c 2 c;cam2cam;cam 2 cam"), new Setting.Bool ('wordCensor_fullOnly', '[Censored Words]: Ban only full words ("butt" is censored, but "buttstuff" is not)', true), new Setting.Bool ('wordCensor_remove' , '[Censored Words]: Hide messages that contain censored words. Otherwise, censored words will be starred out.', false), new Setting.Bool ('wordCensor_silence' , '[Censored Words]: Silence users after a word in one of their messages has been censored', true), new Setting.Choice('wordCensor_notify' , ['none', 'notice', 'original message'], '[Censored Words]: Choose the notification type the broadcaster gets if a message was censored', 'original message'), new Setting.Choice('wordCensor_notify_mod' , ['none', 'notice', 'original message'], '[Censored Words]: Choose the notification type moderators get if a message was censored' , 'original message'), new Setting.Bool ('wordCensor_for_broadcaster', '[Censored Words]: Censor words from the broadcaster', false), new Setting.Bool ('wordCensor_for_mod' , '[Censored Words]: Censor words from mods', false), new Setting.Bool ('wordCensor_for_fanclub' , '[Censored Words]: Censor words from fanclub members', false), new Setting.Bool ('wordCensor_for_tokens' , '[Censored Words]: Censor words from users with tokens', false), new Setting.Bool ('security_wordCensor_mod' , '[Permissions]: Moderators can change censored words settings. This includes listing all censored terms!', true) ] this.handlers = { message : [ function (m) { if (isSilenced(m.getUser())) return; var checks = ['broadcaster', 'mod', 'fanclub', 'tokens']; for (var i = 0 ; i < checks.length ; i++) { if (m.getUser().is(checks[i]) && !sys.settings.get('wordCensor_for_' + checks[i]).getValue()) { return; } } var original = m.getMessage(); var replaced = original.mapReplace(censoredWords, sys.settings.get('wordCensor_fullOnly').getValue()); if (original != replaced) { var shortNotice = ""; var fullNotice = ""; if (sys.settings.get('wordCensor_remove').getValue()) { m.setHidden(true); shortNotice += m.getUser().getName() + '\'s message was removed because it included censored words.'; fullNotice += 'Message was removed:\n' + m.getUser().getName() + ': ' + original; } else { m.setMessage(replaced); shortNotice += m.getUser().getName() + '\'s message was censored because it included censored words.'; fullNotice += 'Original Message:\n' + m.getUser().getName() + ': ' + original; } if (sys.settings.get('wordCensor_silence').getValue()) { silence(m.getUser()); shortNotice += ' The user has been silenced.'; fullNotice += '\nThe user has been silenced.'; } var bg = sys.settings.get('wordCensor_notice_bg').getValue(); var fg = sys.settings.get('wordCensor_notice_fg').getValue(); var w = sys.settings.get('wordCensor_notice_w' ).getValue(); switch (sys.settings.get('wordCensor_notify').getValue()) { case 'notice': cb.sendNotice(shortNotice, cb.room_slug, bg, fg, w); break; case 'original message': cb.sendNotice(fullNotice, cb.room_slug, bg, fg, w); break; } switch (sys.settings.get('wordCensor_notify_mod').getValue()) { case 'notice': cb.sendNotice(shortNotice, '', bg, fg, w, 'red'); break; case 'original message': cb.sendNotice(fullNotice, '', bg, fg, w, 'red'); break; } } } ] } this.filters = [ function (m) { return isSilenced(m.getUser()) ? false : null; } ] this.commands = { censor : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var search = p.join(' '); if (!search) { sendFailure("No word to be censored has been specified. Nothing changed.", m.getUser()); return true; } if (search in censoredWords) { sendFailure("\"" + search + "\" is already on the list of censored words. Nothing to add.", m.getUser()); return true; } censoredWords[search] = "".padL(search.length, '*'); sendChange("\"" + search + "\" was added to the list of censored words."); return true; }, uncensor : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var search = p.join(' '); if (!search) { sendFailure("No word to uncensor has been specified. Nothing changed.", m.getUser()); return true; } if (!(search in censoredWords)) { sendFailure("\"" + search + "\" is not on the list of censored words. Nothing to remove.", m.getUser()); return true; } delete censoredWords[search]; sendChange("\"" + search + "\" was removed from the list of censored words."); return true; }, list : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var message = 'censored words: \n----------\n'; for (var b in censoredWords) { message += b + "\n"; } message += '----------'; sendNotice(message, m.getUser()); return true; }, censorship : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var color = p.shift() || ''; var settingName = ''; var groupName = ''; var value = p.shift(); switch(User.Color.fromName(color)) { case User.Color.ORANGE: settingName = 'wordCensor_for_broadcaster'; groupName = 'the broadcaster'; break; case User.Color.RED: settingName = 'wordCensor_for_mod'; groupName = 'moderators'; break; case User.Color.GREEN: settingName = 'wordCensor_for_fanclub'; groupName = 'fanclub members'; break; case User.Color.CYAN: settingName = 'wordCensor_for_tokens'; groupName = 'users with tokens'; break; } if (settingName) { if (value === void 0) { var status = sys.settings.get(settingName).getValue() ? 'on' : 'off'; sendNotice('Censorship for ' + groupName + ' is "' + status + '".', m.getUser()); return true; } var returnVal = sys.settings.get(settingName).setValue(value); var status = sys.settings.get(settingName).getValue() ? 'on' : 'off'; if (returnVal) { sendChange('Censorship for ' + groupName + ' has been turned "' + status + '".'); } else { sendFailure(value + ' is not a valid value. Use one of on/true/1 or off/false/0', m.getUser()); } } else { sendFailure('No group found. Specify "broadcaster" , "mods", "fanclub" or "tokens" to see or change censorship settings.', m.getUser()); } return true; }, notifications : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var settingName = ''; var groupName = ''; var group = p.shift() || ""; switch(User.Color.fromName(group)) { case User.Color.ORANGE: settingName = 'wordCensor_notify'; groupName = 'the broadcaster'; break; case User.Color.RED: settingName = 'wordCensor_notify_mod'; groupName = 'moderators'; break; } if (settingName) { var value = p.shift() || ""; switch (value) { case 'off': case 'none': case '0': value = 'none'; break; case 'short': case 'notice': value = 'notice'; break; case 'long': case 'original': value = 'original message'; break; default: sendNotice('Notifications of censored words for ' + groupName + ' is set to "' + sys.settings.get(settingName).getValue() + '".', m.getUser()); return true; } var returnVal = sys.settings.get(settingName).setValue(value); var status = sys.settings.get(settingName).getValue(); if (returnVal) { sendChange('Notifications of censored words for ' + groupName + ' have been changed to "' + status + '".', groupName == 'moderators'); } else { sendFailure(value + ' is not a valid value. Use one of none/off/0, short/notice or long/original', m.getUser()); } } else { sendFailure('No group found. Specify "broadcaster" or "mods" to see or change notifications settings.', m.getUser()); } return true; }, silence : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var user = p.shift(); if (!user) { sendFailure("No username specified.", m.getUser()); return true; } silence(user); sendChange("User " + user + " was silenced.", true); if (!User.Archive.get(user) && user != cb.room_slug) { sendWarning("The user has not been seen in this room yet. Are you sure you spelled the name correctly?", m.getUser()); } return true; }, unsilence : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var user = p.shift(); if (!user) { sendFailure("No username specified.", m.getUser()); return true; } unsilence(user); sendChange("User " + user + " was unsilenced.", true); if (!User.Archive.get(user) && user != cb.room_slug) { sendWarning("The user has not been seen in this room yet. Are you sure you spelled the name correctly?", m.getUser()); } return true; }, autosilence : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var value = p.shift(); if (value === void 0) { value = sys.settings.get('wordCensor_silence').getValue() ? 'on' : 'off'; sendNotice('Autosilence of users who used censored words is ' + value, m.getUser()); } else { var returnVal = sys.settings.get('wordCensor_silence').setValue(value); value = sys.settings.get('wordCensor_silence').getValue() ? 'on' : 'off'; if (returnVal) { sendChange('Autosilence of users who used censored words was switched ' + value); } else { sendFailure(value + ' is not a valid value. Use one of on/true/1 or off/false/0', m.getUser()); } } return true; }, autoremove : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_wordCensor_')) { return false; } var value = p.shift(); if (value === void 0) { value = sys.settings.get('wordCensor_remove').getValue() ? 'on' : 'off'; sendNotice('Removal of messages containing censored words is ' + value, m.getUser()); } else { var returnVal = sys.settings.get('wordCensor_remove').setValue(value); value = sys.settings.get('wordCensor_remove').getValue() ? 'on' : 'off'; if (returnVal) { sendChange('Removal of messages containing censored words was switched ' + value); } else { sendFailure(value + ' is not a valid value. Use one of on/true/1 or off/false/0', m.getUser()); } } return true; } } this.init = function () { censoredWords = parseCensoredWords(sys.settings.get('wordCensor_words').getValue()); } }); new Module ('control', { externalSettings : [ new Setting.Bool("security_eval_mod", "[Permissions]: Mods have full control over the app", true, true) ], commands : { set : function(p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_eval_')) { return false; } var name = p.shift(); var value = p.join(' '); var returnVal = system.settings.get(name).setValue(value); if (returnVal) { cb.sendNotice('Variable "' + name + '" has been set to "' + value + '".', m.getUser().getName(), system.settings.get ('success_bg').getValue(), system.settings.get ('success_fg').getValue(), system.settings.get ('success_w').getValue()); } else { cb.sendNotice(value + ' is not a valid value for ' + name + '.', m.getUser().getName(), system.settings.get ('failure_bg').getValue(), system.settings.get ('failure_fg').getValue(), system.settings.get ('failure_w').getValue()); } return true; }, get : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_eval_')) { return false; } var name = p.shift(); var value = system.settings.get(name).getValue(); cb.sendNotice('Variable "' + name + '" is "' + value + '".', m.getUser().getName()); return true; }, load : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_eval_')) { return false; } var module = p.shift(); if(system.loadModule(module)) { cb.sendNotice('Module "' + module + '" successfully loaded.', m.getUser().getName(), system.settings.get ('success_bg').getValue(), system.settings.get ('success_fg').getValue(), system.settings.get ('success_w').getValue()); } else { cb.sendNotice('Module "' + module + '" not found.', m.getUser().getName(), system.settings.get ('failure_bg').getValue(), system.settings.get ('failure_fg').getValue(), system.settings.get ('failure_w').getValue()); } return true; }, unload : function (p,c,m) { if (!utility.securityCheck(m.getUser(), ['mod'], 'security_eval_')) { return false; } var module = p.shift(); if(system.unloadModule(module)) { cb.sendNotice('Module "' + module + '" successfully unloaded.', m.getUser().getName(), system.settings.get ('success_bg').getValue(), system.settings.get ('success_fg').getValue(), system.settings.get ('success_w').getValue()); } else { cb.sendNotice('Module "' + module + '" was not loaded.', m.getUser().getName(), system.settings.get ('failure_bg').getValue(), system.settings.get ('failure_fg').getValue(), system.settings.get ('failure_w').getValue()); } return true; } } }); new Module('whois', new function () { this.commands = { whoami : function (p,c,m) { p.unshift(m.getUser().getName()); return this.whois(p,c,m); }, whois : function (p,c,m) { var caller = m.getUser().getName(); if (p.length == 0) { cb.sendNotice("No target user specified. If you want info for yourself, please use /whoami", caller, system.settings.get('failure_bg').getValue(), system.settings.get('failure_fg').getValue(), system.settings.get('failure_w').getValue()); return true; } var name = p.shift().toLowerCase(); var user; if (name == caller.toLowerCase()) { user = m.getUser(); } else { user = User.Archive.get(name); if (!user) { cb.sendNotice('----\nUser "' + name + '" was not active after the app started.\n----', caller); return true; } } name = user.getName(); // reload name for correct case var color = user.getColor(); var colors = (function () { var colors = []; for (var currentColor in User.Color) { currentColor = User.Color[currentColor]; if (!(currentColor instanceof User.Color)) continue; if (currentColor != color && user.is(currentColor)) colors.push(currentColor); } return colors; })(); var active = user.getLastSeen(); var gender = user.getGender(); var he = c == 'whoami' ? 'you' : gender.getPersonalPronoun(); var his = c == 'whoami' ? 'your' : gender.getPossessivePronoun(); var is = gender == User.Gender.COUPLE || c == 'whoami' ? ' are' : ' is'; var has = gender == User.Gender.COUPLE || c == 'whoami' ? ' have' : ' has'; var info = '----\n'; if (c == 'whoami') { info += (he + ' ' + is + ' ' + name + '.\nYou').capitalize(); } else { info += name; } info += ' ' + is + ' ' + gender.getName() + '.\n'; info += (his + ' primary status is ' + color.getName() + ' (' + color.getCode() + ')\n').capitalize(); if (colors.length) { info += (he + ' ' + is + ' also ').capitalize(); for (var i = 0 ; i < colors.length ; i++) { info += colors[i].getName() + ' (' + colors[i].getCode() + ')'; if (i+3 <= colors.length) info+= ', '; if (i+2 == colors.length) info+= ' and '; } info += '\n'; } if (user.getEnter()) { info += (he + ' entered ' + utility.getTimeDifference(user.getEnter()) + ' ago.\n').capitalize(); } else { info += (he + ' ' + has + ' already been in this room when the app started.\n').capitalize(); } if (user.getLastChat()) { info += (he + ' sent ' + his + ' last chat message ' + utility.getTimeDifference(user.getLastChat().getTime()) + ' ago.\n').capitalize(); } else { info += (he + ' ' + has + 'n\'t sent any chat messages yet.\n').capitalize(); } if (user.getLastTip()) { info += (his + ' last tip in this room was ' + user.getLastTip().getAmount() + ' tokens, ' + utility.getTimeDifference(user.getLastTip().getTime()) + ' ago.\n').capitalize(); info += (he + ' tipped ' + user.getTipTotal() + ' tokens since the app started.\n').capitalize(); info += (his + ' highest tip was ' + user.getHighestTip().getAmount() + ' tokens, ' + utility.getTimeDifference(user.getHighestTip().getTime()) + ' ago.\n').capitalize(); } else { info += (he + ' ' + has + ' not tipped in this room yet.\n').capitalize(); } if (user.getLeave() > user.getEnter()) { info += (he + ' left this room ' + utility.getTimeDifference(user.getLeave()) + ' ago.\n').capitalize(); } info += '----'; cb.sendNotice(info, caller); return true; } } }); sys.init(); sys.loadModule('allCaps'); sys.loadModule('noGraphics'); sys.loadModule('wordCensor'); sys.loadModule('whois'); sys.loadModule('control');
© Copyright Chaturbate 2011- 2024. All Rights Reserved.