Bots Home
|
Create an App
retnabot
Author:
bot_factory
Description
Source Code
Launch Bot
Current Users
Created by:
Bot_Factory
/* ################################################################################################################# # Custom bot for ah_ha # # Modules included are: LovensMenu,spamBlock,retNP,ban,Help # # Author: bot_factory # Version: 20220214.1911 ################################################################################################################# */ /* ############################## # main (version 20211220.1817) ############################## */ var botname='retnabot',roomname='ah_ha'; /* ##################################################### # Declare Global variables and initalization function ##################################################### */ var modules={},thismod={},botmods={}; modules.names=[]; var model=cb.room_slug var debug=0; const wspc=String.fromCodePoint(0x2800),wspc2=wspc+wspc,wspc3=wspc2+wspc; cb.settings_choices=[]; function init() { modnames=modules.names.join(); sendNotice(`${wspc}Running ${botname} with the following functions enabled:\n${wspc2}${modnames}\n${wspc}Type /help for more info\n${wspc}${botname} was created by bot_factory`,"","#900000"); // sendNotice(`${wspc}Bot ${botname} courtesy of alanstuart`,model,"#900000"); for (const m of modsHandling("onInit")) {modules[m].funct("onInit","",m);} botInit(); } /* ############################# # Process Messages ############################# */ cb.onMessage(function (msg) { let c=parseMsg(msg); if (debug) {sendNotice("Debug: user="+c.user+",iscmd="+c.iscmd+",ismod="+c.ismod+",ismodel="+c.ismodel+",isgrey="+c.isgrey+",isfan="+c.isfan+",model="+model+",msg="+c.msg.m,c.user,"#ffffff","#000090","bold");} /* ####################################### # Process chat messages (non-commands) ####################################### */ if (!c.iscmd) { for (const m of modsHandling("onMessage")) { if (modules[m].funct("onMessage",c,m)) {return msg;} } return msg; } /* ####################################### # Process command messages ####################################### */ if (c.iscmd) { if (debug) {sendNotice("Debug: cmd="+c.cmd+",cpct="+c.cmdparmct+",c0="+c.cmd0+",c1="+c.cmd1+",c2="+c.cmd2+",cp1="+c.cmdparms[1],c.user,"#ffffff","#000090","bold");} for (const m of modsHandling("onCommand")) { if (modules[m].funct("onCommand",c,m)) {msg['X-Spam']=true;return msg;} } } // If it was a recognized command but not processed above, it must be syntax or permission error, // Otherwise pass through the command message unaltered (it may be used by another bot) if (c.cmd in c.cmds) {return badCommand('Syntax or Authorization error in command, type "/help" for more info',c);} else {return msg;} }); /* ############################# # Process User Entering Room ############################# */ cb.onEnter(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" entered room","","#ffffff","#000090","bold");} for (const m of modsHandling("onEnter")) {modules[m].funct("onEnter",user,m);} }); /* ############################# # Process User Leaving Room ############################# */ cb.onLeave(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" left room","","#ffffff","#000090","bold");} for (const m of modsHandling("onLeave")) {modules[m].funct("onLeave",user,m);} }); /* ############################# # Process User Following ############################# */ cb.onFollow(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" followed","","#ffffff","#000090","bold");} for (const m of modsHandling("onFollow")) {modules[m].funct("onFollow",user,m);} }); /* ############################# # Process User unFollowing ############################# */ cb.onUnFollow(function(user) { if (debug) {sendNotice("Debug: user "+user.user+" unfollowed","","#ffffff","#000090","bold");} for (const m of modsHandling("onUnFollow")) {modules[m].funct("onUnFollow",user,m);} }); /* ############## # Process Tip ############## */ cb.onTip(function(tip) { if (debug) {sendNotice(`Debug: amt=${tip.smount},msg=${tip.message},from=${tip.from_user}`,"","#ffffff","#000090","bold");} for (const m of modsHandling("onTip")) {modules[m].funct("onTip",tip,m);} }); /* ################## # CORE FUNCTIONS # ################## /* ####################################################################### # Get the list of mods that have a handler for the event ####################################################################### */ function modsHandling(event) { let modlist=[]; modules.names.forEach(m=>{if (modules[m].events.includes(event)) {modlist.push(m)}}) return modlist; } /* ####################################################################### # Parse command parameters and user info into variables ####################################################################### */ function parseMsg(msg) { let c={}; c.msg=msg; c.origmsg=msg.m; c.user=msg.user; if (msg.is_mod||botmods[c.user]) {c.ismod=1;} else {c.ismod=0;} if (msg.has_tokens) {c.isgrey=0;} else {c.isgrey=1;} if (msg.in_fanclub) {c.isfan=1;} else {c.isfan=0;} if (c.user==model) {c.ismodel=1; c.ismod=1;} else {c.ismodel=0;} if (msg.m.substr(0,1)!=='/') {c.iscmd=0; return c;} else {c.iscmd=1} c.cmdparms=[]; c.cmdparms = notBlank(msg.m.substr(1).split(" ")); c.cmd = c.cmdparms[0]; c.cmdparmct = c.cmdparms.length-1; c.cmd0=c.cmd1=c.cmd2=c.cmd1p=c.cms2p=""; if (c.cmdparmct==0) {c.cmd0=c.cmd;} if (c.cmdparmct==1) {c.cmd1=c.cmd; c.cmd1p=c.cmd+" "+c.cmdparms[1];} if (c.cmdparmct==2) {c.cmd2=c.cmd; c.cmd2p=c.cmd+" "+c.cmdparms[1]+" "+c.cmdparms[2];} c.cmds=[]; return c; } /* ########################################################################### # Sends an error message notice in response to an invalid command message ########################################################################### */ function badCommand(badmsg,c) { cb.sendNotice('Error in command "'+c.msg.m+'"'+"\n"+badmsg,c.user,"#900000","#ffffff"); c.msg['X-Spam'] = true; return c.msg; } /* ########################################################################### # Function to facilitate splitting command message parms ########################################################################### */ function notBlank(array) { return array.filter(function(item){ return item != ""; }); } /* ##################################################################################### # Notice management # (if your bot uses this function, add "checkNotices()" into the init section) ##################################################################################### */ var notices={},notice={},lastsend=0;notice.timer=0; // function checkNotices() { const now=new Date().getTime(); if (notice.timer==0) {notice.last=now;} Object.keys(notices).forEach(n=>{ if (notices[n].interval>0) { notices[n].timeleft-=now-notice.last; if (notices[n].timeleft<=0) { showNotice(n); notices[n].timeleft+=notices[n].interval; } } }); notice.last=now; notice.timer=cb.setTimeout(checkNotices,1000); } // function addNotice(n,msg,user,interval,delay=0,fgcolor="#000090",bgcolor="#ffffff",weight="bold") { if (n in notices) {delete notices[n];} if (delay==-1) {delay=Math.floor(Math.random()*interval);} notices[n]={"message":msg,"user":user,"interval":interval*1000,"fgcolor":fgcolor,"bgcolor":bgcolor,"weight":weight,"timeleft":delay*1000}; if ((interval!==0)&&(delay!==0)) showNotice(n); } // function delNotice(n) {if (n in notices) {notices[n].interval=0;}} // function listNotices(user) { if (Object.keys(notices).length==0) {sendNotice("There are currently no Notices",user); return;} sendNotice("# List of notices",user); Object.keys(notices).forEach(n=>{ let u=notices[n].user; if (Array.isArray(u)) {u=u.join();} let m=notices[n].message; if (typeof(m)=='function') {m=m.name+"()";} sendNotice("# name="+n+", user="+u+", interval="+notices[n].interval/1000+" sec, nextnotice="+notices[n].timeleft/1000+"sec, message= "+m,user); }); } // function processUserList(ul) { let ul1=((ul.split(" ")).join("")).split(","); if (ul1.length==0) {return [`#Invalid user list: "${ul}"`]} let ul2=[]; for (u of ul1) { if (validateUserName(u)) {ul2.push(u)} else {return [`#Invalid user name: "${u}"`]} } if (ul2.includes("*")) {return ["*"];} return ul2; } // function validateUserName(n) { if (n.length>32) {return 0;} if ((n=="*")||(n=="*m")||(n=="*b")) {return 1;} if (!/^[a-zA-X0-9_]+$/.test(n)) {return 0;} return 1; } // function showNotice(n) { let m=""; if (typeof(notices[n].message)=='function') {m=notices[n].message();} else {m=notices[n].message;} let users=notices[n].user; if (!Array.isArray(users)) {users=[users];} for (u of users) { if (u=="*m") {sendNotice(m,"",notices[n].fgcolor,notices[n].bgcolor,notices[n].weight,"red");} else { if (u=="*b") {u=model;} else if (u=="*") {u="";} sendNotice(m,u,notices[n].fgcolor,notices[n].bgcolor,notices[n].weight); } } } // function sendNotice(notice,touser="",fgcolor="#000090",bgcolor="#ffffff",weight="bold",togroup="") { var now = new Date().getTime(); var wait = Math.max(lastsend+200-now,0); setTimeout(function(){cb.sendNotice(notice,touser,bgcolor,fgcolor,weight,togroup);},wait); lastsend=now+wait; } /* ##################################################################################### # Read settings for a module into modules[mod].data ##################################################################################### */ function readCBSettings(mod) { const m = modules[mod]; Object.keys(cb.settings).forEach(s=>{ let val = cb.settings[s]; let sp = s.split('_'); if (sp[0].toLowerCase()==mod.toLowerCase()) { if (typeof(val)=="string") { if ((val.toLowerCase()=="-yes-")||(val.toLowerCase()=="-true-")) {val=1;} else if ((val.toLowerCase()=="-no-")||(val.toLowerCase()=="-false-")) {val=0;} } sp.splice(0,1); if (sp[0]) { const ind=Number(sp[0]); if (Number.isInteger(ind)) { sp.splice(0,1); const vn=sp.join('_'); if (!m.data[vn]) {m.data[vn]=[];} m.data[vn][ind]=val; } else { const vn=sp.join('_'); m.data[vn]=val; } } else {m.data[s]=val;} } }) } /* ##################################################################################### # Override cb.setting_choices parameters setup in modules ##################################################################################### */ function deleteSC(scn) { cb.settings_choices.forEach((sc,i)=>{ if (sc.name.toLowerCase()==scn.toLowerCase()) {cb.settings_choices.splice(i,1); return;} }); } /* ######################################################################################### # Stub function to be run on bot initialization -- to be overridden with custom bot code ######################################################################################### */ function botInit() {} /* #################### # MODULES #################### */ /* ##################################################################################### # Module: LovensMenu (version 20211103.1659) ##################################################################################### */ modules['LovensMenu']={};thismod=modules['LovensMenu'];thismod.data={};modules.names.push('LovensMenu');thismod.name='LovensMenu'; thismod.cmd='lov'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#880000"; thismod.data.lnot=[]; thismod.data.enmsg=["disabled","enabled"]; thismod.data.lovre=new RegExp("^\-{8}.*(sec|SEC|Here are my levels|okens|Special Commands)"); cb.settings_choices.push( {name:`${thismod.name}_enabled`,type:'choice',choice1:"-Yes-",choice2:"-No-",defaultValue:'-Yes-',label:'Replace Lovense notification wall with friendlier, more compact menu?',required:true}, ); thismod.events=["onMessage","onCommand","onInit"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if (c.cmd==mod.cmd) { c.cmds[c.cmd]=1; if (c.cmdparmct==0) { if (!mod.data.enabled) {sendNotice("LovenseMenu is disabled, see chat notices for Lovens tip options",c.user,mod.data.fgcol,mod.data.bgcol); return 1;} let ll="There are no Lovens tip options currently available"; if (Object.keys(mod.data.lnot).length>0) { ll=":blankx Lovens Tip Menu Options: :blankx\n"; Object.keys(mod.data.lnot).forEach(l=>ll+=`:blankx :blankx ${mod.data.lnot[l]} :blankx\n`); } sendNotice(ll,c.user,mod.data.fgcol,mod.data.bgcol); return 1; } else if (c.cmdparmct==1&&(c.cmdparms[1]=="on"||c.cmdparms[1]=="off")) { if (c.ismodel || c.ismod) { if (c.cmdparms[1]=="on") {mod.data.enabled=1;} else {mod.data.enabled=0;} sendNotice(`Lovens Menu has been ${mod.data.enmsg[mod.data.enabled]}`,c.user); return 1; } } } } else if (mode=="onMessage") { if (mod.data.enabled && c.ismodel && mod.data.lovre.test(c.msg.m)) { if (Number(Date.now()-mod.data.lastnot)>30000) { mod.data.lnot=[]; mod.data.nsent=0; } mod.data.lnot.push(c.msg.m); mod.data.lastnot=Date.now(); c.msg.m=""; c.msg['X-Spam'] = true; setTimeout(mod.menumsg,15000); return 1; } } else if (mode=="onInit") { mod.data.nsent=0; mod.data.lastnot=0; readCBSettings(m); } return 0; } thismod['menumsg'] = function() { const mod=modules['LovensMenu']; if (mod.data.nsent) {return;} if (Number(Date.now()-mod.data.lastnot)<10000) {return;} sendNotice(":blankx Type /lov to see options for making Lovense Toy respond to Tips! :blankx","",mod.data.fgcol,mod.data.bgcol); mod.data.nsent=1; } thismod.summary = "Replaces the Lovense Tip wall of notifications with a single notification and a menu command"; thismod.desc = "See LovensMenu bot description for details"; thismod.lparms = {'Replace Lovense notificatioin wall with friendlier command?': "Select Yes to enable the Lovens Menu replacemnt, or No to use normal Lovense menu"} thismod.commands = {'/lov': "Displays the Lovens Tip menu to the user", '*/lov on': 'Enable Lovens Menu', '*/lov off': 'Disable Lovens Menu' }; /* ##################################################################################### # Module: spamBlock (version 20220212.1858) ##################################################################################### */ modules['spamBlock']={};thismod=modules['spamBlock'];thismod.data={};modules.names.push('spamBlock');thismod.name='spamBlock'; thismod.cmd='sb'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#880000"; thismod.data.verify=[]; thismod.data.enabled=1; thismod.data.enmsg=["disabled","enabled"]; thismod.data.log=[]; thismod.data.reqfmt='**Requested mobile format number**'; thismod.data.nums=[[ '_$$$_', '$___$', '$___$', '$___$', '_$$$_' ],[ '__$$_', '_$_$_', '___$_', '___$_', '_$$$$' ],[ '_$$$_', '$___$', '__$$_', '_$___', '$$$$$' ],[ '$$$$_', '____$', '_$$$_', '____$', '$$$$_' ],[ '$__$_', '$__$_', '$$$$$', '___$_', '___$_' ],[ '$$$$$', '$____', '$$$$_', '____$', '$$$$_' ],[ '_$$$_', '$____', '$$$$_', '$___$', '_$$$_' ],[ '$$$$$', '___$_', '__$__', '_$___', '$____' ],[ '_$$$_', '$___$', '_$$$_', '$___$', '_$$$_' ],[ '_$$$_', '$___$', '_$$$$', '___$_', '_$$__' ]]; cb.settings_choices.push({name:`spamblock_level`,type:'choice',choice1:"Verify Greys Only",choice2:"Verify Everyone Except Mods & FanClub Members",choice3:"Disable Verification", default:"Verify Greys Only",label:'spamBlock Verification Level',required:true}, {name:`spamblock_wlist`,type:'str',defaultValue:"",label:`spamBlock Whitelist. Leave blank unless you want to exclude certain users from verification (if you do, enter their usernames separated by commas)`, required:false,maxLength:128}, {name:'spamblock_timer',type:'int',defaultValue:10,label:'How often to display spamBlock count of messages that were blocked (in minutes)',required:true,minvalue:1}); thismod.events=["onMessage","onCommand","onInit"]; thismod.funct = function(mode,c,m) { const mod=modules[m]; if (mode=="onCommand") { if (c.cmd==mod.cmd) { c.cmds[c.cmd]=1; if (c.cmdparmct==1&&(c.cmdparms[1]=="log")) { sendNotice(mod.showSpam(),c.user,mod.data.bgcol,mod.data.fgcol); return 1; } if (c.ismod||c.ismodel) { if (c.cmdparmct==0) {sendNotice(`SpamBlock is ${mod.data.enmsg[mod.data.enabled]}`,c.user,mod.data.fgcol,mod.data.bgcol);return 1;} else if (c.cmdparmct==1&&(c.cmdparms[1]=="on"||c.cmdparms[1]=="off")) { if (c.cmdparms[1]=="on") {mod.data.enabled=1;} else {mod.data.enabled=0;} sendNotice(`SpamBlock has been ${mod.data.enmsg[mod.data.enabled]}`,c.user); return 1; } else if (c.cmdparmct==1&&(c.cmdparms[1].substr(0,4)=="test")) { let touser=c.user; if (c.cmdparms[1]=="testall") {touser=""} mod.shownum(mod,touser); mod.data.widenum=!mod.data.widenum; mod.shownum(mod,touser); mod.data.widenum=!mod.data.widenum; return 1; } else if (c.cmdparmct==2&&(c.cmdparms[1]=="wl")) { let le=c.cmdparms[2].toLowerCase(); if (!mod.data.verify[le]) {mod.data.verify[le]=[];} mod.data.verify[le]["status"]="Whitelisted"; sendNotice(`user ${le} has been whitelisted`,c.user); return 1; } else if (c.cmdparmct==1&&(c.cmdparms[1]=="list")) { let uct=0; let listmsg=""; Object.keys(mod.data.verify).forEach(e=>{uct++;listmsg+=`${wspc}User: ${e}, Verification Status: ${mod.data.verify[e]["status"]}${wspc}\n`}); if (uct) {sendNotice(`${wspc}List of users/status\n${wspc}\n`+listmsg,c.user,mod.data.fgcol,mod.data.bgcol);} else {sendNotice(`${wspc}No Users have gone through verification${wspc}`,c.user,mod.data.fgcol,mod.data.bgcol);} return 1; } } else {badCommand("You are not authorized to run spamBlock commands",c); return 1;} } return 0; } else if (mode=="onMessage") { if (mod.data.enabled) { if (c.isfan) {return 0;} if (c.ismod) {return 0;} if (mod.data.level=="Disable Verification") {return 0;} if (mod.data.level=="Verify Greys Only") {if (!c.isgrey) {return 0;}} if (!mod.data.verify[c.user]) { mod.data.verify[c.user]=[]; mod.data.verify[c.user]["1stmsg"]=c.msg.m; mod.data.verify[c.user]["time"]=new Date(); } else if (mod.data.verify[c.user]["status"]=="Confirmed") {return 0;} else if (mod.data.verify[c.user]["status"]=="Whitelisted") {return 0;} else if (mod.data.verify[c.user]["status"]=="Challenged") { if (c.msg.m.toLowerCase()=="m") { mod.data.widenum=0; mod.data.badresp=0; mod.data.verify[c.user].bad.push({"chal":mod.data.verify[c.user].number,"resp":mod.data.reqfmt}); } else if (c.msg.m==mod.data.verify[c.user]["number"]) { mod.data.verify[c.user]["status"]="Confirmed"; sendNotice(`You have been verified, thanks for helping us battle spam!`,c.user,"#008800"); c.msg.m=mod.data.verify[c.user]["1stmsg"]+"\n"; return 0; } else { mod.data.verify[c.user].bad.push({"chal":mod.data.verify[c.user].number,"resp":c.msg.m}); mod.data.badresp=1; } } c.msg.m=""; c.msg['X-Spam'] = true; const num=mod.shownum(mod,c.user); mod.data.verify[c.user]["number"]=num; if (!mod.data.verify[c.user].bad) {mod.data.verify[c.user].bad=[]} mod.data.verify[c.user]["status"]="Challenged"; return 1; } } else if (mode=="onInit") { readCBSettings(m); mod.data.widenum=1; mod.data.badresp=0; if (mod.data.wlist) { notBlank(mod.data.wlist.split(",")).forEach(e=>{ let le=e.toLowerCase(); if (!mod.data.verify[le]) {mod.data.verify[le]=[];} mod.data.verify[le]["status"]="Whitelisted"; }); } if (mod.data.timer) {addNotice(m,mod.spamCount,model,Number(mod.data.timer*60),-1,mod.data.fgcol,mod.data.bgcol)} checkNotices(); } return 0; } thismod['shownum'] = function(mod,u) { let num=String(Math.floor(Math.random()*1000)).padStart(3,'0'); let ni=""; if (mod.data.widenum) { ni+=`\n ${wspc} `; [0,1,2,3,4].forEach((line)=>{ [0,1,2].forEach((digit)=>{ const n=num.substr(digit,1); let ns=mod.data.nums[n][line]; ni+=ns+` ${wspc} `; }); ni+=`\n ${wspc} `; }); if (mod.data.badresp) { ni+=`\n${wspc} Incorrect response -- please enter the number shown above to enable chat`+ `\n${wspc} If you can't read the number, please expand your chat screen,\n${wspc} or enter M to show the number in a more mobile friendly format \n${wspc}`; } else {ni+=`\n${wspc} Please enter the number shown above to enable chat (you will only need to do this once) \n${wspc}`;} } else { [0,1,2].forEach((digit)=>{ ni+="\n"; [0,1,2,3,4].forEach((line)=>{ const n=num.substr(digit,1); let ns=mod.data.nums[n][line]; ni+=` ${wspc} `+ns+" \n"; }) }); if (mod.data.badresp) {ni+=`\n${wspc} Incorrect response -- please enter the 3 digit number shown above to enable chat (top digit, followed by the middle, and then the bottom digit) \n${wspc}`} else {ni+=`\n${wspc} Please enter the 3 digit number shown above to enable chat (top digit, followed by the middle, and then the bottom digit). You will only need to do this once. \n${wspc}`} } // ni=ni.replace(/\_/g,':sbwh '); // ni=ni.replace(/\$/g,':sbbl '); if (mod.data.badresp) {sendNotice(ni,u,"#ff0000")} else {sendNotice(ni,u)} return [num]; } thismod['showSpam'] = function() { const mod=modules['spamBlock']; let any=false,msg="",uarr=String.fromCodePoint(0x27a4),sra=String.fromCodePoint(0x273d).repeat(1),sla=String.fromCodePoint(0x25c0).repeat(1),ct=0;ct=0; for (const un of Object.keys(mod.data.verify)) { const u=mod.data.verify[un]; if (u.status=="Challenged") { any=true; ct++; msg+=`\n${wspc}${uarr}User:${wspc}${un}\n${wspc}${wspc}${wspc}${wspc}${wspc}First Message: ${u["1stmsg"]}${wspc}${sla}`; u.bad.forEach((b)=>{ let resp=b.resp; if ((resp!=mod.data.reqfmt)&&!(/^\d{3}$/.test(b.resp))) {ct++; resp=`${resp}${wspc}${sla}`}; msg+=`\n${wspc}${wspc}${wspc}${wspc}${wspc}Challenge: ${b["chal"]}, Response: ${resp}`; }) msg+=`\n${wspc}${wspc}${wspc}${wspc}${wspc}Challenge: ***, No response yet`; } } if (any) {return `${wspc}spamBlock Log (${ct} Messages Blocked)${msg}`} else {return "No spam messages have been detected yet"} } thismod['spamCount'] = function() { const mod=modules['spamBlock']; let any=false,ct=0; for (const un of Object.keys(mod.data.verify)) { const u=mod.data.verify[un]; if (u.status=="Challenged") { any=true; ct++; u.bad.forEach((b)=>{if ((b.resp!=mod.data.reqfmt)&&!(/^\d{3}$/.test(b.resp))) {ct++}}); } } if (any) {return `spamBlock has intercepted ${ct} spambot messages so far! Type "/sb log" for details`} else {return "No spambots have tried to get past spamBlock yet!"} } thismod.summary = "spamBlock uses a couple smart but simple techniques to make it the most effective and user-friendly spam blocker available on Chaturbate.spamBlock is the Most Effective AND the most User-Friendly spam blocker available"; thismod.desc = "See spamBlock bot description (https://chaturbate.com/apps/app_details/spamblock) for details"; thismod.lparms = {'Verification Level': "Select whether the requirement to answer the spam verification question should apply to Greys Only, or to All Users (excluding Mods and Fan Club members). Verification can also be disabled", 'Whitelist': 'You may optionally enter a comma separated list of usernames that should be excluded from having to go through the user verification process', 'How often to display block count': 'Specify the frequency in minutes that you want the performer to be notified of the number of messages blocked by spamBlock'}; thismod.commands = {'*/sb': "Display spamBlock status (enabled or disabled)", '*/sb on': 'Enable spamBlock (spamBlock is enabled by default at startup)', '*/sb off': 'Disable spamBlock', '*/sb list': 'List the status of each user that spamBlock has attempted to verify', '*/sb wl [username]': 'Adds user [username] to the whitelist' }; /* ##################################################################################### # Module: retNP (version 20211230.2305) ##################################################################################### */ modules['retNP']={};thismod=modules['retNP'];thismod.data={};modules.names.push('retNP');thismod.name='retNP'; thismod.cmd='np'; thismod.data.bgcol="#ffffff";thismod.data.fgcol="#b3b3b3";thismod.data.perfcol='#e35500' thismod.data.gen={"m":String.fromCodePoint(0x1F17C),"f":String.fromCodePoint(0x1F175),"s":String.fromCodePoint(0x1F183),"c":String.fromCodePoint(0x1F172)}; thismod.data.col={"model":"","grey":String.fromCodePoint(0x2070),"lblue":String.fromCodePoint(0x00B9),"dblue":String.fromCodePoint(0x00B2), "lpurp":String.fromCodePoint(0x00B3),"dpurp":String.fromCodePoint(0x2074),"fan":"","mod":""} thismod.data.act={"follow":String.fromCodePoint(0x1F465),"enter":String.fromCodePoint(0x2714),"leave":String.fromCodePoint(0x2717)}; thismod.data.nlist=[]; thismod.data.stats=[]; thismod.data.adduser=[]; thismod.data.watchcode={"No One":0,"Mods & Fanclub Members":1,"Mods, Fanclub & Purple":2,"Mods, Fanclub, Purple & Dark Blue":3,"All users with Tokens":4,"All Users":5}; thismod.data.utcode=gen={"model":0,"mod":1,"fan":2,"dpurp":3,"lpurp":4,"dblue":5,"lblue":6,"grey":7}; thismod.data.notify = [[1,0,0,0,0,0,0,0], [1,1,1,0,0,0,0,0], [1,1,1,1,1,0,0,0], [1,1,1,1,1,1,0,0], [1,1,1,1,1,1,1,0], [1,1,1,1,1,1,1,1]]; //thismod.data.emote={"E":String.fromCodePoint(0xff1d).repeat(2)+String.fromCodePoint(0x25b7).repeat(1),"L":String.fromCodePoint(0x25c1).repeat(1)+String.fromCodePoint(0xff1d).repeat(2),"F":String.fromCodePoint(0x1f525)}; thismod.data.emote={"E":String.fromCodePoint(0x2714),"L":String.fromCodePoint(0x274c),"F":String.fromCodePoint(0x1f525),">":String.fromCodePoint(0x25b7)}; thismod.data.msgpref={"E":"Welcome to the room","L":"See you again soon"}; thismod.data.color={"model":"#dc5500","grey":"#939393","lblue":"#6699aa","dblue":"#1e5cfb","lpurp":"#be6aff","dpurp":"#804baa","fan":"#009900","mod":"#dc0000"} cb.settings_choices.push( {name:`${thismod.name}_watch`,type:'choice',label:'Select which types of users that Enter/Leave notifications should be displayed for',required:true,defaultValue:'All Users', choice1:"No One",choice2:"All Users",choice3:"Mods & Fanclub Members",choice4:"Mods, Fanclub & Purple",choice5:"Mods, Fanclub, Purple & Dark Blue",choice6:"All users with Tokens"}, {name:`${thismod.name}_addusers`,type:'str',defaultValue:"",label:`List of specific Users to always show Enter/Leave notifications for (separated by commas, blank for none)`,required:false,maxLength:128}, {name:`${thismod.name}_nl`,type:'str',defaultValue:"",label:`List of additional users to be shown enter/leave notifications (separated by commas)`,required:false}, {name:`${thismod.name}_follow`,type:'choice',choice1:"-Yes-",choice2:"-No-",defaultValue:'-Yes-',label:'Display Follow/UnFollow Notifications?',required:true}, {name:`${thismod.name}_hnrmute`,type:'choice',choice1:"-Yes-",choice2:"-No-",defaultValue:'-Yes-',required:true, label:"Mute Hit\&Run User Notifications - users who leave the room right after entering will have notifications muted, but their activity can be viewed using the command \"/np report\""}, {name:`${thismod.name}_hnrtimer`,type:'int',defaultValue:5,label:'Hit&Run Timer (in seconds) - users that leave the room within this number of seconds will be considered a Hit&Run',required:true,minvalue:1}, {name:`${thismod.name}_hnralertct`,type:'int',defaultValue:10,required:true,minvalue:0, label:'Hit&Run Alert Count - An alert notice will be sent to the performer after a user commits this number of Hit&Runs (enter 0 for no alerts)'}, {name:`${thismod.name}_hnrrpttimer`,type:'int',defaultValue:15,label:'How often to display count of Hit&Run users (in minutes, 0 for never)',required:true,minvalue:0} ); thismod.events=["onCommand","onFollow","onUnFollow","onEnter","onLeave","onInit"]; thismod.funct = function(mode,c,m) { const u=c; const mod=modules[m]; let perf=[model,,...mod.data.nlist]; if (mode=="onCommand") { if (c.cmd==mod.cmd) { c.cmds[c.cmd]=1; if (c.ismod||c.ismodel) { if (c.cmdparmct==1&&(c.cmdparms[1]=="report"||c.cmdparms[1]=="rpt")) { let rpt=[],msg="",stats=mod.data.stats; for (const u in stats) {if (stats[u].hnr) {rpt.push({"name":stats[u].name,"hnr":stats[u].hnr,"ok":stats[u].ok})}} if (rpt.length) { msg+=`${wspc}Hit & Run Users:${wspc}`; rpt.sort((a, b)=>b.hnr-a.hnr); for (const h of rpt) {msg+=`\n${wspc3}${mod.data.emote['>']} ${h.name}: ${h.hnr} Hit & Runs, ${h.ok} legit sessions${wspc}`} } else {msg=wspc+"No hit and run users yet"} sendNotice(msg,c.user,mod.data.fgcol,mod.data.bgcol); return 1; } } else {badCommand("You are not authorized to run spamBlock commands",c); return 1;} } return 0; } else if (mode=="onFollow") { if (!mod.data.follow) {return;} let ut=c.user; perf.forEach(u=>sendNotice(wspc+mod.data.act.follow+ut+mod.data.gen[c.gender]+mod.data.col[mod.uType(c)],u,mod.data.perfcol,mod.data.bgcol)); } else if (mode=="onUnFollow") { if (!mod.data.follow) {return;} let ut=c.user; perf.forEach(u=>sendNotice(wspc+mod.data.act.leave+mod.data.act.follow+ut+mod.data.gen[c.gender]+mod.data.col[mod.uType(c)],u,mod.data.perfcol,mod.data.bgcol)); } else if (mode=="onEnter") { const st=mod.data.stats,un=u.user; if (!st[un]) {st[un]={"hnr":0,"ok":0,"name":un,sessions:[]}} const sesno=st[un].sessions.push({"status":"o","entered":new Date(),"exited":0})-1; setTimeout(()=>mod.checkHnR(c,sesno),Number(mod.data.hnrtimer)*1000); if (!mod.data.hnrmute) {mod.showNotif(u,'E')} } else if (mode=="onLeave") { const un=u.user; if (!mod.data.stats[un]) {return} const stus=mod.data.stats[un].sessions; for (const s of stus) { if (s.status!=="c") { const st=s.status; s.status="c"; s.exited=new Date(); if (st=='v'||!mod.data.hnrmute) {mod.showNotif(u,"L")} break; } } } else if (mode=="onInit") { sendNotice(`${wspc}Running module retNP${wspc}\n${wspc2}${mod.data.emote['>'].repeat(3)} In your broadcast settings screen (gear icon next to PM tab), `+ `set the Entry and Leave notifications to None${wspc2}`,model,mod.data.bgcol,mod.data.fgcol); readCBSettings(m); if (mod.data.nl) {notBlank(mod.data.nl.split(",")).forEach(e=>mod.data.nlist.push(e.toLowerCase()))} const addusers=mod.data.addusers+""; notBlank(addusers.split(",")).forEach(e=>{mod.data.adduser[e.toLowerCase()]=1}); if (mod.data.hnrrpttimer) {mod.hnrCount()} } return 0; } thismod['checkHnR'] = function(u,sesno) { const mod=modules['retNP']; const stu=mod.data.stats[u.user]; const s=stu.sessions[sesno]; if (s.status=="c") { stu.hnr++; if (mod.data.hnralertct==stu.hnr) {sendNotice(`${wspc}User ${u.user} has now had ${stu.hnr} Hit and Runs (and ${stu.ok} legit sessions)${wspc2}`,model,mod.data.bgcol,mod.data.fgcol)} } else { s.status="v"; stu.ok++; if (mod.data.hnrmute) {mod.showNotif(u,'E')} } } thismod['showNotif'] = function(u,mode) { const mod=modules['retNP']; const perf=[model,,...mod.data.nlist]; const ut=mod.uType(u); const utcol=mod.data.color[ut]; const utcode=mod.data.utcode[ut]; const emote=mod.data.emote[mode]; const msgpref=mod.data.msgpref[mode]; const watchcode=mod.data.watchcode[mod.data.watch]; if (mod.data.notify[watchcode][utcode]||mod.data.adduser[u.user]) { if (mode=="E") { perf.forEach(uu=>sendNotice(wspc+mod.data.act.enter+u.user+mod.data.gen[u.gender]+mod.data.col[mod.uType(u)],uu,mod.data.fgcol,mod.data.bgcol)); } else { perf.forEach(uu=>sendNotice(wspc+mod.data.act.leave+u.user+mod.data.gen[u.gender]+mod.data.col[mod.uType(u)],uu,mod.data.fgcol,mod.data.bgcol)); } } } thismod['hnrCount'] = function() { const mod=modules['retNP']; let ct=0,stats=mod.data.stats; for (const u in stats) {if (stats[u].hnr) {ct++}} if (ct) {sendNotice(`${wspc}There have been ${ct} Hit & Run users, type "/np report" for details${wspc2}`,model,mod.data.bgcol,mod.data.fgcol)} setTimeout(mod.hnrCount,Number(mod.data.hnrrpttimer)*60000); } thismod['uType'] = function(u) { const mod=modules['retNP']; if (u.user==model) {return "model"} else if (u.is_mod) {return "mod"} else if (u.in_fanclub) {return "fan"} else if (u.tipped_tons_recently) {return "dpurp"} else if (u.tipped_alot_recently) {return "lpurp"} else if (u.tipped_recently) {return "dblue"} else if (u.has_tokens) {return "lblue"} else {return "grey"} } thismod.summary = "Provides better control over notifications when users enter/leave/follow, and hides notifications for \"Hit \& Run\" users that immediately leave the room"; thismod.desc = "Allows more control over notifications for users who enter/leave the room or follow\n"+ "For example, can be used to only show notifications for specific users, and/or\n"+ "Block Enter/Leave notofications for \"Hit & Run\" users that leave the room immediately, and show them in a separate report\n"+ "**\n** Note - To avoid duplicate messages, in your broadcast settings screen (gear icon next to PM tab), set the Entry and Leave notifications to None\n**"; thismod.lparms = {'Enter/Leave Notification User Types': "Select which types of users that enter/leave notifications should be displayed for", 'List of specific Users to always show Enter/Leave notifications for': 'You may optionally enter a comma separated list of usernames that notifications will be shown for in addition to the user types specified above', 'Who should get notified when Users Enter/Leave?': "Select who should get notified when users enter/leave", 'Display Follow Thank You Notifications?': "Select whether a thank you notification should be displayed in the room for new followers", 'Mute Hit&Run User Notifications': "Users who leave the room right after entering will have notifications muted, but their activity can be viewed using the command \"/np report\"", 'Hit&Run Timer (in seconds)':'Users that leave the room within this number of seconds will be considered a Hit&Run', 'Hit&Run Alert Count':'An alert notice will be sent to the performer after a user commits this number of Hit&Runs (enter 0 for no alerts)', 'How often to display count of Hit & Run users':'Select frequency (in minutes) that the performer should be shown the Hit&Run user count (0 for no notifications)'} thismod.commands = {'*/np report': "Display a list of Hit $ Run users", '*/np rpt': "(Same as /np report)" }; /* ##################################################################################### # Module: ban (version 20211220.1741) ##################################################################################### */ modules['ban']={};thismod=modules['ban'];thismod.data={};modules.names.push('ban');thismod.name='ban'; thismod.cmd='ban'; thismod.data.fgcol="#ffffff";thismod.data.bgcol="#ff0000"; thismod.data.blist=[]; cb.settings_choices.push({name:`ban_notify`,type:'choice',choice1:"No One",choice2:"Model Only",choice3:"Model and Mods", default:"No One",label:'Show banned messages to:',required:true}); thismod.events=["onMessage","onCommand","onInit"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onMessage") { if (mod.data.blist[c.user.toLowerCase()]) { c.msg['X-Spam']=true; if (mod.data.notify=="Model and Mods") {sendNotice(`The following message was blocked from ${c.user}: ${c.msg.m}`,"",mod.data.bgcol,mod.data.fgcol,"","red")} if (mod.data.notify.substr(0,5)=="Model") {sendNotice(`The following message was blocked from ${c.user}: ${c.msg.m}`,model,mod.data.bgcol,mod.data.fgcol,)} return 1; } } else if (mode=="onCommand") { if (c.cmd==mod.cmd) { if (!c.ismodel && !c.ismod) {badCommand(`You are not authorized to run the ${mod.cmd} command`,c); return 1;} c.cmds[c.cmd]=1; if (c.cmdparmct==0) { let ul="There are no users on the banned list"; if (Object.keys(mod.data.blist).length>0) { ul=":blankx Banned List: :blankx\n"; Object.keys(mod.data.blist).forEach(u=>ul+=`:blankx - ${u} :blankx\n`); } sendNotice(ul,c.user,mod.data.fgcol,mod.data.bgcol); return 1; } else if (c.cmdparmct==1) { c.cmdparms[1]=c.cmdparms[1].toLowerCase(); if (c.cmdparms[1]=='del') {return 0;} mod.data.blist[c.cmdparms[1]]=1; mod.sN(`User ${c.cmdparms[1]} has been added to the banned list`,c); return 1; } else if (c.cmdparmct==2) { c.cmdparms[1]=c.cmdparms[1].toLowerCase();c.cmdparms[2]=c.cmdparms[2].toLowerCase(); if (c.cmdparms[1]!=="del") {return 0;} if (c.cmdparms[2]=="*") {mod.data.blist=[]; mod.sN(`All users removed from banned list`,c);} else if (mod.data.blist[c.cmdparms[2]]) {delete mod.data.blist[c.cmdparms[2]]; mod.sN(`User ${c.cmdparms[2]} removed from banned list`,c);} else {sendNotice(`User ${c.cmdparms[2]} is not on the banned list`,c.user,mod.data.fgcol,mod.data.bgcol);} return 1; } } } else if (mode=="onInit") {readCBSettings(m);} return 0; } thismod['sN'] = function(n,c) { sendNotice(n,c.user,mod.data.fgcol,mod.data.bgcol); if (c.user!==model) {sendNotice(n+" by "+c.user,model,mod.data.fgcol,mod.data.bgcol)} } thismod.lparms = {'Show banned messages to': "Select who should get a notification showing the message when a banned user chats"}; thismod.summary = "Ban users from chatting"; thismod.commands = {'/ban': 'Show banned list', '/ban [u]': 'Ban user [u]', '/ban del u|*': 'Remove user [u] from banned list (*=remove everyone)' }; /* ##################################################################################### # Module: Help (version 20211220.1829) ##################################################################################### */ modules['Help']={};thismod=modules['Help'];thismod.data={};modules.names.push('Help');thismod.name='Help'; thismod.data.fgcol="#000000";thismod.data.bgcol="#00ee00"; thismod.cmd="help"; thismod.events=["onCommand"]; thismod.funct = function(mode,c,m) { mod=modules[m]; if (mode=="onCommand") { if ((c.cmd==mod.cmd)||(c.cmd=="h")||(c.cmd=="?")) { c.cmds[c.cmd]=1; if (c.cmdparmct==0) { let h=`${wspc} Help for Bot ${botname}`; if (bothelp&&(typeof(bothelp)=="string")) {bothelp.split("\n").forEach(l=>{h+=`\n ${wspc} ${l}`})}; if (modules.names.length>0) { h+="\n"+wspc+" This Bot includes the following functions: \n"; for (const m of modules.names) { h+=` ${wspc} > "${m}"`; if (m.summary) {h+=` - ${m.summary}`;} h+=` \n`; } h+=wspc+" For help on one of these functions, type \"/help [function]\""; } sendNotice(h,c.user,mod.data.fgcol,mod.data.bgcol,"normal"); return 1; } else if (c.cmdparmct==1) { let cm = c.cmdparms[1]; if (cm!=='*') { let mfound=0; for (const m of modules.names) { if ((m==cm)||(m.toLowerCase()==cm)) {mfound=1;cm=m;} else if (modules[m].cmd) {if (modules[m].cmd.toLowerCase()==cm) {mfound=1;cm=m;}} } if (!mfound) {badCommand(`Function "${cm}" not found. Type "/help" for the list of functions in this Bot`,c); return 1;} let h1=` ${wspc} Help for function "${cm}"`; let cmod=modules[cm]; if (cmod.summary) {h1+=` (${cmod.summary})`;} let h2=""; if (cmod.desc) {cmod.desc.split("\n").forEach(l=>{h2+=` ${wspc} ${l}\n`});} if (cmod.commands && Object.keys(cmod.commands).length) { h2+=wspc2+" Commands: \n"; Object.keys(cmod.commands).forEach(c=>{ let nc=c; let mo=""; if (c.substr(0,1)=='*') {nc=c.substr(1);mo="(model/mods only)"} h2+=` ${wspc} > "${nc}" - ${cmod.commands[c]} ${mo} ${wspc}\n` }); } if (cmod.lparms && Object.keys(cmod.lparms).length) { h2+=wspc2+"\n ${wspc} Launch Parms: \n"; Object.keys(cmod.lparms).forEach(c=>{h2+=` ${wspc} > "${c}" - ${cmod.lparms[c]} ${wspc}\n`}); } if (h2=="") {sendNotice("No help found for function "+cm,c.user,mod.data.fgcol,mod.data.bgcol,"normal");} else {sendNotice(`${h1}\n${h2}`,c.user,mod.data.fgcol,mod.data.bgcol,"normal");} return 1; } else { let h=`Custom bot for <a href="https://chaturbate.com/${roomname}" style="color:#8888ff;text-decoration:underline;">`+ `${roomname}</a>'s room. Current modules included are: ${modnames}<br>`; for (const m of modules.names) { let mod=modules[m]; let mdesc=""; if (mod.summary) {mdesc=" - "+mod.summary;} h+=`<br><span style="font-style:italic;font-weight:bold;text-decoration:underline;color:#0000ff;">${m}</span><b>${mdesc}</b><br>`; if (mod.desc) {mod.desc.split("\n").forEach(l=>{h+=`${l}<br>`});} if (mod.commands && Object.keys(mod.commands).length) { h+=`<span style="text-decoration:underline;font-style:italic;font-weight:bold;color:#000000;">Commands</span><br>`; Object.keys(mod.commands).forEach(c=>{ let nc=c; let mo=""; if (c.substr(0,1)=='*') {nc=c.substr(1);mo="(model/mods only)"} h+=` > <span style="font-style:italic;color:#000000;font-weight:bold;">${nc}</span>`+ ` ${modules[m].commands[c]} ${mo}<br>`; }); } if (mod.lparms && Object.keys(mod.lparms).length) { h+=`<span style="text-decoration:underline;font-style:italic;font-weight:bold;color:#000000;">Launch Parameters</span><br>`; Object.keys(mod.lparms).forEach(c=>{ h+=` > <span style="font-style:italic;color:#000000;font-weight:bold;">${c}</span>`+ ` ${modules[m].lparms[c]}<br>`; }); } } sendNotice(`Copy this code to the bot description: ${h}`,c.user,"","","normal"); return 1; } } } } return 0; } thismod.summary = "get help on Bot functions and commands", thismod.desc = "Get help by typing /help, /h, or /?", thismod.commands = {'/h': "Get help on the Bot, and a list of all functions in the bot", '/h [function]': 'Get help on one of the functions in the bot, including it\'s commands', '/h *': "Display an auto-genertaed html description of the bot, that can be cut and paste into the Bot's description screen" }; bothelp="Retnabot by bot_factory"; /* ################################################ # AFTER MODULES HAVE BEEN PROCESSED, RUN INIT # ################################################ */ init();
© Copyright Chaturbate 2011- 2024. All Rights Reserved.