From fcb562397a0688a696ffb1b54ed33a8335adb935 Mon Sep 17 00:00:00 2001 From: rainbownapkin Date: Sat, 23 Jul 2022 09:24:19 +0000 Subject: [PATCH] Finished tokebot implementation. tz and of tokes decapitalized and consolidated, !r added, toke log and per user toke count tracking. Toke count on tooltip. Improved moderator commands & tokebot output formatting. --- README.md | 49 ++++++--- src/channel/channel.js | 14 ++- src/channel/tokebot.js | 106 +++++++++++++++++--- tokebot/tokes | 220 ++++++++++++++++++++++++++++++++++++++++- www/css/cytube.css | 1 + www/js/callbacks.js | 25 ++++- www/js/ui.js | 4 +- www/js/util.js | 19 ++-- 8 files changed, 389 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 72b26730..de52895e 100644 --- a/README.md +++ b/README.md @@ -200,15 +200,29 @@ dev goals for 1.1 pineapple express: - merge tokebot into ourfore.st codebase, one server instead of two. - port chozobot code to cytube module ✓ - - CRITICAL BUG FIX: Duplicate username during callout (test toking on multiple channels, etc...) - - load toke commands from tokes file - - tokewhisper (server whisper, can optionally be displayed as PM client side) - - profile and userlist entry(togglable clientside, on by default) - - bot specific rank - - reset cooldown accessible from modmenu (quiet and loud, quiet by default) - - log tokes w/ date to file. This will be switched to mariadb in the next update - - tokefile, list of usernames with toke count. This will be switched to mariadb in the next update - - total tokes listed on profile tooltip + - tokewhisper (server whisper, can optionally be displayed as PM client side) ✓ + - load toke commands from tokes file ✓ + - profile and userlist entry ✓ + - disable certain options in profile context menu ✓ + - mod commands ✓ + - reset cooldown command (quiet and loud, quiet by default) ✓ + - siteowner commands ✓ + - reload tokes command ✓ + - tokesay command ✓ + - tokeannounce command ✓ + - tokewhisper command ✓ + - !r to rando-toke ✓ + - log tokes w/ date to file. This will be consolidated to a better toke history in mariadb in a future update + - append [tokers],# of tokers,timestamp(epoch) on toke. + - tokefile, list of usernames with toke count. This should eventually be moved to a property of account or user + - json of map ["username", # of tokes] ✓ + - load file on startup ✓ + - update file every toke ✓ + - total tokes listed on profile tooltip ✓ + - send toke count with user and set toke count ✓ + - display on tooltip ✓ + - add toke to profile client side on toke(avoid sending information twice, write after tokes in tooltip) ✓ + - include modflair on tokewhisper ✓ - autobump - sepearate bump lists, based on js/txt files at first, will be stored in db next update (may use multiple at once) @@ -219,17 +233,24 @@ dev goals for 1.1 pineapple express: - require video be at least 4 minutes to add bump (mods can override from bump menu) - finishing touches - - CRITICAL BUG FIX: video sometimes unlatches if sync delayed on video start.(Fix pre-latch, if not duration check until sync is past 2s?) - - CRITICAL BUG FIX: userlist profile tooltips are currently broken - - CRITICAL BUG FIX: chat does not fill screen in portrait mode (video height being subtracted while video collapsed) + - Critical Bug Fix: video sometimes unlatches if sync delayed on video start.(Fix pre-latch, if not duration check until sync is past 2s?) + - Critical Bug Fix: userlist profile & current connected users tooltips are currently broken ✓ + - Critical Bug Fix: chat does not fill screen in portrait mode (video height being subtracted while video collapsed) + - Critical Bug Fix: make serverside commands case insensitive(May have been intentional with cytube, don't give a shit, it's a bug.) + - Critical Bug Fix: serverside commands trigger other commands with same letters (!announce triggers !a) + - Minor Bug Fix: hide "close playlist" button when playlist is in fpanel + - Minor Bug Fix: Execute serverside commands with whitespace before them while also sending them as normal chat to comform to tokebot behavior in (v1)Panama Red + - add scrollTo() on fpplaylist open - save temporary vids to channel library - getplaylistlinks outputs in fpanel - display links - pop mod nmenu - css variables in theme for ez customizablity + - import data from old tokelog - merge fore.st theme changes to fore.st dusk, consider moving some of them over to cytube.css for easier management - extra shit(probs wait til next update, or hotfix) + - shared tokes across channels - short chats (acronyms, emoji, single letters/numbers/symbols) pop in over video from left starting at top left, overflow pops in below, instead of in chat box. Chats slide back up into top of vid after 2s. (optional, default on) - pop out btn - basic profile page (in side panel) @@ -247,7 +268,9 @@ dev goals for 1.1 pineapple express: - getres - update minicont dur - update minicont buttons - + - treez.one Now Playing in MOTD (these will need coordination with treez.one) + - treez.one tokebot syncronization (ESPECIALLY this one) + - ## License Original fore.st code is provided under the Affero General Public License v3 in order to prevent fore.st being used in proprietary software. (see the LICENSE file for the full text.) diff --git a/src/channel/channel.js b/src/channel/channel.js index f9cee189..7891a765 100644 --- a/src/channel/channel.js +++ b/src/channel/channel.js @@ -624,13 +624,18 @@ Channel.prototype.maybeResendUserlist = function maybeResendUserlist(user, newRa }; Channel.prototype.packUserData = function (user) { + var tc = 0; + if(this.modules.tokebot.statmap != null){ + tc = (this.modules.tokebot.statmap.get(user.getName()) == null ? 0 : this.modules.tokebot.statmap.get(user.getName())); + } var base = { name: user.getName(), rank: user.account.effectiveRank, profile: user.account.profile, meta: { afk: user.is(Flags.U_AFK), - muted: user.is(Flags.U_MUTED) && !user.is(Flags.U_SMUTED) + muted: user.is(Flags.U_MUTED) && !user.is(Flags.U_SMUTED), + toke: tc } }; @@ -643,7 +648,8 @@ Channel.prototype.packUserData = function (user) { muted: user.is(Flags.U_MUTED), smuted: user.is(Flags.U_SMUTED), aliases: user.account.aliases, - ip: user.displayip + ip: user.displayip, + toke: tc } }; @@ -656,7 +662,8 @@ Channel.prototype.packUserData = function (user) { muted: user.is(Flags.U_MUTED), smuted: user.is(Flags.U_SMUTED), aliases: user.account.aliases, - ip: user.realip + ip: user.realip, + toke: tc } }; @@ -697,7 +704,6 @@ Channel.prototype.sendUserProfile = function (users, user) { name: user.getName(), profile: user.account.profile }; - users.forEach(function (u) { u.socket.emit("setUserProfile", packet); }); diff --git a/src/channel/tokebot.js b/src/channel/tokebot.js index 407c6eef..64a8b760 100644 --- a/src/channel/tokebot.js +++ b/src/channel/tokebot.js @@ -17,8 +17,12 @@ import fs from 'fs'; var ChannelModule = require("./module"); +//global vars +var tokes = loadTokes(); +var solotokes = ["", "https://ourfore.st/img/femotes/onetoker.jpg","https://ourfore.st/img/femotes/solotoke.jpg","https://ourfore.st/img/femotes/1toker.gif"]; -function loadTokes(){ +//global functions +function loadTokes(){//load tokes as array from file const rawContents = fs.readFileSync("tokebot/tokes").toString('utf8'); var spcReg = /^\s*$/g; var t = rawContents.split("\n").filter(function(i){ @@ -27,12 +31,36 @@ function loadTokes(){ return t; } -var tokes = loadTokes(); +//used to store ES6 maps as arrays in JSON +function mapReplacer(key, value) { + if(value instanceof Map) { + return { + dataType: 'Map', + value: Array.from(value.entries()), // or with spread: value: [...value] + }; + } else { + return value; + } +} +function mapReviver(key, value) { + if(typeof value === 'object' && value !== null) { + if (value.dataType === 'Map') { + return new Map(value.value); + } + } + return value; +} + +function randi(len) {//get random number from zero to len, meant for use to pull random items from an array + return Math.floor(Math.random() * len); //The maximum is exclusive and the minimum is inclusive +} + + +//constructor function TokebotModule(_channel){ ChannelModule.apply(this, arguments); - //mod command registration this.channel.modules.chat.registerCommand("!resettoke", this.resettoke.bind(this)); @@ -45,21 +73,27 @@ function TokebotModule(_channel){ //!toke command registration this.updatetokes(); + this.channel.modules.chat.registerCommand("!r", this.randotoke.bind(this)); + + this.loadtfile();//load up toke stats from toke file. + + } +//protoype definition TokebotModule.prototype = Object.create(ChannelModule.prototype); +//tokebot object properties TokebotModule.prototype.toking = 0; TokebotModule.prototype.tokers = []; TokebotModule.prototype.cdown = 3; TokebotModule.prototype.cdel = 120; TokebotModule.prototype.ctime = 120; -TokebotModule.prototype.solotokes = ["", "https://ourfore.st/img/femotes/onetoker.jpg","https://ourfore.st/img/femotes/solotoke.jpg","https://ourfore.st/img/femotes/1toker.gif"]; +TokebotModule.prototype.statmap = null; //mod commands TokebotModule.prototype.resettoke = function(user, msg, _meta){ if(user.account.effectiveRank >= 2 && this.toking == 2){ - //this.toking = 0; this.ctime = 0; this.tokewhisper("!toke cooldown reset.", user.account.name); } @@ -98,6 +132,11 @@ TokebotModule.prototype.tokewhisperCmd = function(user, msg, _meta){ } } +//extra user commands +TokebotModule.prototype.randotoke = function(user, msg, _meta){ + this.toke(user, '!' + tokes[randi(tokes.length)],_meta); +} + //main toke logic (adapted from chozobot implementation) TokebotModule.prototype.toke = function (user, msg, _meta){ var name = user.getName() @@ -116,7 +155,7 @@ TokebotModule.prototype.toke = function (user, msg, _meta){ if(this.tokers.includes(name)){ this.tokewhisper(" You're already taking part in this toke!", name); }else{ - this.tokesay("joined the toke! Post " + msg + " to take part!"); + this.tokesay(name + " joined the toke! Post " + msg + " to take part!"); this.tokers.push(name); this.cdown = 3; } @@ -156,8 +195,9 @@ TokebotModule.prototype.endtoke = function (tb){ tb.tokesay("Take a toke " + callstring + "! " + tb.tokers.length + " tokers!"); }else{ - tb.tokesay("Take a toke " + tb.tokers.toString() + ". " + (tb.solotokes[tb.getRandomInt(0,tb.solotokes.length)])); + tb.tokesay("Take a toke " + tb.tokers.toString() + ". " + (solotokes[randi(solotokes.length)])); } + tb.logtoke(); tb.tokers = []; tb.toking = 2;//reset toking mode setTimeout(tb.cooldown, 1000, tb); @@ -181,9 +221,7 @@ TokebotModule.prototype.updatetokes = function (){ tokes = loadTokes(); if(this.channel.modules.chat){//register !toke commands - if(tokes == null){//if for some reason tokes file couldnt be loaded - this.channel.modules.chat.registerCommand("!toke", this.toke.bind(this)); - console.log("[tokebot] Unable to load toke commands from ./tokebot/tokes, defaulting to !toke definition"); + if(tokes == null){//if for some reason tokes file couldnt be loaded this.channel.modules.chat.registerCommand("!toke", this.toke.bind(this)); console.log("[tokebot] Unable to load toke commands from ./tokebot/tokes, defaulting to !toke definition"); }else{//if we we're able to pull toke commands var _this = this;//we need to use this, might put this up higher to replace the tb parameter in other member functions tokes.forEach(function(tokec){ @@ -200,7 +238,7 @@ TokebotModule.prototype.tokesay = function (msg,quiet){ meta:{ addClass: (quiet ? null : "shout"), addClassToNameAndTimestamp: true, - forceShowName: true, + forceShowName: (quiet ? true : false), //It's loud enough when announcing. Toke chats are rare enouhg to be more prominent :P modflair: 3 }, time: Date.now() @@ -224,10 +262,46 @@ TokebotModule.prototype.tokewhisper = function (msg, usr){//(msg, username) } } -TokebotModule.prototype.getRandomInt = function (min, max) { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min) + min); //The maximum is exclusive and the minimum is inclusive -}; +//filesystem manipulation functions +TokebotModule.prototype.writetokelog = function(){//append a toke to current channels toke log + var _this = this; + fs.appendFile("tokebot/" + this.channel.name + "_toke.log" ,('[' + this.tokers.toString() + '],' + this.tokers.length + ',' + new Date().getTime() + "\n"), function(err){ + if(err){ + console.log("[chan: " + _this.channel.name + "] TOKE LOG WRITE ERROR: " + err); + } + }); +} +TokebotModule.prototype.loadtfile = function(){//load tokefile into statmap(default to new Map() on error) + var _this = this; + fs.readFile("tokebot/" + this.channel.name + "_tokefile", function(err,data){ + if(err){ + console.log("[chan: " + _this.channel.name + "] TOKE FILE READ ERROR (may overwrite existing stat file!): " + err); + _this.statmap = new Map(); + }else{ + _this.statmap = JSON.parse(data, mapReviver); + } + }); +} + +TokebotModule.prototype.writetfile = function(){//write statmap to tokefile + var _this = this; + fs.writeFile("tokebot/" + this.channel.name + "_tokefile", JSON.stringify(_this.statmap, mapReplacer), function(err,data){ + if(err){ + console.log("[chan: " + _this.channel.name + "] TOKE FILE WRITE ERROR: " + err); + } + }); +} + +TokebotModule.prototype.logtoke = function(){ + this.writetokelog();//save toke to toke log + var _this = this; + + this.tokers.forEach(function (u){//for all tokers + var ct = _this.statmap.get(u);//lets make this a lil prettier :P + _this.statmap.set(u,(ct == null ? 1 : ++ct));//increment toke counter + }); + + this.writetfile();//write statmap to tfile +} module.exports = TokebotModule; diff --git a/tokebot/tokes b/tokebot/tokes index 815b3c7c..ce79bb67 100644 --- a/tokebot/tokes +++ b/tokebot/tokes @@ -30,7 +30,6 @@ hit tjoke tjokem devilslettuce -tokem toakem grass liftoff @@ -71,7 +70,7 @@ justgirlythings heyrainbowaddthis inhale ignite -THEPLANT +theplant spark sparkone sparkem @@ -81,3 +80,220 @@ witness roastem crabpeople shootthemoon +ballmastr +checkitout +brule +strangerthings +strange +silicon +goteamventure +snaildown +high +stoned +drunk +glazzballs +sin +vibe +frittata +breen +soup +robots +love +hootiehoo +pot +toe +feet +foot +science +horse +bagel +roach +ranch +weedistight +mattea +katebush +runningupthathill +running +morbin +yee +maidenless +smellyplants +foryourhealth +cromdar +cbd +yeet +viking +suck +vamp +sparkle +northman +jack +keanu +woof +yote +pizza +dudewhat +wine +red +beer +liquor +ipa +a +c +d +x +y +z +n +rat +smeg +meg +kegels +greasy +bullshitartist +spear +fang +brutal +dethklok +goodbye +tab +jfc +ghost +burger +toad +snek +pill +2count +doobie +dooby +yeehaw +debra +tree +69 +311 +buttstonked +trees +treez +plants +plantz +aliens +ollie +greatscott +121gigawatts +88mph +smokeweedblazeit +smek +cry +smook +justdudethings +oscarfever +007 +kiff +kief +jeff +gay +lesbian +bi +trans +queer +meow +tocar +fumar +ruhroh +spoop +tok +fight +club +stab +otke +greatergood +toker +tokes +toked +twunk +twonk +doublerainbow +kava +kratom +catjam +fuck +squanch +snortskie +zoinks +luckoftheirish +comeondown +ihaventeventriedityet +warter +water +death +dead +smokeweed +quack +clurb +coffee +duck +cum +nut +bong +piss +smok +basmati +meds +vitamins +protein +blazem", //^og tok +squirt +drinkwater +chug +olympic +marihuana +hooray +flambe +flambé +tenturnyourrainsoundsoff +jabroni +lame +yoke +reefer +bloke +hailsanta +tonks +henshin +maryjane +fart +shart +jinkies +whatastorymark +ohhaimark +cheep +bat +bats +batman +birdgirl +himbo +t +o +k +e +b +popcorn +puppy +puppybowl +superbowl +super +bowl +owl +kitty +crab +rso +drugs +drugz +spacesurf +birdup +eltoke +thistooshallpass +beber +wrasslin +her +yikes +booyak diff --git a/www/css/cytube.css b/www/css/cytube.css index d5cb3c96..78149642 100644 --- a/www/css/cytube.css +++ b/www/css/cytube.css @@ -192,6 +192,7 @@ body{ display: flex; flex-wrap: wrap; align-items: center; + z-index: 2; } #chatheader > p, #videowrap-header { diff --git a/www/js/callbacks.js b/www/js/callbacks.js index e9f555d7..e50abf19 100644 --- a/www/js/callbacks.js +++ b/www/js/callbacks.js @@ -522,10 +522,26 @@ Callbacks = { }, chatMsg: function(data) { - if(data.username === "tokebot" && data.meta.addClass === "server-whisper" && USEROPTS.toke_pm){ - data.meta = {}; - window.Callbacks.pm(data); - return; + if(data.username === "tokebot"){ + console.log(data); + if(data.meta.addClass === "server-whisper"){ + data.meta.modflair = 3; + if( USEROPTS.toke_pm){ + data.meta = { + modflair: 3 + }; + window.Callbacks.pm(data); + return; + } + }else if(data.meta.addClass === "shout" && data.msg.startsWith("Take a toke")){ + data.msg.split(" ").forEach(function(w){ + var n = w.slice(0,-1); + + if(usrColors[0].includes(n)){ + $(".userlist_" + n).data().meta.toke++; + } + }); + } } addChatMessage(data); }, @@ -577,7 +593,6 @@ Callbacks = { addUser: function(data) { CyTube._internal_do_not_use_or_you_will_be_banned.addUserToList(data, true); - console.log(data); sortUserlist(); }, diff --git a/www/js/ui.js b/www/js/ui.js index c422398f..a8e17d03 100644 --- a/www/js/ui.js +++ b/www/js/ui.js @@ -207,8 +207,8 @@ $("#usercount").mousemove(function (ev) { if(popup.length == 0) return; - popup.css("top", (ev.clientY + 5) + "px"); - popup.css("left", (ev.clientX - 120) + "px"); + popup.css("top", (ev.clientY + 5) - $("#usercount").parent().offset().top + "px"); + popup.css("left", (ev.clientX - 120) - $("#usercount").parent().offset().left + "px"); }); $("#usercount").mouseleave(function () { diff --git a/www/js/util.js b/www/js/util.js index 7232db3c..2d326588 100644 --- a/www/js/util.js +++ b/www/js/util.js @@ -184,6 +184,9 @@ function formatUserlistItem(div) { $("
").appendTo(profile); $("").text(meta.ip).appendTo(profile); } + + $("
").appendTo(profile); + $("").text("tokes: " + div.data().meta.toke).appendTo(profile); if (meta.aliases) { $("
").appendTo(profile); $("").text("aliases: " + meta.aliases.join(", ")).appendTo(profile); @@ -195,12 +198,13 @@ function formatUserlistItem(div) { profile.css("left", horiz + "px") }); name.mousemove(function(ev) { - var top = ev.clientY + 5; - var horiz = ev.clientX; - if ($("body").hasClass("synchtube")) horiz -= profile.outerWidth(); + var top = ev.clientY + 5 - div.parent().offset().top; + var horiz = ev.clientX - div.offset().left; + + //if ($("body").hasClass("synchtube")) horiz -= profile.outerWidth(); profile.css("left", horiz + "px") - .css("top", top + "px"); + .css("top", top + "px"); }); name.mouseleave(function() { profile.remove(); @@ -494,10 +498,11 @@ function sortUserlist() { }, meta: { afk: false, - aliases: [], + aliases: ["tokebot"], ip: "127.0.0.1", muted: false, - smuted: false + smuted: false, + toke: '∞' } } ); @@ -3555,7 +3560,7 @@ CyTube._internal_do_not_use_or_you_will_be_banned.addUserToList = function (data } assignColors(data.name); var div = $("
") - .addClass("userlist_item").attr('id', getColor(data.name)); + .addClass("userlist_item").addClass("userlist_" + data.name).attr('id', getColor(data.name)); var icon = $("").appendTo(div); var nametag = $("").text(data.name).appendTo(div); div.data("name", data.name);