Bots Home
|
Create an App
StatsBot
Author:
entomy
Description
Source Code
Launch Bot
Current Users
Created by:
Entomy
/** * Provides aliases for emblem emotes */ var emblems; /** * Provides aliases for emblem emotes */ (function (emblems) { "use strict"; emblems.arrow = " :arrow16 "; emblems.ballot = " :ballot16 "; emblems.bb8 = " :miniBB-8 "; emblems.blank = " :blank16 "; emblems.bronzemedal = " :bronzemedal16 "; emblems.crown = " :crown16 "; emblems.gavel = " :gavel16 "; emblems.goldmedal = " :goldmedal16 "; emblems.hitachi = " :hitachi16 "; emblems.notice = " :notice16 "; emblems.silvermedal = " :silvermedal16 "; emblems.song = " :song16 "; emblems.timer = " :timer16 "; emblems.tipmenu = " :tipmenu16 "; emblems.token = " :token12 "; emblems.trusted = " :trusted16 "; emblems.whisper = " :whisper16 "; emblems.whispermod = " :whispermod16 "; })(emblems || (emblems = {})); /** * Manages notices, especially buffering notices */ var notice; /** * Manages notices, especially buffering notices */ (function (notice_1) { "use strict"; /** * Color to use in notices, if none specified */ notice_1.color = "#000000"; /** * Buffer of notices that haven't been posted */ var buffer = []; /** * Add the notice to the buffer * @param notice Notice to add */ function add(notice) { buffer[buffer.length] = notice; } notice_1.add = add; /** * Add the notices to the buffer * @param notices Notices to add */ function adds() { var notices = []; for (var _i = 0; _i < arguments.length; _i++) { notices[_i] = arguments[_i]; } for (var _a = 0, notices_1 = notices; _a < notices_1.length; _a++) { var notice_2 = notices_1[_a]; add(notice_2); } } notice_1.adds = adds; /** * Apply the emblem to each notice in the buffer * @param emblem Emblem to apply */ function apply(emblem) { for (var _i = 0, buffer_1 = buffer; _i < buffer_1.length; _i++) { var notice_3 = buffer_1[_i]; notice_3 = emblem + notice_3; } } notice_1.apply = apply; /** * Clear the buffer */ function clear() { buffer = []; } notice_1.clear = clear; /** * Print the help menu for notices * @param message Requesting message */ function help(message) { if (permissions.isAtLeastModerator(message)) { add("/note,notice <Message> --Send a notice to chat"); post(message.user); clear(); } } notice_1.help = help; /** * Post all notices in the buffer * @param to User to send to * @param textcolor Color of the text * @param weight Weight of the font * @param autoclear Clear the buffer automatically */ function post(to, textcolor, weight, autoclear) { if (to === void 0) { to = ""; } if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } if (autoclear === void 0) { autoclear = true; } var message = buffer.join("\n"); cb.sendNotice(message, to, "#FFFFFF", textcolor, weight); if (autoclear) clear(); } notice_1.post = post; /** * Post all notices in the buffer * @param to Group to send to * @param textcolor Color of the text * @param weight Weight of the font */ function postGroup(to, textcolor, weight, autoclear) { if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } if (autoclear === void 0) { autoclear = true; } var message = buffer.join("\n"); cb.sendNotice(message, "", "#FFFFFF", textcolor, weight, to); if (autoclear) clear(); } notice_1.postGroup = postGroup; /** * Send a notice * @param message Message to send * @param to User to send to * @param textcolor Color of the text * @param weight Weight of the font */ function send(message, to, textcolor, weight) { if (to === void 0) { to = ""; } if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } cb.sendNotice(message, to, "#FFFFFF", textcolor, weight); } notice_1.send = send; /** * Send a notice * @param message Message to send * @param to Group to send to * @param textcolor Color of the text * @param weight Weight of the font */ function sendGroup(message, to, textcolor, weight) { if (textcolor === void 0) { textcolor = notice_1.color; } if (weight === void 0) { weight = "bold"; } cb.sendNotice(message, "", "#FFFFFF", textcolor, weight, to); } notice_1.sendGroup = sendGroup; /** * Try to parse a valid notice command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { if (permissions.isAtLeastModerator(message)) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/note": case "/notice": send(emblems.notice + m.join(" ")); return true; default: return false; } } return false; } notice_1.tryParse = tryParse; })(notice || (notice = {})); /** * Provides permissions checking * A lot of these are provided by the object anyways, are are implemented for the sake of orthogonality * This is solely for permissions purposes, the levels are: * broadcaster > trusted user > moderator > fanclub > tipped tons > tipped alot > tipped > has tokens > gray */ var permissions; /** * Provides permissions checking * A lot of these are provided by the object anyways, are are implemented for the sake of orthogonality * This is solely for permissions purposes, the levels are: * broadcaster > trusted user > moderator > fanclub > tipped tons > tipped alot > tipped > has tokens > gray */ (function (permissions) { "use strict"; /** * List of trusted users; users with elevated permissions */ var trusted = []; /** * Trust the users * @param users Users to trust */ function entrust() { var users = []; for (var _i = 0; _i < arguments.length; _i++) { users[_i] = arguments[_i]; } for (var _a = 0, users_1 = users; _a < users_1.length; _a++) { var user_1 = users_1[_a]; trusted[trusted.length] = user_1; } } permissions.entrust = entrust; /** * Remove trust of the users * @param users Users to detrust */ function detrust() { var users = []; for (var _i = 0; _i < arguments.length; _i++) { users[_i] = arguments[_i]; } for (var _a = 0, users_2 = users; _a < users_2.length; _a++) { var user_2 = users_2[_a]; trusted = cbjs.arrayRemove(trusted, user_2); } } permissions.detrust = detrust; /** * Is the user the broadcaster? * @param user User to check */ function isBroadcaster(user) { return user.user === cb.room_slug; } permissions.isBroadcaster = isBroadcaster; /** * Is the user a trusted user? * @param user User to check */ function isTrusted(user) { return cbjs.arrayContains(trusted, user.user); } permissions.isTrusted = isTrusted; /** * Is the user at least a trusted user? * @param user User to check */ function isAtLeastTrusted(user) { return isBroadcaster(user) || isTrusted(user); } permissions.isAtLeastTrusted = isAtLeastTrusted; /** * Is the user a moderator? * @param user User to check */ function isModerator(user) { return user.is_mod; } permissions.isModerator = isModerator; /** * Is the user at least a moderator? * @param user User to check */ function isAtLeastModerator(user) { return isAtLeastTrusted(user) || isModerator(user); } permissions.isAtLeastModerator = isAtLeastModerator; /** * Is the user in the fanclub? * @param user User to check */ function isInFanclub(user) { return user.in_fanclub; } permissions.isInFanclub = isInFanclub; /** * Is the user at least in the fanclub? * @param user User to check */ function isAtLeastInFanclub(user) { return isAtLeastModerator(user) || isInFanclub(user); } permissions.isAtLeastInFanclub = isAtLeastInFanclub; /** * Has the user tipped tons recently? * @param user User to check */ function hasTippedTons(user) { return user.tipped_tons_recently; } permissions.hasTippedTons = hasTippedTons; /** * Has the user at least tipped tons recently? * @param user User to check */ function hasAtLeastTippedTons(user) { return isAtLeastInFanclub(user) || hasTippedTons(user); } permissions.hasAtLeastTippedTons = hasAtLeastTippedTons; /** * Has the user tipped alot recently? * @param user User to check */ function hasTippedAlot(user) { return user.tipped_alot_recently; } permissions.hasTippedAlot = hasTippedAlot; /** * Has the user at least tipped alot recently? * @param user User to check */ function hasAtLeastTippedAlot(user) { return hasAtLeastTippedTons(user) || hasTippedAlot(user); } permissions.hasAtLeastTippedAlot = hasAtLeastTippedAlot; /** * Has the user tipped recently? * @param user User to check */ function hasTipped(user) { return user.tipped_recently; } permissions.hasTipped = hasTipped; /** * Has the user at least tipped recently? * @param user User to check */ function hasAtLeastTipped(user) { return hasAtLeastTippedAlot(user) || hasTipped(user); } permissions.hasAtLeastTipped = hasAtLeastTipped; /** * Does the user have tokens? * @param user User to check */ function hasTokens(user) { return user.has_tokens; } permissions.hasTokens = hasTokens; /** * Does the user at least have tokens? * @param user User to check */ function hasAtLeastTokens(user) { return hasAtLeastTipped(user) || hasTokens(user); } permissions.hasAtLeastTokens = hasAtLeastTokens; /** * Prints the help for permissions * @param message Requesting message */ function help(message) { if (permissions.isAtLeastTrusted(message)) { notice.add("/trust,trusted"); } if (permissions.isBroadcaster(message)) { notice.add(emblems.blank + "add <User>+ --Entrust the users"); notice.add(emblems.blank + "del,delete,rem,remove <User>+ --Detrust the users"); } if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "list --List all trusted users"); notice.post(message.user); } } permissions.help = help; /** * Try to parse a permissions command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { if (permissions.isBroadcaster(message)) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/detrust": for (var _i = 0, m_1 = m; _i < m_1.length; _i++) { var user_3 = m_1[_i]; detrust(user_3); } return true; case "/entrust": for (var _a = 0, m_2 = m; _a < m_2.length; _a++) { var user_4 = m_2[_a]; entrust(user_4); } return true; case "/trust": case "/trusted": if (m.length === 0) return false; var operation = m.shift().toLowerCase(); switch (operation) { case "add": for (var _b = 0, m_3 = m; _b < m_3.length; _b++) { var user_5 = m_3[_b]; entrust(user_5); } return true; case "del": case "delete": case "rem": case "remove": for (var _c = 0, m_4 = m; _c < m_4.length; _c++) { var user_6 = m_4[_c]; detrust(user_6); } return true; case "help": help(message); return true; case "list": notice.send(trusted.join(", "), message.user); return true; default: return false; } } } return false; } permissions.tryParse = tryParse; })(permissions || (permissions = {})); /** * Calculates various stats */ var stats; /** * Calculates various stats */ (function (stats) { "use strict"; function showDuration(sendTo) { var duration = timers.showDuration(); notice.add("Show Duration: " + duration[0] + ":" + duration[1] + ":" + duration[2]); notice.post(sendTo); } stats.showDuration = showDuration; function tippersTotal(sendTo) { notice.add("Tippers Total: " + tippers.count); notice.post(sendTo); } stats.tippersTotal = tippersTotal; function tokensPerHour(sendTo) { var duration = timers.showDuration(); var minutes = duration[0] * 60 + duration[1]; var rate = (tippers.tipped() / minutes) * 60; notice.add("Tokens Per Hour: " + rate); notice.post(sendTo); } stats.tokensPerHour = tokensPerHour; function tokensPerTipper(sendTo) { notice.add("Tokens Per Tipper: " + tippers.tipped() / tippers.count()); notice.post(sendTo); } stats.tokensPerTipper = tokensPerTipper; function tokensTotal(sendTo) { notice.add("Tokens Total: " + tippers.tipped()); notice.post(sendTo); } stats.tokensTotal = tokensTotal; })(stats || (stats = {})); /** * Represents a timer */ var timer = (function () { /** * Create a new timer * @param name Name of the timer * @param duration Duration of the timer, in seconds * @param delay Delay before the timer starts, in seconds */ function timer(name, duration, delay, onStart, onStop) { if (delay === void 0) { delay = 0; } this.name = name; this.duration = duration; this.remaining = duration; this.delay = delay; this.onStart = onStart; this.onStop = onStop; } /** * Extend the timer * @param seconds Seconds to extend by */ timer.prototype.extend = function (seconds) { this.duration += seconds; this.remaining += seconds; notice.send(emblems.timer + "'" + this.name + "' extended with " + seconds + "sec"); }; /** * Is the timer active? * This is true whether the timer is delayed or running * A timer is only inactive when it has stopped */ timer.prototype.isActive = function () { return this.delay > 0 || this.remaining > 0; }; /** * Is the timer currently delayed? */ timer.prototype.isDelayed = function () { return this.delay > 0; }; /** * Is the timer currently running? */ timer.prototype.isRunning = function () { return this.remaining < this.duration && this.remaining > 0; }; /** * Perform one tick of the timer, and call any events necessary */ timer.prototype.tick = function () { // Check event conditions if (this.delay === 0 && this.remaining === this.duration) { notice.send(emblems.timer + "'" + this.name + "' started with " + this.duration / 60 + "min"); if (this.onStart != null) this.onStart(); } else if (this.delay === 0 && this.remaining === 0) { notice.send(emblems.timer + "'" + this.name + "' has expired"); if (this.onStop != null) this.onStop(); } else if (this.delay === 0 && this.remaining % 60 === 0) { notice.send(emblems.timer + "'" + this.name + "' has " + this.remaining / 60 + "min remaining"); } // Time down as necessary if (this.delay > 0) { this.delay--; } else if (this.remaining > 0) { this.remaining--; } }; return timer; }()); /** * Manages timers */ var timers; /** * Manages timers */ (function (timers) { "use strict"; /** * Pool of running timers */ var pool = []; /** * Duration of the show, in seconds */ var showtime = 0; /** * Add the timer to the pool * @param name Name of the timer * @param duration Duration to run for, in seconds * @param delay Delay before start, in seconds * @param onStart Function to call on start * @param onStop function to call on stop */ function add(name, duration, delay, onStart, onStop) { if (delay === void 0) { delay = 0; } pool[pool.length] = new timer(name, duration, delay, onStart, onStop); if (delay > 0) { notice.send(emblems.timer + "'" + name + "' will start in " + delay + "s"); } } timers.add = add; /** * Clear the pool of all timers */ function clear() { pool = []; } timers.clear = clear; /** * Delete the specified timer without properly stopping it * @param name Timer name or position to delete */ function del(timer) { if (typeof timer === "number") { notice.send(emblems.timer + "'" + pool[timer].name + "' has been removed"); pool = cbjs.arrayRemove(pool, pool[timer]); } else if (typeof timer === "string") { if (cbjs.arrayContains(pool, lookup(timer))) { notice.send(emblems.timer + "'" + timer + "' has been removed"); pool = cbjs.arrayRemove(pool, lookup(timer)); } } } timers.del = del; /** * Extend the timer by duration * @param name Name of the timer * @param duration Duration, in seconds, to extend run for */ function extend(name, duration) { var timer = lookup(name); if (timer != null) { timer.extend(duration); } } timers.extend = extend; /** * Prints the help menu for timers * @param message Requesting message */ function help(message) { notice.add("/timer,timers"); if (permissions.isAtLeastModerator(message)) { notice.add(emblems.blank + "add,start <Duration> <Name> --Add and start the timer"); } if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "clr,clear --Clear and stop all timers"); notice.add(emblems.blank + "del,delete (<Name> | <Position>) --Delete the timer without any stop events"); notice.add(emblems.blank + "ext,extend <Duration> <Name> --Extend the timer"); } notice.add(emblems.blank + "list,print --List all active timers"); if (permissions.isAtLeastTrusted(message)) { notice.add(emblems.blank + "stop (<Name | <Position>) --Stop the timer next tick"); } notice.post(message.user); } timers.help = help; /** * List all active timers */ function list() { return pool; } timers.list = list; /** * Lookup the timer in the pool, null if not found * @param name Name to lookup */ function lookup(name) { for (var _i = 0, pool_1 = pool; _i < pool_1.length; _i++) { var timer_1 = pool_1[_i]; if (timer_1.name.toLowerCase() == name.toLowerCase()) { return timer_1; } } return null; } timers.lookup = lookup; /** * Get the current duration of the show * This is formatted time: [hours, minutes, seconds] */ function showDuration() { var hours = 0; var minutes = 0; var seconds = showtime; while (seconds >= 3600) { seconds -= 3600; hours += 1; } while (seconds >= 60) { seconds -= 60; minutes += 1; } return [hours, minutes, seconds]; } timers.showDuration = showDuration; /** * Start the timers */ function start() { cb.setTimeout(tick, 1000); } timers.start = start; /** * Set the timer to stop next tick * @param timer Timer to stop */ function stop(timer) { if (typeof timer === "number") { if (pool[timer] != null) pool[timer].remaining = 0; } else if (typeof timer === "string") { var t = lookup(timer); if (t != null) { t.remaining = 0; } } } timers.stop = stop; /** * Count down one interval */ function tick() { var keep = []; showtime += 1; for (var _i = 0, pool_2 = pool; _i < pool_2.length; _i++) { var timer_2 = pool_2[_i]; if (timer_2.isActive()) keep[keep.length] = timer_2; timer_2.tick(); } if (pool !== keep) { pool = keep; } cb.setTimeout(tick, 1000); } /** * Try to parse a timer command, returning true if a valid command is found * @param message Requesting message */ function tryParse(message) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); cb.log("command: " + command); switch (command) { case "/timer": case "/timers": // Command is valid, break out break; default: return false; } if (m.length === 0) return false; var operation = m.shift().toLowerCase(); cb.log("operation: " + operation); var name; // This is assigned while parsing operations var duration; // This is assigned while parsing operations var pos; // This is assigned while parsing operations switch (operation) { case "add": case "start": duration = m.shift(); if (isNaN(Number(duration))) { // Duration wasn't at the beginning, try finding it at the end m.unshift(duration); duration = m.pop(); if (isNaN(Number(duration))) return false; // No duration found, not a valid command } // We've found the duration, the rest is the name name = m.join(" "); timers.add(name, Number(duration) * 60); return true; case "clr": case "clear": timers.clear(); return true; case "del": case "delete": pos = m.shift(); if (isNaN(Number(pos))) { // pos isn't actually a position, so put it back m.unshift(pos); timers.del(m.join(" ")); } else { timers.del(Number(pos) - 1); } return true; case "ext": case "extend": duration = m.shift(); if (isNaN(Number(duration))) { // Duration wasn't at the beginning, try finding it at the end m.unshift(duration); duration = m.pop(); if (isNaN(Number(duration))) return false; // No duration found, not a valid command } // We've found the duration, the rest is the name name = m.join(" "); timers.extend(name, Number(duration) * 60); return true; case "help": help(message); return true; case "list": case "print": var i = 0; for (var _i = 0, pool_3 = pool; _i < pool_3.length; _i++) { var timer_3 = pool_3[_i]; notice.add(++i + ") '" + timer_3.name + "' with " + timer_3.remaining + "s"); } notice.apply(emblems.timer); notice.post(message.user); return true; case "stop": pos = m.shift(); if (isNaN(Number(pos))) { // pos isn't actually a position, so put it back m.unshift(pos); timers.stop(m.join(" ")); } else { timers.stop(Number(pos) - 1); } return true; default: return false; } } timers.tryParse = tryParse; })(timers || (timers = {})); /** * Represents a tipper; a user who as tipped */ var tipper = (function () { function tipper(name, tipped) { this.name = name; this.tipped = tipped; } return tipper; }()); /** * Manages and records tippers */ var tippers; /** * Manages and records tippers */ (function (tippers) { "use strict"; /** * All the tippers this show */ var pool = []; /** * Add the tip, incrementing an existing tipper, or adding a new one * @param tip Tip to add */ function add(tip) { var candidate = lookup(tip.from_user); if (candidate == null) { pool[pool.length] = new tipper(tip.from_user, 0); candidate = pool[pool.length - 1]; } candidate.tipped += tip.amount; } tippers.add = add; /** * Get the total amount of tippers */ function count() { return pool.length; } tippers.count = count; /** * Adds a dummy tipper * This creates an entry in the tippers manager, with no tip amount, which is necessary for teams * This should never, ever, be called outside of initialization * @param name Name of the tipper */ function dummy(name) { pool[pool.length] = new tipper(name, 0); } tippers.dummy = dummy; /** * Lookup the user, null if not found * @param user User to look up */ function lookup(user) { for (var _i = 0, pool_4 = pool; _i < pool_4.length; _i++) { var tipper_1 = pool_4[_i]; if (tipper_1.name === user) return tipper_1; } return null; } tippers.lookup = lookup; /** * Get the total amount tipped */ function tipped() { var total = 0; for (var _i = 0, pool_5 = pool; _i < pool_5.length; _i++) { var tipper_2 = pool_5[_i]; total += tipper_2.tipped; } return total; } tippers.tipped = tipped; })(tippers || (tippers = {})); /** * Tracks viewers for stats purposes * Don't take the gender stats too seriously: people lie. This is just a curiousity. */ var viewers; /** * Tracks viewers for stats purposes * Don't take the gender stats too seriously: people lie. This is just a curiousity. */ (function (viewers) { "use strict"; viewers.current = 0; viewers.withTokens = 0; viewers.inFanclub = 0; viewers.claimMale = 0; viewers.claimFemale = 0; viewers.claimTrans = 0; viewers.claimCouple = 0; function enter(user) { viewers.current += 1; if (user.has_tokens) viewers.withTokens += 1; if (user.in_fanclub) viewers.inFanclub += 1; if (user.gender == "m") viewers.claimMale += 1; if (user.gender == "f") viewers.claimFemale += 1; if (user.gender == "s") viewers.claimTrans += 1; if (user.gender == "c") viewers.claimTrans += 1; } viewers.enter = enter; function leave(user) { viewers.current -= 1; if (user.has_tokens) viewers.withTokens -= 1; if (user.in_fanclub) viewers.inFanclub -= 1; if (user.gender == "m") viewers.claimMale -= 1; if (user.gender == "f") viewers.claimFemale -= 1; if (user.gender == "s") viewers.claimTrans -= 1; if (user.gender == "c") viewers.claimTrans -= 1; } viewers.leave = leave; })(viewers || (viewers = {})); cb.onEnter(function (user) { viewers.enter(user); }); cb.onLeave(function (user) { viewers.leave(user); }); cb.onMessage(function (message) { // Mark a message as spam if a foreslash is found at the beginning if (message.m.trim().charAt(0) === "/") message['X-Spam'] = true; /** Whether a valid command has been found while parsing */ var validCommand = false; // Attempt to parse a command // This is goal-directed parsing, essentially, JavaScript just doesn't have any good syntax for it // While a command has not been found, keep trying to parse commands // When a command has been found, mark it as spam, which in turn avoids further attempts at parsing if (!validCommand) { validCommand = stats.tryParse(message); } // Return the message return message; }); cb.onTip(function (tip) { tippers.add(tip); }); var stats; (function (stats) { "use strict"; /** * Print all the stats * @param message Requesting message */ function print(message) { stats.showDuration(message.user); stats.tokensTotal(message.user); stats.tippersTotal(message.user); stats.tokensPerHour(message.user); stats.tokensPerTipper(message.user); listViewers(message.user); } stats.print = print; function listViewers(sendTo) { notice.add("Viewers (Signed In): " + viewers.current); notice.add("Viewers (With Tokens): " + viewers.withTokens); notice.add("Viewers (Claimed Male): " + viewers.claimMale); notice.add("Viewers (Claimed Female): " + viewers.claimFemale); notice.add("Viewers (Claimed Trans): " + viewers.claimTrans); notice.add("Viewers (Claimed Couple): " + viewers.claimCouple); notice.post(sendTo); } stats.listViewers = listViewers; function tryParse(message) { if (permissions.isAtLeastTrusted(message)) { var m = message.m.split(" "); if (m.length === 0) return false; var command = m.shift().toLowerCase(); switch (command) { case "/stat": case "/stats": case "/statistic": case "/statistics": print(message); return true; default: return false; } } return false; } stats.tryParse = tryParse; })(stats || (stats = {})); /** * Initialization code */ { notice.color = "#000000"; timers.start(); }
© Copyright Chaturbate 2011- 2024. All Rights Reserved.