Bots Home
|
Create an App
#menu
Author:
rainydio_bc
Description
Source Code
Launch Bot
Current Users
Created by:
Rainydio_Bc
(function (cb) { 'use strict'; cb = cb && cb.hasOwnProperty('default') ? cb['default'] : cb; function parseTags(str) { var tags = str.match(/#\w+/g) || []; return tags.map(function (tag) { return tag.slice(1).toLowerCase(); }); } var activitiesCount = 9; var activitiesCache = null; (function () { cb["settings_choices"] = [{ label: "Influence half life", name: "influenceHL", type: "int", minValue: 1, defaultValue: 30 }, { label: "Tax", name: "tax", type: "int", minValue: 0, maxValue: 100, defaultValue: 55 }, { label: "Queue length", name: "queueLength", type: "int", minValue: 0, maxValue: activitiesCount, defaultValue: 2 }]; for (var i = 1; i <= activitiesCount; i++) { cb["settings_choices"].push({ label: "#" + String(i), name: "activity" + String(i), type: "str", required: false }); } })(); function isReady() { return typeof cb.settings.influenceHL !== "undefined"; } function parseActivityConfig(str) { var weight = null; var parts = str.split(" "); for (var i = parts.length - 1; i >= 0; i--) { var part = parts[i]; if (/^[0-9]+%$/.test(part)) { weight = parseFloat(part.slice(0, -1)); parts.splice(i, 1); continue; } } if (weight === null) { throw new Error("No weight for " + str); } var icon = parts[0]; var title = parts.slice(1).join(" "); var tags = parseTags(title); return { icon: icon, tag: tags[0], weight: weight }; } function getActivities() { if (activitiesCache === null) { activitiesCache = []; for (var i = 1; i <= activitiesCount; i++) { var name = "activity" + String(i); var config = cb.settings[name]; if (config === "") { continue; } var activity = parseActivityConfig(config); activitiesCache.push(activity); } } return activitiesCache; } function hasActivity(tag) { var activities = getActivities(); for (var i = 0; i < activities.length; i++) { var activity = activities[i]; if (activity.tag === tag) { return true; } } return false; } function getActivityIcon(tag) { var activities = getActivities(); for (var i = 0; i < activities.length; i++) { var activity = activities[i]; if (activity.tag === tag) { return activity.icon; } } throw new Error("Unknown activity " + tag); } function getInfluenceHL() { return cb.settings.influenceHL * (1000 * 60); } function getTax() { return cb.settings.tax / 100; } function getQueueLength() { return cb.settings.queueLength; } var current = []; var queue = []; var priorities = { }; function prioritizeActivity(tag, influence) { var tax = getTax(); var activities = getActivities(); var norm = activities .map(function (activity) { return activity.weight; }) .reduce(function (sum, weight) { return sum + weight; }, 0); for (var i = 0; i < activities.length; i++) { var activity = activities[i]; var amount = influence * tax * activity.weight / norm; if (activity.tag === tag) { amount += influence * (1 - tax) * activity.weight; } if (priorities.hasOwnProperty(activity.tag) === false) { priorities[activity.tag] = 0; } priorities[activity.tag] += amount; } } function setCurrent(tags) { var queueLength = getQueueLength(); var activities = getActivities(); for (var i = 0; i < tags.length; i++) { var tag = tags[i]; if (current.indexOf(tag) === -1 && queue.indexOf(tag) === -1) { priorities[tag] = 0; } } current = tags; queue = queue.filter(function (queueTag) { return tags.indexOf(queueTag) === -1; }); if (queue.length > queueLength) { queue = queue.slice(0, queueLength); } else if (queue.length < queueLength) { var topTags = activities.filter(function (activity) { return queue.indexOf(activity.tag) === -1 && current.indexOf(activity.tag) === -1; }).map(function (activity) { return { tag: activity.tag, priority: priorities[activity.tag] || 0, rnd: Math.random() }; }).sort(function (a, b) { return a.rnd - b.rnd; }).sort(function (a, b) { return b.priority - a.priority; }).map(function (o) { return o.tag; }); queue = queue.concat(topTags.slice(0, queueLength - queue.length)); } return true; } function getCurrent() { return current; } function getQueue() { return queue; } var paused = false; var timestamp = Date.now(); var users = []; // general idea is to track audience priorities by // calculating influence between current and previously recorded timestamps // aftewards accumulated influence is added to activities // // e.g. tip -> increase activity priority -> increase user influence // // evolveAudience can be paused when private show started, or camwhore is afk // so that influence is no decaying and priorities are not shifting function getActivityRanks() { return getActivities().map(function (activity) { var influenceSum = 0; for (var y = 0; y < users.length; y++) { var user = users[y]; if (user.online) { for (var j = 0; j < user.preferences.length; j++) { if (user.preferences[j] === activity.tag) { influenceSum += user.influence / user.preferences.length; } } } } return { tag: activity.tag, influence: influenceSum }; }).sort(function (a, b) { return b.influence - a.influence; }).map(function (a) { return a.tag; }); } function evolveAudience() { if (paused) { return false; } var influenceHL = getInfluenceHL(); var activities = getActivities(); var now = Date.now(); var timeDelta = now - timestamp; var influenceExp = timeDelta / influenceHL; var influenceDecay = Math.pow(2, influenceExp); for (var i = 0; i < activities.length; i++) { var activity = activities[i]; var activityInfluenceSum = 0; for (var y = 0; y < users.length; y++) { var user = users[y]; if (user.online) { for (var j = 0; j < user.preferences.length; j++) { if (user.preferences[j] === activity.tag) { activityInfluenceSum += user.influence / user.preferences.length; } } } } var activityInfluenceDelta = activityInfluenceSum - (activityInfluenceSum / influenceDecay); prioritizeActivity(activity.tag, activityInfluenceDelta); } for (var k = 0; k < users.length; k++) { users[k].influence = users[k].influence / influenceDecay; } timestamp = now; return true; } function setUserOnline(username) { for (var i = 0; i < users.length; i++) { if (users[i].username === username) { evolveAudience(); users[i].online = true; return true; } } return false; } function setUserOffline(username) { for (var i = 0; i < users.length; i++) { if (users[i].username === username) { evolveAudience(); users[i].online = false; return true; } } return false; } function getUserInfluence(username) { for (var i = 0; i < users.length; i++) { if (users[i].username === username) { return users[i].influence; } } return 0; } function increaseUserInfluence(username, amount) { for (var i = 0; i < users.length; i++) { if (users[i].username === username) { evolveAudience(); users[i].influence += amount; return true; } } cb.log(JSON.stringify(users)); users.push({ username: username, online: true, influence: amount, preferences: [] }); return true; } function getUserPreferences(username) { for (var i = 0; i < users.length; i++) { if (users[i].username === username) { return users[i].preferences; } } return []; } function setUserPreferences(username, preferences) { for (var i = 0; i < users.length; i++) { if (users[i].username === username) { evolveAudience(); users[i].preferences = preferences; return true; } } users.push({ username: username, online: true, influence: 0, preferences: preferences }); return true; } function warnUnknownTags(username, tags) { var tagsLine = tags.map(function (tag) { return "#" + tag; }).join(" "); cb.sendNotice("Unknown tags " + tagsLine, username, "#FFFFFF", "#8F1537", "bold"); } function warnNoCurrentTags(currentLine) { cb.sendNotice("No known tags in '" + currentLine + "'", cb.room_slug, "#FFFFFF", "#8F1537", "bold"); } function sendExplanationNotice(username) { var ranks = getActivityRanks().map(function (tag, i) { return String(i + 1) + ". " + getActivityIcon(tag) + " #" + tag; }).join("\n"); var explanation = [ "No tip menu! Please provide feedback how confusing and fair described system is.", "", "Use hastags in tip notes and chat messages to set your preferences. " + "The more tips you sent the more influence power you get. It is slowly decaying over time. " + "Combined preferences are ranked and higher ranked preferences are performed more often. " + "Every token matter, and everything eventually gets into queue anyway.", "", "Current ranks are:", ranks, "", "You may send just hashtags.", "> #pussylicking #scissors", "...or convience others", "> Everyone vote for #scissors!" ].join("\n"); cb.sendNotice(explanation, username, "#FFFFFF", "#053F5E", "bold"); } function sendRanksNotice() { var ranks = getActivityRanks().map(function (tag, i) { return String(i + 1) + ". " + getActivityIcon(tag) + " #" + tag; }).join("\n"); cb.sendNotice(ranks, cb.room_slug, "#FFFFFF", "#053F5E", "bold"); } function parseBroadcasterCommand(message) { if (message.indexOf("/ss current ") === 0) { var currentLine = message.slice("/ss current ".length); var activityTags = parseTags(currentLine).filter(hasActivity); if (activityTags.length === 0) { warnNoCurrentTags(currentLine); return true; } if (setCurrent(activityTags)) { cb.changeRoomSubject(currentLine); return true; } } if (message.indexOf("/ss explain ") === 0) { var username = message.slice("/ss explain ".length); sendExplanationNotice(username); return true; } if (message === "/ranks") { sendRanksNotice(); return true; } return false; } function parseUserCommand(username, message) { if (message === "/menu") { sendExplanationNotice(username); return true; } if (message === "/tipmenu") { sendExplanationNotice(username); return true; } return false; } function parseUserPreferences(username, message) { var tags = parseTags(message); var preferences = tags.filter(function (tag) { return hasActivity(tag); }); var unknownTags = tags.filter(function (tag) { return hasActivity(tag) === false; }); if (unknownTags.length !== 0) { warnUnknownTags(username, unknownTags); } if (preferences.length === 0) { return false; } return setUserPreferences(username, preferences); } function redrawEvery5s() { if (isReady() && evolveAudience()) { cb.drawPanel(); } setTimeout(redrawEvery5s, 5000); } cb.onEnter(function (evt) { var username = evt["user"]; sendExplanationNotice(username); if (setUserOnline(username)) { cb.drawPanel(); } }); cb.onLeave(function (evt) { var username = evt["user"]; if (setUserOffline(username)) { cb.drawPanel(); } }); cb.onTip(function (evt) { var username = evt["from_user"]; var amount = parseInt(evt["amount"]); var message = evt["message"]; increaseUserInfluence(username, amount); parseUserPreferences(username, message); cb.drawPanel(); }); cb.onMessage(function (evt) { var username = evt["user"]; var message = evt["m"]; var redraw = false; if (username === cb.room_slug) { if (parseBroadcasterCommand(message)) { evt["X-Spam"] = true; redraw = true; } } if (username !== cb.room_slug) { if (parseUserCommand(username, message)) { evt["X-Spam"] = true; redraw = true; } redraw = redraw || parseUserPreferences(username, message); } if (redraw) { cb.drawPanel(); } }); cb.onDrawPanel(function (evt) { var username = evt["user"]; var influence = getUserInfluence(username); var preferences = getUserPreferences(username); var influenceStr; if (influence <= 0.05) { influenceStr = 0; } else if (influence < 10) { influenceStr = influence.toFixed(1); } else { influenceStr = String(Math.round(influence)); } influenceStr += String.fromCodePoint(0x1F48E); var preferencesStr = preferences.map(getActivityIcon).join(" "); var statusStr = [getCurrent().map(getActivityIcon).join(" + ")] .concat(getQueue().map(getActivityIcon)) .join(" " + String.fromCodePoint(0x27A1) + " "); return { "template": "3_rows_of_labels", "row1_label": "Influence", "row1_value": influenceStr, "row2_label": "Preferences", "row2_value": preferencesStr, "row3_label": "Queue", "row3_value": statusStr }; }); redrawEvery5s(); }(cb));
© Copyright Chaturbate 2011- 2025. All Rights Reserved.