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 = $("