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.
This commit is contained in:
rainbownapkin 2022-07-23 09:24:19 +00:00
parent 46bcb040f2
commit fcb562397a
8 changed files with 389 additions and 49 deletions

View file

@ -200,15 +200,29 @@ dev goals for 1.1 pineapple express:
- merge tokebot into ourfore.st codebase, one server instead of two. - merge tokebot into ourfore.st codebase, one server instead of two.
- port chozobot code to cytube module ✓ - port chozobot code to cytube module ✓
- CRITICAL BUG FIX: Duplicate username during callout (test toking on multiple channels, etc...) - tokewhisper (server whisper, can optionally be displayed as PM client side) ✓
- load toke commands from tokes file - load toke commands from tokes file ✓
- tokewhisper (server whisper, can optionally be displayed as PM client side) - profile and userlist entry ✓
- profile and userlist entry(togglable clientside, on by default) - disable certain options in profile context menu ✓
- bot specific rank - mod commands ✓
- reset cooldown accessible from modmenu (quiet and loud, quiet by default) - reset cooldown command (quiet and loud, quiet by default) ✓
- log tokes w/ date to file. This will be switched to mariadb in the next update - siteowner commands ✓
- tokefile, list of usernames with toke count. This will be switched to mariadb in the next update - reload tokes command ✓
- total tokes listed on profile tooltip - 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 - autobump
- sepearate bump lists, based on js/txt files at first, will be stored in db next update (may use multiple at once) - 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) - require video be at least 4 minutes to add bump (mods can override from bump menu)
- finishing touches - 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: 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: 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: 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 - save temporary vids to channel library
- getplaylistlinks outputs in fpanel - getplaylistlinks outputs in fpanel
- display links - display links
- pop mod nmenu - pop mod nmenu
- css variables in theme for ez customizablity - 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 - 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) - 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) - 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 - pop out btn
- basic profile page (in side panel) - basic profile page (in side panel)
@ -247,7 +268,9 @@ dev goals for 1.1 pineapple express:
- getres - getres
- update minicont dur - update minicont dur
- update minicont buttons - update minicont buttons
- treez.one Now Playing in MOTD (these will need coordination with treez.one)
- treez.one tokebot syncronization (ESPECIALLY this one)
-
## License ## 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. 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.) (see the LICENSE file for the full text.)

View file

@ -624,13 +624,18 @@ Channel.prototype.maybeResendUserlist = function maybeResendUserlist(user, newRa
}; };
Channel.prototype.packUserData = function (user) { 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 = { var base = {
name: user.getName(), name: user.getName(),
rank: user.account.effectiveRank, rank: user.account.effectiveRank,
profile: user.account.profile, profile: user.account.profile,
meta: { meta: {
afk: user.is(Flags.U_AFK), 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), muted: user.is(Flags.U_MUTED),
smuted: user.is(Flags.U_SMUTED), smuted: user.is(Flags.U_SMUTED),
aliases: user.account.aliases, 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), muted: user.is(Flags.U_MUTED),
smuted: user.is(Flags.U_SMUTED), smuted: user.is(Flags.U_SMUTED),
aliases: user.account.aliases, 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(), name: user.getName(),
profile: user.account.profile profile: user.account.profile
}; };
users.forEach(function (u) { users.forEach(function (u) {
u.socket.emit("setUserProfile", packet); u.socket.emit("setUserProfile", packet);
}); });

View file

@ -17,8 +17,12 @@ import fs from 'fs';
var ChannelModule = require("./module"); 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'); const rawContents = fs.readFileSync("tokebot/tokes").toString('utf8');
var spcReg = /^\s*$/g; var spcReg = /^\s*$/g;
var t = rawContents.split("\n").filter(function(i){ var t = rawContents.split("\n").filter(function(i){
@ -27,12 +31,36 @@ function loadTokes(){
return t; 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){ function TokebotModule(_channel){
ChannelModule.apply(this, arguments); ChannelModule.apply(this, arguments);
//mod command registration //mod command registration
this.channel.modules.chat.registerCommand("!resettoke", this.resettoke.bind(this)); this.channel.modules.chat.registerCommand("!resettoke", this.resettoke.bind(this));
@ -45,21 +73,27 @@ function TokebotModule(_channel){
//!toke command registration //!toke command registration
this.updatetokes(); 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); TokebotModule.prototype = Object.create(ChannelModule.prototype);
//tokebot object properties
TokebotModule.prototype.toking = 0; TokebotModule.prototype.toking = 0;
TokebotModule.prototype.tokers = []; TokebotModule.prototype.tokers = [];
TokebotModule.prototype.cdown = 3; TokebotModule.prototype.cdown = 3;
TokebotModule.prototype.cdel = 120; TokebotModule.prototype.cdel = 120;
TokebotModule.prototype.ctime = 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 //mod commands
TokebotModule.prototype.resettoke = function(user, msg, _meta){ TokebotModule.prototype.resettoke = function(user, msg, _meta){
if(user.account.effectiveRank >= 2 && this.toking == 2){ if(user.account.effectiveRank >= 2 && this.toking == 2){
//this.toking = 0;
this.ctime = 0; this.ctime = 0;
this.tokewhisper("!toke cooldown reset.", user.account.name); 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) //main toke logic (adapted from chozobot implementation)
TokebotModule.prototype.toke = function (user, msg, _meta){ TokebotModule.prototype.toke = function (user, msg, _meta){
var name = user.getName() var name = user.getName()
@ -116,7 +155,7 @@ TokebotModule.prototype.toke = function (user, msg, _meta){
if(this.tokers.includes(name)){ if(this.tokers.includes(name)){
this.tokewhisper(" You're already taking part in this toke!", name); this.tokewhisper(" You're already taking part in this toke!", name);
}else{ }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.tokers.push(name);
this.cdown = 3; this.cdown = 3;
} }
@ -156,8 +195,9 @@ TokebotModule.prototype.endtoke = function (tb){
tb.tokesay("Take a toke " + callstring + "! " + tb.tokers.length + " tokers!"); tb.tokesay("Take a toke " + callstring + "! " + tb.tokers.length + " tokers!");
}else{ }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.tokers = [];
tb.toking = 2;//reset toking mode tb.toking = 2;//reset toking mode
setTimeout(tb.cooldown, 1000, tb); setTimeout(tb.cooldown, 1000, tb);
@ -181,9 +221,7 @@ TokebotModule.prototype.updatetokes = function (){
tokes = loadTokes(); tokes = loadTokes();
if(this.channel.modules.chat){//register !toke commands if(this.channel.modules.chat){//register !toke commands
if(tokes == null){//if for some reason tokes file couldnt be loaded 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");
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 }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 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){ tokes.forEach(function(tokec){
@ -200,7 +238,7 @@ TokebotModule.prototype.tokesay = function (msg,quiet){
meta:{ meta:{
addClass: (quiet ? null : "shout"), addClass: (quiet ? null : "shout"),
addClassToNameAndTimestamp: true, 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 modflair: 3
}, },
time: Date.now() time: Date.now()
@ -224,10 +262,46 @@ TokebotModule.prototype.tokewhisper = function (msg, usr){//(msg, username)
} }
} }
TokebotModule.prototype.getRandomInt = function (min, max) { //filesystem manipulation functions
min = Math.ceil(min); TokebotModule.prototype.writetokelog = function(){//append a toke to current channels toke log
max = Math.floor(max); var _this = this;
return Math.floor(Math.random() * (max - min) + min); //The maximum is exclusive and the minimum is inclusive 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; module.exports = TokebotModule;

View file

@ -30,7 +30,6 @@ hit
tjoke tjoke
tjokem tjokem
devilslettuce devilslettuce
tokem
toakem toakem
grass grass
liftoff liftoff
@ -71,7 +70,7 @@ justgirlythings
heyrainbowaddthis heyrainbowaddthis
inhale inhale
ignite ignite
THEPLANT theplant
spark spark
sparkone sparkone
sparkem sparkem
@ -81,3 +80,220 @@ witness
roastem roastem
crabpeople crabpeople
shootthemoon 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

View file

@ -192,6 +192,7 @@ body{
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
z-index: 2;
} }
#chatheader > p, #videowrap-header { #chatheader > p, #videowrap-header {

View file

@ -522,11 +522,27 @@ Callbacks = {
}, },
chatMsg: function(data) { chatMsg: function(data) {
if(data.username === "tokebot" && data.meta.addClass === "server-whisper" && USEROPTS.toke_pm){ if(data.username === "tokebot"){
data.meta = {}; 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); window.Callbacks.pm(data);
return; 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); addChatMessage(data);
}, },
@ -577,7 +593,6 @@ Callbacks = {
addUser: function(data) { addUser: function(data) {
CyTube._internal_do_not_use_or_you_will_be_banned.addUserToList(data, true); CyTube._internal_do_not_use_or_you_will_be_banned.addUserToList(data, true);
console.log(data);
sortUserlist(); sortUserlist();
}, },

View file

@ -207,8 +207,8 @@ $("#usercount").mousemove(function (ev) {
if(popup.length == 0) if(popup.length == 0)
return; return;
popup.css("top", (ev.clientY + 5) + "px"); popup.css("top", (ev.clientY + 5) - $("#usercount").parent().offset().top + "px");
popup.css("left", (ev.clientX - 120) + "px"); popup.css("left", (ev.clientX - 120) - $("#usercount").parent().offset().left + "px");
}); });
$("#usercount").mouseleave(function () { $("#usercount").mouseleave(function () {

View file

@ -184,6 +184,9 @@ function formatUserlistItem(div) {
$("<br/>").appendTo(profile); $("<br/>").appendTo(profile);
$("<em/>").text(meta.ip).appendTo(profile); $("<em/>").text(meta.ip).appendTo(profile);
} }
$("<br/>").appendTo(profile);
$("<em/>").text("tokes: " + div.data().meta.toke).appendTo(profile);
if (meta.aliases) { if (meta.aliases) {
$("<br/>").appendTo(profile); $("<br/>").appendTo(profile);
$("<em/>").text("aliases: " + meta.aliases.join(", ")).appendTo(profile); $("<em/>").text("aliases: " + meta.aliases.join(", ")).appendTo(profile);
@ -195,10 +198,11 @@ function formatUserlistItem(div) {
profile.css("left", horiz + "px") profile.css("left", horiz + "px")
}); });
name.mousemove(function(ev) { 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") profile.css("left", horiz + "px")
.css("top", top + "px"); .css("top", top + "px");
}); });
@ -494,10 +498,11 @@ function sortUserlist() {
}, },
meta: { meta: {
afk: false, afk: false,
aliases: [], aliases: ["tokebot"],
ip: "127.0.0.1", ip: "127.0.0.1",
muted: false, 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); assignColors(data.name);
var div = $("<div/>") var div = $("<div/>")
.addClass("userlist_item").attr('id', getColor(data.name)); .addClass("userlist_item").addClass("userlist_" + data.name).attr('id', getColor(data.name));
var icon = $("<span/>").appendTo(div); var icon = $("<span/>").appendTo(div);
var nametag = $("<span/>").text(data.name).appendTo(div); var nametag = $("<span/>").text(data.name).appendTo(div);
div.data("name", data.name); div.data("name", data.name);