diff --git a/package.json b/package.json index 796a0bb..cb166b1 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ }, "scripts": { "start": "node ./src/server.js", - "start:dev": "nodemon ./src/server.js" + "start:dev": "nodemon ./src/server.js", + "build": "node node_modules/jsdoc/jsdoc.js --recurse src/ --destination www/doc/" }, "devDependencies": { "nodemon": "^3.1.10", diff --git a/src/app/channel/media/playlistHandler.js b/src/app/channel/media/playlistHandler.js index 1d8ea1d..d9ead81 100644 --- a/src/app/channel/media/playlistHandler.js +++ b/src/app/channel/media/playlistHandler.js @@ -183,7 +183,7 @@ module.exports = class{ /** * Validates client requests to change default titles for a given playlist * @param {Object} data - Data handed over from the client - * @returns + * @returns {Array} Array of strings containing valid titles from the output */ changeDefaultTitlesValidator(data){ //Create empty array to hold titles diff --git a/src/app/channel/media/queuedMedia.js b/src/app/channel/media/queuedMedia.js index 5fbd77f..2ecb213 100644 --- a/src/app/channel/media/queuedMedia.js +++ b/src/app/channel/media/queuedMedia.js @@ -57,7 +57,7 @@ module.exports = class extends media{ * @param {media} media - Media object to queue * @param {Number} startTime - Start time formatted as a JS Epoch * @param {Number} startTimeStamp - Start time stamp in seconds - * @returns + * @returns {queuedMedia} queuedMedia object created from given media object */ static fromMedia(media, startTime, startTimeStamp){ //Create and return queuedMedia object from given media object and arguments @@ -75,7 +75,7 @@ module.exports = class extends media{ /** * Converts array of media objects into array of queuedMedia objects - * @param {[media]} mediaList - Array of media objects to queue + * @param {Array} mediaList - Array of media objects to queue * @param {Number} start - Start time formatted as JS Epoch * @returns Array of converted queued media objects */ diff --git a/src/utils/media/yanker.js b/src/utils/media/yanker.js index 5ff5c38..f16640d 100644 --- a/src/utils/media/yanker.js +++ b/src/utils/media/yanker.js @@ -26,7 +26,7 @@ const ytdlpUtil = require('./ytdlpUtils'); * Checks a given URL and runs the proper metadata fetching function to create a media object from any supported URL * @param {String} url - URL to yank media against * @param {String} title - Title to apply to yanked media - * @returns + * @returns {Array} Returns list of yanked media objects on success */ module.exports.yankMedia = async function(url, title){ //Get pull type diff --git a/www/doc/app_channel_activeChannel.js.html b/www/doc/app_channel_activeChannel.js.html new file mode 100644 index 0000000..22dd331 --- /dev/null +++ b/www/doc/app_channel_activeChannel.js.html @@ -0,0 +1,203 @@ + + + + + JSDoc: Source: app/channel/activeChannel.js + + + + + + + + + + +
+ +

Source: app/channel/activeChannel.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//local imports
+const connectedUser = require('./connectedUser');
+const chatBuffer = require('./chatBuffer');
+const queue = require('./media/queue');
+const channelModel = require('../../schemas/channel/channelSchema');
+const playlistHandler = require('./media/playlistHandler')
+
+/**
+ * Class representing a single active channel
+ */
+module.exports = class{
+
+    /**
+     * Instantiates an activeChannel object
+     * @param {channelManager} server - Parent Server Object
+     * @param {Mongoose.Document} chanDB  - chanDB to rehydrate buffer from
+     */
+    constructor(server, chanDB){
+        this.server = server;
+        this.name = chanDB.name;
+        this.tokeCommands = chanDB.tokeCommands;
+        //Keeping these in a map was originally a vestige but it's more preformant than an array or object so :P
+        this.userList = new Map();
+        this.queue = new queue(server, chanDB, this);
+        this.playlistHandler = new playlistHandler(server, chanDB, this);
+        //Define the chat buffer
+        this.chatBuffer = new chatBuffer(server, chanDB, this);
+    }
+
+
+    /**
+     * Handles server-side initialization for new connections to the channel
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     * @param {Socket} socket - Requesting Socket
+     */
+    async handleConnection(userDB, chanDB, socket){
+        //get current user object from the userlist
+        var userObj = this.userList.get(userDB.user);
+        //get channel rank for current user
+        const chanRank = await chanDB.getChannelRankByUserDoc(userDB);
+
+        //If user is already connected
+        if(userObj){
+            //Add this socket on to the userobject
+            userObj.sockets.push(socket.id);
+        //If the user is joining the channel
+        }else{
+            //Grab flair
+            await userDB.populate('flair');
+            //Set user object
+            userObj = new connectedUser(userDB, chanRank, this, socket);
+        }
+
+        //Set user entry in userlist
+        this.userList.set(userDB.user, userObj);
+
+        //if everything looks good, admit the connection to the channel
+        socket.join(socket.chan);
+
+        //Define per-channel event listeners
+        this.queue.defineListeners(socket);
+        this.playlistHandler.defineListeners(socket);
+
+        //Hand off the connection initiation to it's user object
+        await userObj.handleConnection(userDB, chanDB, socket)
+
+        //Send out the userlist
+        this.broadcastUserList(socket.chan);
+    }
+
+    /**
+     * Handles server-side initialization for disconnecting from the channel
+     * @param {Socket} socket - Requesting Socket
+     */
+    handleDisconnect(socket){
+        //If we have more than one active connection
+        if(this.userList.get(socket.user.user).sockets.length > 1){
+            //temporarily store userObj
+            var userObj = this.userList.get(socket.user.user);
+
+            //Filter out disconnecting socket from socket list, and set as current socket list for user
+            userObj.sockets = userObj.sockets.filter((id) => {
+                return id != socket.id;
+            });
+
+            //Update the userlist
+            this.userList.set(socket.user.user, userObj);
+        }else{
+            //If this is the last connection for this user, remove them from the userlist
+            this.userList.delete(socket.user.user);
+        }
+
+        //and send out the filtered list
+        this.broadcastUserList(socket.chan);
+    }
+
+    /**
+     * Broadcasts user list to all users
+     */
+    broadcastUserList(){
+        //Create a userlist object with the tokebot user pre-loaded
+        var userList = [{
+            user: "Tokebot",
+            flair: "classic",
+            highLevel: "∞",
+        }];
+        
+        this.userList.forEach((userObj, user) => {
+            userList.push({
+                user: user,
+                flair: userObj.flair,
+                highLevel: userObj.highLevel
+            });
+        });
+
+        this.server.io.in(this.name).emit("userList", userList);
+    }
+
+    /**
+     * Broadcasts channel emote list to connected users
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     */
+    async broadcastChanEmotes(chanDB){
+        //if we wherent handed a channel document
+        if(chanDB == null){
+            //Pull it based on channel name
+            chanDB = await channelModel.findOne({name: this.name});
+        }       
+
+        //Get emote list from channel document
+        const emoteList = chanDB.getEmotes();
+
+        //Broadcast that sumbitch
+        this.server.io.in(this.name).emit('chanEmotes', emoteList);
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_channelManager.js.html b/www/doc/app_channel_channelManager.js.html new file mode 100644 index 0000000..f94e5ef --- /dev/null +++ b/www/doc/app_channel_channelManager.js.html @@ -0,0 +1,354 @@ + + + + + JSDoc: Source: app/channel/channelManager.js + + + + + + + + + + +
+ +

Source: app/channel/channelManager.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Config
+const config = require('../../../config.json');
+
+//Local Imports
+const channelModel = require('../../schemas/channel/channelSchema');
+const emoteModel = require('../../schemas/emoteSchema');
+const {userModel} = require('../../schemas/user/userSchema');
+const userBanModel = require('../../schemas/user/userBanSchema');
+const loggerUtils = require('../../utils/loggerUtils');
+const csrfUtils = require('../../utils/csrfUtils');
+const activeChannel = require('./activeChannel');
+const chatHandler = require('./chatHandler');
+
+/**
+ * Class containing global server-side channel connection management logic
+ */
+module.exports = class{
+    /**
+     * Instantiates object containing global server-side channel conection management logic
+     * @param {Server} io - Socket.io server instanced passed down from server.js 
+     */
+    constructor(io){
+        //Set the socket.io server
+        this.io = io;
+
+        //Load
+        this.activeChannels = new Map;
+
+        //Load server components
+        this.chatHandler = new chatHandler(this);
+        //this.mediaYanker = new mediaYanker(this);
+
+        //Handle connections from socket.io
+        io.on("connection", this.handleConnection.bind(this) );
+    }
+
+    /**
+     * Handles global server-side initialization for new connections to any channel
+     * @param {Socket} socket - Requesting Socket
+     */
+    async handleConnection(socket){
+        try{
+            //ensure unbanned ip and valid CSRF token
+            if(!(await this.validateSocket(socket))){
+                socket.disconnect();
+                return;
+            }
+
+            //Prevent logged out connections and authenticate socket
+            if(socket.request.session.user != null){
+                //Authenticate socket
+                const userDB = await this.authSocket(socket);
+
+                //Get the active channel based on the socket
+                var {activeChan, chanDB} = await this.getActiveChan(socket);
+
+                //Check for chan ban
+                const ban = await chanDB.checkBanByUserDoc(userDB);
+                if(ban != null){
+                    //Toss out banned user's
+                    if(ban.expirationDays < 0){
+                        socket.emit("kick", {type: "kicked", reason: "You have been permanently banned from this channel!"});
+                    }else{
+                        socket.emit("kick", {type: "kicked", reason: `You have been temporarily banned from this channel, and will be unbanned in ${ban.getDaysUntilExpiration()} day(s)!`});
+                    }
+                    socket.disconnect();
+                    return;
+                }
+
+                //Define listeners for inter-channel classes
+                this.defineListeners(socket);
+                this.chatHandler.defineListeners(socket);
+
+                //Hand off the connection to it's given active channel object
+                //Lil' hacky to pass chanDB like that, but why double up on DB calls?
+                activeChan.handleConnection(userDB, chanDB, socket);
+            }else{
+                //Toss out anon's
+                socket.emit("kick", {type: "disconnected", reason: "You must log-in to join this channel!"});
+                socket.disconnect();
+                return;
+            }
+        }catch(err){
+            //Flip a table if something fucks up
+            return loggerUtils.socketCriticalExceptionHandler(socket, err);
+        } 
+    }
+
+    /**
+     * Global server-side validation logic for new connections to any channel
+     * @param {Socket} socket - Requesting Socket
+     * @returns {Boolean} true on success
+     */
+    async validateSocket(socket){
+        //If we're proxied use passthrough IP
+        const ip = config.proxied ? socket.handshake.headers['x-forwarded-for'] : socket.handshake.address;
+
+        //Look for ban by IP
+        const ipBanDB = await userBanModel.checkBanByIP(ip);
+
+        //If this ip is randy bobandy
+        if(ipBanDB != null){
+            //Make the number a little prettier despite the lack of precision since we're not doing calculations here :P
+            const expiration = ipBanDB.getDaysUntilExpiration() < 1 ? 0 : ipBanDB.getDaysUntilExpiration();
+
+            //If the ban is permanent
+            if(ipBanDB.permanent){
+                //tell it to fuck off
+                socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been permanently banned. Your cleartext IP has been saved to the database. Any associated accounts will be nuked in ${expiration} day(s).`});
+            //Otherwise
+            }else{
+                //tell it to fuck off
+                socket.emit("kick", {type: "kicked", reason: `The IP address you are trying to connect from has been temporarily banned. Your cleartext IP has been saved to the database until the ban expires in ${expiration} day(s).`});
+            }
+
+
+            return false;
+        }
+
+
+        //Check for Cross-Site Request Forgery
+        if(!csrfUtils.isRequestValid(socket.request)){
+            socket.emit("kick", {type: "disconnected", reason: "Invalid CSRF Token!"});
+            return false;
+        }
+
+
+        return true;
+    }
+
+    /**
+     * Global server-side authorization logic for new connections to any channel
+     * @param {Socket} socket - Requesting Socket
+     * @returns {Mongoose.Document} - Authorized User Document upon success
+     */
+    async authSocket(socket){
+        //Find the user in the Database since the session won't store enough data to fulfill our needs :P
+        const userDB = await userModel.findOne({user: socket.request.session.user.user});
+
+        if(userDB == null){
+            throw loggerUtils.exceptionSmith("User not found!", "unauthorized");
+        }
+
+        //Set socket user and channel values
+        socket.user = {
+            id: userDB.id,
+            user: userDB.user,
+        };
+
+        return userDB;
+    }
+
+    /**
+     * Gets active channel from a given socket
+     * @param {Socket} socket - Socket to check
+     * @returns {Object} Object containing users active channel name and channel document object
+     */
+    async getActiveChan(socket){
+        socket.chan = socket.handshake.headers.referer.split('/c/')[1].split('/')[0];
+        const chanDB = (await channelModel.findOne({name: socket.chan}));
+
+        //Check if channel exists
+        if(chanDB == null){
+            throw loggerUtils.exceptionSmith("Channel not found", "validation");
+        }
+
+        //Check if current channel is active
+        var activeChan = this.activeChannels.get(socket.chan);
+
+        if(!activeChan){
+            //If not, make it so
+            activeChan = new activeChannel(this, chanDB);
+            this.activeChannels.set(socket.chan, activeChan);
+        }
+
+        //Return whatever the active channel is (new or old)
+        return {activeChan, chanDB};
+    }
+
+    /**
+     * Define Global Server-Side socket event listeners
+     * @param {Socket} socket - Socket to check
+     */
+    defineListeners(socket){
+        //Socket Listeners
+        socket.conn.on("close", (reason) => {this.handleDisconnect(socket, reason)});
+    }
+
+    /**
+     * Global server-side logic for handling disconncted sockets
+     * @param {Socket} socket - Socket to check
+     * @param {String} reason - Reason for disconnection
+     */
+    handleDisconnect(socket, reason){
+        var activeChan = this.activeChannels.get(socket.chan);
+        activeChan.handleDisconnect(socket, reason);
+    }
+
+    /**
+     * Pulls user information by socket
+     * @param {Socket} socket - Socket to check
+     * @return returns related user info
+     */
+    getSocketInfo(socket){
+        const channel = this.activeChannels.get(socket.chan);
+        return channel.userList.get(socket.user.user);
+    }
+
+    /**
+     * Pulls user information by socket
+     * @param {Socket} socket - Socket to check
+     * @return returns related user info
+     */
+    getConnectedChannels(socket){
+        //Create a list to hold connected channels
+        var chanList = [];
+
+        //For each channel
+        this.activeChannels.forEach((channel) => {
+            //Check and see if the user is connected
+            const foundUser = channel.userList.get(socket.user.user);
+
+            //If we found a user and this channel hasn't been added to the list
+            if(foundUser){
+                chanList.push(channel);
+            }
+        });
+
+        //return the channels this user is connected to
+        return chanList;
+    }
+
+    /**
+     * Iterates through connections by a given username, and runs them through a given callback function/method
+     * @param {String} user - Username to crawl connections against
+     * @param {Function} cb - Callback function to run active connections of a given user against
+     */
+    crawlConnections(user, cb){
+        //For each channel
+        this.activeChannels.forEach((channel) => {
+            //Check and see if the user is connected
+            const foundUser = channel.userList.get(user);
+
+            //If we found a user and this channel hasn't been added to the list
+            if(foundUser){
+                cb(foundUser);
+            }
+        });    
+    }
+
+    /**
+     * Iterates through connections by a given username, and runs them through a given callback function/method
+     * @param {String} user - Username to crawl connections against
+     * @param {Function} cb - Callback function to run active connections of a given user against
+     */
+    getConnections(user){
+        //Create a list to store our connections
+        var connections = [];
+
+        //crawl through connections
+        //this.crawlConnections(user,(foundUser)=>{connections.push(foundUser)});
+        this.crawlConnections(user,(foundUser)=>{connections.push(foundUser)});
+
+        //return connects
+        return connections;
+    }
+
+    /**
+     * Kicks a user from all channels by username
+     * @param {String} user - Username to kick from the server
+     * @param {String} reason - Reason for kick
+     */
+    kickConnections(user, reason){
+        //crawl through connections and kick user
+        this.crawlConnections(user,(foundUser)=>{foundUser.disconnect(reason)});
+    }
+
+    /**
+     * Broadcast global emote list
+     */
+    async broadcastSiteEmotes(){
+        //Get emote list from DB
+        const emoteList = await emoteModel.getEmotes();
+
+        //Broadcast that sumbitch
+        this.io.sockets.emit('siteEmotes', emoteList);
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_chat.js.html b/www/doc/app_channel_chat.js.html new file mode 100644 index 0000000..9cdcac6 --- /dev/null +++ b/www/doc/app_channel_chat.js.html @@ -0,0 +1,90 @@ + + + + + JSDoc: Source: app/channel/chat.js + + + + + + + + + + +
+ +

Source: app/channel/chat.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+/**
+ * Class representing a single chat message
+ */
+class chat{
+    /**
+     * Instantiates a chat message object
+     * @param {connectedUser} user - User who sent the message
+     * @param {String} flair - Flair ID String for the flair used to send the message
+     * @param {Number} highLevel - Number representing current high level
+     * @param {String} msg - Contents of the message, with links replaced with numbered file-seperator markers
+     * @param {String} type - Message Type Identifier, used for client-side processing.
+     * @param {Array} links - Array of URLs/Links included in the message.
+     */
+    constructor(user, flair, highLevel, msg, type, links){
+        this.user = user;
+        this.flair = flair;
+        this.highLevel = highLevel;
+        this.msg = msg;
+        this.type = type;
+        this.links = links;
+    }
+}
+
+module.exports = chat;
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_chatBuffer.js.html b/www/doc/app_channel_chatBuffer.js.html new file mode 100644 index 0000000..95225b3 --- /dev/null +++ b/www/doc/app_channel_chatBuffer.js.html @@ -0,0 +1,187 @@ + + + + + JSDoc: Source: app/channel/chatBuffer.js + + + + + + + + + + +
+ +

Source: app/channel/chatBuffer.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+const config = require('../../../config.json');
+const channelModel = require('../../schemas/channel/channelSchema');
+
+/**
+ * Class representing a stored chat buffer
+ */
+class chatBuffer{
+    /**
+     * Instantiates a new chat buffer for a given channel
+     * @param {channelManager} server - Parent Server Object
+     * @param {Mongoose.Document} chanDB  - chanDB to rehydrate buffer from
+     * @param {activeChannel} channel  - Parent Channel Object
+     */
+    constructor(server, chanDB, channel){
+        //Grab parent server and chan objects
+        this.server = server;
+        this.channel = channel;
+
+        //If we have no chanDB.chatBuffer
+        if(chanDB == null || chanDB.chatBuffer == null){
+            //Create RAM-based buffer array
+            this.buffer = [];
+        //Otherwise
+        }else{
+            //Pull buffer from DB
+            this.buffer = chanDB.chatBuffer;
+        }
+
+        //Create variables to hold timers for deciding when to write RAM buffer to DB
+        //Goes off 'this.inactivityDelay' seconds after the last chat was sent, assuming it isn't interrupted by new chats
+        this.inactivityTimer = null;
+        this.inactivityDelay = 10;
+        //Goes off 'this.busyDelay' minutes after the first chat message in the current volley of messages. Get's cancelled before being called if this.inactivityTimer goes off.
+        this.busyTimer = null;
+        this.busyDelay = 5;
+    }
+
+    /**
+     * Adds a given chat to the chat buffer in RAM and sets any appropriate timers for DB transactions
+     * @param {chat} chat - Chat object to commit to buffer
+     */
+    push(chat){
+        //push chat into RAM buffer
+        this.buffer.push(chat);
+        
+        //clear existing inactivity timer
+        clearTimeout(this.inactivityTimer);
+
+        //reset inactivity timer
+        this.inactivityTimer = setTimeout(this.handleInactivity.bind(this), 1000 * this.inactivityDelay);
+
+        //If busy timer is unset
+        if(this.busyTimer == null){
+            this.busyTimer = setTimeout(this.handleBusyRoom.bind(this), 1000 * 60 * this.busyDelay);
+        }
+    }
+
+    /**
+     * Removes the oldest item from the chat buffer
+     * 
+     * Was originally created in-case we needed to trigger timing functions
+     * 
+     * Left here since it seems like good form anywho, since this would be a private, or at least protected member in another language
+     */
+    shift(){
+        this.buffer.shift();
+    }
+
+    /**
+     * Called after 10 seconds of chat room inactivity
+     */
+    handleInactivity(){
+        this.saveDB(`${this.inactivityDelay} seconds of inactivity.`);
+    }
+
+    /**
+     * Called after 5 minutes of solid activity
+     */
+    handleBusyRoom(){
+        this.saveDB(`${this.busyDelay} minutes of activity.`);
+    }
+
+    /**
+     * Saves RAM-Based buffer to Channel Document in DB 
+     * @param {String} reason - Reason for DB save, formatted as 'x minutes/seconds of in/activity', used for logging purposes
+     * @param {Mongoose.Document} chanDB - Channel Doc to work with, can be left empty for method to auto-find through channel name.
+     */
+    async saveDB(reason, chanDB){
+        //clear existing timers
+        clearTimeout(this.inactivityTimer);
+        clearTimeout(this.busyTimer);
+        this.inactivityTimer = null;
+        this.busyTimer = null;
+
+        //if the server is in screamy boi mode
+        if(config.verbose){
+            //This should eventually be replaced by a per-channel logging feature that provides access to chan admins via web front-end
+            console.log(`Saving chat buffer to channel ${this.channel.name} after ${reason}.`);
+        }
+
+
+        //If we wheren't handed a channel
+        if(chanDB == null){
+            //Now that everything is clean, we can take our time with the DB :P
+            chanDB = await channelModel.findOne({name:this.channel.name});
+        }
+
+        //If we couldn't find the channel
+        if(chanDB == null){
+            //FUCK
+            throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while saving chat buffer!`, "chat");
+        }
+
+        //Set chan doc buffer to RAM buffer
+        chanDB.chatBuffer = this.buffer;
+
+        //save chan doc to DB.
+        await chanDB.save();
+    }
+}
+
+module.exports = chatBuffer;
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_chatHandler.js.html b/www/doc/app_channel_chatHandler.js.html new file mode 100644 index 0000000..acef38a --- /dev/null +++ b/www/doc/app_channel_chatHandler.js.html @@ -0,0 +1,383 @@ + + + + + JSDoc: Source: app/channel/chatHandler.js + + + + + + + + + + +
+ +

Source: app/channel/chatHandler.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM imports
+const validator = require('validator')
+
+//local imports
+const commandPreprocessor = require('./commandPreprocessor');
+const loggerUtils = require('../../utils/loggerUtils');
+const linkUtils = require('../../utils/linkUtils');
+const emoteValidator = require('../../validators/emoteValidator');
+const chat = require('./chat');
+const {userModel} = require('../../schemas/user/userSchema');
+
+/**
+ * Class containing global server-side chat relay logic
+ */
+module.exports = class{
+    /**
+     * Instantiates a chatHandler object
+     * @param {channelManager} server - Parent Server Object
+     */
+    constructor(server){
+        //Set server
+        this.server = server;
+        //Initialize command preprocessor
+        this.commandPreprocessor = new commandPreprocessor(server, this)
+        //Max chat buffer size
+        this.chatBufferSize = 50;
+    }
+
+    /**
+     * Defines global server-side chat relay event listeners
+     * @param {Socket} socket - Requesting Socket
+     */
+    defineListeners(socket){
+        socket.on("chatMessage", (data) => {this.handleChat(socket, data)});
+        socket.on("setFlair", (data) => {this.setFlair(socket, data)});
+        socket.on("setHighLevel", (data) => {this.setHighLevel(socket, data)});
+        socket.on("addPersonalEmote", (data) => {this.addPersonalEmote(socket, data)});
+        socket.on("deletePersonalEmote", (data) => {this.deletePersonalEmote(socket, data)});
+    }
+
+    /**
+     * Handles incoming chat messages from client connections
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {Object} data - Event payload
+     */
+    handleChat(socket, data){
+        this.commandPreprocessor.preprocess(socket, data);
+    }
+
+    /**
+     * Handles incoming client request to change flair 
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {Object} data - Event payload
+     */
+    async setFlair(socket, data){
+        var userDB = await userModel.findOne({user: socket.user.user});
+
+        if(userDB){
+            try{
+                //We can take this data raw since our schema checks it against existing flairs, and mongoose sanatizes queries
+                const flairDB = await userDB.setFlair(data.flair);
+
+                //Crawl through users active connections
+                this.server.crawlConnections(socket.user.user, (conn)=>{
+                    //Update flair
+                    conn.updateFlair(flairDB.name);
+                });
+            }catch(err){
+                return loggerUtils.socketExceptionHandler(socket, err);
+            }
+        }
+    }
+
+    /**
+     * Handles incoming client request to change high level 
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {Object} data - Event payload
+     */
+    async setHighLevel(socket, data){
+        var userDB = await userModel.findOne({user: socket.user.user});
+
+        if(userDB){
+            try{
+                //Floor input to an integer and set high level
+                userDB.highLevel = Math.floor(data.highLevel);
+                //Save user DB Document
+                await userDB.save();
+
+                //GetConnects across all channels
+                const connections = this.server.getConnections(socket.user.user);
+
+                //For each connection
+                connections.forEach((conn) => {
+                    conn.updateHighLevel(userDB.highLevel);
+                });
+            }catch(err){
+                return loggerUtils.socketExceptionHandler(socket, err);
+            }
+        }
+    }
+
+    /**
+     * Handles incoming client request to add a personal emote
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {Object} data - Event payload
+     */
+    async addPersonalEmote(socket, data){
+        //Sanatize and Validate input
+        const name = emoteValidator.manualName(data.name);
+        const link = emoteValidator.manualLink(data.link);
+        
+        //If we received good input
+        if(link && name){
+            //Generate marked link object
+            var emote = await linkUtils.markLink(link);
+
+            //If the link we have is an image or video
+            if(emote.type == 'image' || emote.type == 'video'){
+                //Get user document from DB
+                const userDB = await userModel.findOne({user: socket.user.user})
+
+                //if we have a user in the DB
+                if(userDB != null){
+                    //Convert marked link into emote object with 1 ez step for only $19.95
+                    emote.name = name;
+
+                    //add emote to user document emotes list
+                    userDB.emotes.push(emote);
+
+                    //Save user doc
+                    await userDB.save();
+                }
+            }
+        }
+    }
+
+    /**
+     * Handles incoming client request to delete a personal emote
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {Object} data - Event payload
+     */
+    async deletePersonalEmote(socket, data){
+        //Get user doc from DB based on socket
+        const userDB = await userModel.findOne({user: socket.user.user});
+
+        //if we found a user
+        if(userDB != null){
+            await userDB.deleteEmote(data.name);
+        }
+    }
+
+    //Base chat functions
+    /**
+     * Creates a new chatObject and relays the resulting message to the given channel
+     * @param {String} user - Originating user
+     * @param {String} flair - Flair ID to mark chat with
+     * @param {Number} highLevel - High Level to mark chat with
+     * @param {String} msg - Message Text Content
+     * @param {String} type - Message Type, used for client-side chat post-processing.
+     * @param {String} chan - Channel to broadcast message within
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayChat(user, flair, highLevel, msg, type = 'chat', chan, links){
+        this.relayChatObject(chan, new chat(user, flair, highLevel, msg, type, links));
+    }
+
+    /**
+     * Relays an existing chat object to a channel
+     * @param {String} chan - Channel to broadcast message within
+     * @param {chat} chat - Chat Object representing the message to broadcast to the given channel
+     */
+    relayChatObject(chan, chat){
+        //Send out chat
+        this.server.io.in(chan).emit("chatMessage", chat);
+
+        const channel = this.server.activeChannels.get(chan);
+
+        //If chat buffer length is over mandated size
+        if(channel.chatBuffer.buffer.length >= this.chatBufferSize){
+            //Take out oldest chat
+            channel.chatBuffer.shift();
+        }
+
+        //Add buffer to chat
+        channel.chatBuffer.push(chat);
+    }
+
+    /**
+     * Creates a new chatObject and relays the resulting message to the given socket
+     * @param {Socket} socket - Socket we're sending a message to (sounds menacing, huh?)
+     * @param {String} user - Originating user
+     * @param {String} flair - Flair ID to mark chat with
+     * @param {Number} highLevel - High Level to mark chat with
+     * @param {String} msg - Message Text Content
+     * @param {String} type - Message Type, used for client-side chat post-processing.
+     * @param {String} chan - Channel to broadcast message within
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayPrivateChat(socket, user, flair, highLevel, msg, type, links){
+        this.relayPrivateChatObject(socket , new chat(user, flair, highLevel, msg, type, links));
+    }
+
+    /**
+     * Handles incoming client request to delete a personal emote
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {Object} data - Event payload
+     */
+    relayPrivateChatObject(socket, chat){
+        socket.emit("chatMessage", chat);
+    }
+
+    /**
+     * Creates a new chatObject and relays the resulting message to the entire server
+     * @param {String} user - Originating user
+     * @param {String} flair - Flair ID to mark chat with
+     * @param {Number} highLevel - High Level to mark chat with
+     * @param {String} msg - Message Text Content
+     * @param {String} type - Message Type, used for client-side chat post-processing.
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayGlobalChat(user, flair, highLevel, msg, type = 'chat', links){
+        this.relayGlobalChatObject(new chat(user, flair, highLevel, msg, type, links));
+    }
+
+    /**
+     * Relays an existing chat object to the entire server
+     * @param {chat} chat - Chat Object representing the message to broadcast throughout the server
+     */
+    relayGlobalChatObject(chat){
+        this.server.io.emit("chatMessage", chat);
+    }
+
+    //User Chat Functions
+    /**
+     * Relays a chat message from a user to the rest of the channel based on socket
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {String} msg - Message Text Content
+     * @param {String} type - Message Type, used for client-side chat post-processing.
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayUserChat(socket, msg, type, links){
+        const user = this.server.getSocketInfo(socket);
+        this.relayChat(user.user, user.flair, user.highLevel, msg, type, socket.chan, links);
+    }
+
+    //Toke Chat Functions
+    /**
+     * Broadcasts toke callout to the server
+     * @param {String} msg - Message Text Content
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayTokeCallout(msg, links){
+        this.relayGlobalChat("Tokebot", "", '∞', msg, "toke", links);
+    }
+    /**
+     * Broadcasts toke callout to the server
+     * @param {Socket} socket - Socket we're sending the whisper to
+     * @param {String} msg - Message Text Content
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayTokeWhisper(socket, msg, links){
+        this.relayPrivateChat(socket, "Tokebot", "", '∞', msg, "tokewhisper", links);
+    }
+
+    /**
+     * Broadcasts toke whisper to the server
+     * @param {String} msg - Message Text Content
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayGlobalTokeWhisper(msg, links){
+        this.relayGlobalChat("Tokebot", "", '∞', msg, "tokewhisper", links);
+    }
+
+    //Announcement Functions
+    /**
+     * Broadcasts announcement to the server
+     * @param {String} msg - Message Text Content
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayServerAnnouncement(msg, links){
+        this.relayGlobalChat("Server", "", '∞', msg, "announcement", links);
+    }
+
+    /**
+     * Broadcasts announcement to a given channel
+     * @param {String} msg - Message Text Content
+     * @param {Array} links - Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+     */
+    relayChannelAnnouncement(chan, msg, links){
+        const activeChan = this.server.activeChannels.get(chan);
+
+        //If channel isn't null
+        if(activeChan != null){
+            this.relayChat("Channel", "", '∞', msg, "announcement", chan, links);
+        }
+    }
+
+    //Misc Functions
+    /**
+     * Clears chat for a given channel, targets specified user or entire channel if none found/specified.
+     * @param {String} user - User chats to clear
+     * @param {String} chan - Channel to broadcast message within
+     */
+    clearChat(chan, user){
+        const activeChan = this.server.activeChannels.get(chan);
+
+        //If channel isn't null
+        if(activeChan != null){
+            const target = activeChan.userList.get(user);
+
+            //If no user was entered OR the user was found
+            if(user == null || target != null){
+                this.server.io.in(chan).emit("clearChat", {user});
+            }
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_commandPreprocessor.js.html b/www/doc/app_channel_commandPreprocessor.js.html new file mode 100644 index 0000000..c3fb194 --- /dev/null +++ b/www/doc/app_channel_commandPreprocessor.js.html @@ -0,0 +1,480 @@ + + + + + JSDoc: Source: app/channel/commandPreprocessor.js + + + + + + + + + + +
+ +

Source: app/channel/commandPreprocessor.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const validator = require('validator');//No express here, so regular validator it is!
+
+//Local Imports
+const tokebot = require('./tokebot');
+const linkUtils = require('../../utils/linkUtils');
+const permissionModel = require('../../schemas/permissionSchema');
+const channelModel = require('../../schemas/channel/channelSchema');
+
+/**
+ * Class containing global server-side chat/command pre-processing logic
+ */
+module.exports = class commandPreprocessor{
+    /**
+     * Instantiates a commandPreprocessor object
+     * @param {channelManager} server - Parent Server Object
+     * @param {chatHandler} chatHandler - Parent Chat Handler Object
+     */
+    constructor(server, chatHandler){
+        this.server = server;
+        this.chatHandler = chatHandler;
+        this.commandProcessor = new commandProcessor(server, chatHandler);
+        this.tokebot = new tokebot(server, chatHandler);
+    }
+
+    /**
+     * Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly
+     * @param {Socket} socket - Socket we're receiving the request from
+     * @param {Object} data - Event payload
+     */
+    async preprocess(socket, data){
+        //Set command object
+        const commandObj = {
+            socket,
+            sendFlag: true,
+            rawData: data,
+            chatType: 'chat'
+        }
+
+        //If we don't pass sanatization/validation turn this car around
+        if(!this.sanatizeCommand(commandObj)){
+            return;
+        }
+
+        //split the command
+        this.splitCommand(commandObj);
+
+        //Process the command
+        await this.processServerCommand(commandObj);
+
+        //If we're going to relay this command as a message, continue on to chat processing
+        if(commandObj.sendFlag){
+            //Prep the message
+            await this.prepMessage(commandObj);
+
+            //Send the chat
+            this.sendChat(commandObj);
+        }
+    }
+
+    /**
+     * Sanatizes and Validates a single user chat message/command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} false if Command/Message is too long to send
+     */
+    sanatizeCommand(commandObj){
+        //Trim and Sanatize for XSS
+        commandObj.command = validator.trim(validator.escape(commandObj.rawData.msg));
+
+        //Return whether or not the shit was long enough
+        return (validator.isLength(commandObj.rawData.msg, {min: 1, max: 255}));
+    }
+
+    /**
+     * Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders
+     * These arrays are used to handle further command/chat processing
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     */
+    splitCommand(commandObj){
+        //Split string by words
+        commandObj.commandArray = commandObj.command.split(/\b/g);//Split by word-borders
+        commandObj.argumentArray = commandObj.command.match(/\b\w+\b/g);//Match by words surrounded by borders
+    }
+
+    /**
+     * Uses the server's Command Processor object to process the chat/command request.
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     */
+    async processServerCommand(commandObj){
+        //If the raw message starts with '!' (skip commands that start with whitespace so people can send example commands in chat)
+        if(commandObj.rawData.msg[0] == '!'){
+            //if it isn't just an exclimation point, and we have a real command
+            if(commandObj.argumentArray != null){
+                //If the command processor knows what to do with whatever the fuck the user sent us
+                if(this.commandProcessor[commandObj.argumentArray[0].toLowerCase()] != null){
+                    //Process the command and use the return value to set the sendflag (true if command valid)
+                    commandObj.sendFlag = await this.commandProcessor[commandObj.argumentArray[0].toLowerCase()](commandObj, this);
+                }else{
+                    //Process as toke command if we didnt get a match from the standard server-side command processor
+                    commandObj.sendFlag = await this.tokebot.tokeProcessor(commandObj);
+                }
+            }
+        }
+    }
+
+    /**
+     * Iterates through links in message and marks them by link type for later use by client-side post-processing
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     */
+    async markLinks(commandObj){
+        //Setup the links array
+        commandObj.links = [];
+
+        //For each link sent from the client
+        //this.rawData.links.forEach((link) => {
+        for (const link of commandObj.rawData.links){
+            //Add a marked link object to our links array
+            commandObj.links.push(await linkUtils.markLink(link));
+        }
+    }
+
+    /**
+     * Re-creates message string from processed Command Array
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     */
+    async prepMessage(commandObj){
+        //Create message from commandArray
+        commandObj.message = commandObj.commandArray.join('').trimStart();
+        //Validate links and mark them by embed type
+        await this.markLinks(commandObj);
+    }
+
+    /**
+     * Relays chat to channel via parent Chat Handler object
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     */
+    sendChat(commandObj){
+        //FUCKIN' SEND IT!
+        this.chatHandler.relayUserChat(commandObj.socket, commandObj.message, commandObj.chatType, commandObj.links);
+    }
+}
+
+/**
+ * Class representing global server-side chat/command processing logic
+ */
+class commandProcessor{
+    /**
+     * Instantiates a commandProcessor object
+     * @param {channelManager} server - Parent Server Object
+     * @param {chatHandler} chatHandler - Parent Chat Handler Object
+     */
+    constructor(server, chatHandler){
+        this.server = server;
+        this.chatHandler = chatHandler;
+    }
+
+    //Command keywords get run through .toLowerCase(), so we should use lowercase method names for command methods
+    /**
+     * Command Processor method to handle the '!whisper' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag
+     */
+    whisper(commandObj){
+        //splice out our command
+        commandObj.commandArray.splice(0,2);
+
+        //Mark out the current message as a whisper
+        commandObj.chatType = 'whisper';
+
+        //Make sure to throw the send flag
+        return true
+    }
+
+    /**
+     * Command Processor method to handle the '!spoiler' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag
+     */
+    spoiler(commandObj){
+        //splice out our command
+        commandObj.commandArray.splice(0,2);
+
+        //Mark out the current message as a spoiler
+        commandObj.chatType = 'spoiler';
+
+        //Make sure to throw the send flag
+        return true
+    }
+
+    /**
+     * Command Processor method to handle the '!strikethrough' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag
+     */
+    strikethrough(commandObj){
+        //splice out our command
+        commandObj.commandArray.splice(0,2);
+
+        //Mark out the current message as a spoiler
+        commandObj.chatType = 'strikethrough';
+
+        //Make sure to throw the send flag
+        return true
+    }
+
+    /**
+     * Command Processor method to handle the '!bold' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag
+     */
+    bold(commandObj){
+        //splice out our command
+        commandObj.commandArray.splice(0,2);
+
+        //Mark out the current message as a spoiler
+        commandObj.chatType = 'bold';
+
+        //Make sure to throw the send flag
+        return true
+    }
+
+    /**
+     * Command Processor method to handle the '!italics' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag
+     */
+    italics(commandObj){
+        //splice out our command
+        commandObj.commandArray.splice(0,2);
+
+        //Mark out the current message as a spoiler
+        commandObj.chatType = 'italics';
+
+        //Make sure to throw the send flag
+        return true
+    }
+
+    /**
+     * Command Processor method to handle the '!announce' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag on un-authorized call to shame the user
+     */
+    async announce(commandObj, preprocessor){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
+
+        //Check if the user has permission, and publicly shame them if they don't (lmao)
+        if(chanDB != null && await chanDB.permCheck(commandObj.socket.user, 'announce')){
+            //splice out our command
+            commandObj.commandArray.splice(0,2);
+
+            //Prep the message using pre-processor functions chat-handling
+            await preprocessor.prepMessage(commandObj);
+
+            //send it
+            this.chatHandler.relayChannelAnnouncement(commandObj.socket.chan, commandObj.message, commandObj.links);
+
+            //throw send flag
+            return false;
+        }
+
+        //throw send flag
+        return true;
+    }
+
+    /**
+     * Command Processor method to handle the '!serverannounce' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag on un-authorized call to shame the user
+     */
+    async serverannounce(commandObj, preprocessor){
+        //Check if the user has permission, and publicly shame them if they don't (lmao)
+        if(await permissionModel.permCheck(commandObj.socket.user, 'announce')){
+            //splice out our command
+            commandObj.commandArray.splice(0,2);
+
+            //Prep the message using pre-processor functions for chat-handling
+            await preprocessor.prepMessage(commandObj);
+
+            //send it
+            this.chatHandler.relayServerAnnouncement(commandObj.message, commandObj.links);
+
+            //disble send flag
+            return false;
+        }
+
+        //throw send flag
+        return true;
+    }
+
+    /**
+     * Command Processor method to handle the '!resettoke' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag on un-authorized call to shame the user
+     */
+    async resettoke(commandObj, preprocessor){
+        //Check if the user has permission, and publicly shame them if they don't (lmao)
+        if(await permissionModel.permCheck(commandObj.socket.user, 'resetToke')){
+            //Acknowledge command
+            this.chatHandler.relayTokeWhisper(commandObj.socket, 'Toke cooldown reset.');
+
+            //Tell tokebot to reset the toke
+            preprocessor.tokebot.resetToke();
+
+            //disable send flag
+            return false;
+        }
+
+        //throw send flag
+        return true;
+    }
+
+    /**
+     * Command Processor method to handle the '!clear' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag on un-authorized call to shame the user
+     */
+    async clear(commandObj){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
+
+        //Check if the user has permission, and publicly shame them if they don't (lmao)
+        if(await chanDB.permCheck(commandObj.socket.user, 'clearChat')){
+            //Send off the command
+            this.chatHandler.clearChat(commandObj.socket.chan, commandObj.argumentArray[1]);
+            //disable send flag
+            return false;
+        }
+
+        //throw send flag
+        return true;
+    }
+
+    /**
+     * Command Processor method to handle the '!kick' command
+     * @param {Object} commandObj - Object representing a single given command/chat request
+     * @returns {Boolean} True to enable send flag on un-authorized call to shame the user
+     */
+    async kick(commandObj){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: commandObj.socket.chan});
+
+        //Check if the user has permission, and publicly shame them if they don't (lmao)
+        if(await chanDB.permCheck(commandObj.socket.user, 'kickUser')){
+            //Get username from argument array
+            const username = commandObj.argumentArray[1];
+
+            //Get channel
+            const channel = this.server.activeChannels.get(commandObj.socket.chan);
+
+            //get initiator and target user objects
+            const initiator = channel.userList.get(commandObj.socket.user.user);
+            const target = channel.userList.get(username);
+
+            //get initiator and target override abilities
+            const override = await permissionModel.overrideCheck(commandObj.socket.user, 'kickUser');
+            const targetOverride = await permissionModel.overrideCheck(target, 'kickUser');
+
+            //If there is no user
+            if(target == null){
+                //silently drop the command
+                return false;
+            }
+
+
+            //If the user is capable of overriding this permission based on site permissions
+            if(override || targetOverride){
+                //If the site rank is equal
+                if(permissionModel.rankToNum(initiator.rank) == permissionModel.rankToNum(target.rank)){
+                    //compare chan rank
+                    if(permissionModel.rankToNum(initiator.chanRank) <= permissionModel.rankToNum(target.chanRank)){
+                        //shame the person running it
+                        return true;
+                    }
+                //otherwise
+                }else{
+                    //compare site rank
+                    if(permissionModel.rankToNum(initiator.rank) <= permissionModel.rankToNum(target.rank)){
+                        //shame the person running it
+                        return true;
+                    }
+                }
+            }else{
+                //If the target has a higher chan rank than the initiator
+                if(permissionModel.rankToNum(initiator.chanRank) <= permissionModel.rankToNum(target.chanRank)){
+                    //shame the person running it
+                    return true;
+                }
+            }
+
+
+            //Splice out kick
+            commandObj.commandArray.splice(0,4)
+
+            //Get collect reason
+            var reason = commandObj.commandArray.join('');
+
+            //If no reason was given
+            if(reason == ''){
+                //Fill in a generic reason
+                reason = "You have been kicked from the channel!";
+            }
+
+            //Kick the user
+            target.disconnect(reason);
+
+            //throw send flag
+            return false;
+        }
+
+        //throw send flag
+        return true;
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_connectedUser.js.html b/www/doc/app_channel_connectedUser.js.html new file mode 100644 index 0000000..f670d7b --- /dev/null +++ b/www/doc/app_channel_connectedUser.js.html @@ -0,0 +1,341 @@ + + + + + JSDoc: Source: app/channel/connectedUser.js + + + + + + + + + + +
+ +

Source: app/channel/connectedUser.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//local imports
+const config = require('../../../config.json');
+const channelModel = require('../../schemas/channel/channelSchema');
+const permissionModel = require('../../schemas/permissionSchema');
+const flairModel = require('../../schemas/flairSchema');
+const emoteModel = require('../../schemas/emoteSchema');
+const { userModel } = require('../../schemas/user/userSchema');
+
+/**
+ * Class representing a single user connected to a channel
+ */
+module.exports = class{
+    /**
+     * Instantiates a connectedUser object
+     * @param {Mongoose.Document} userDB - User document to re-hydrate user from
+     * @param {PemissionModel.chanRank} chanRank - Enum representing user channel rank
+     * @param {String} - Channel the user is connecting to
+     * @param {Socket} socket - Socket associated with the users connection
+     */
+    constructor(userDB, chanRank, channel, socket){
+        this.id = userDB.id;
+        this.user = userDB.user;
+        this.rank = userDB.rank;
+        this.highLevel = userDB.highLevel;
+
+        //Check to make sure users flair entry from DB is good 
+        if(userDB.flair != null){
+            //Use flair from DB
+            this.flair = userDB.flair.name;
+        //Otherwise
+        }else{
+            //Gracefully default to classic
+            this.flair = 'classic';
+        }
+
+        this.chanRank = chanRank;
+        this.channel = channel;
+        this.sockets = [socket.id];
+    }
+
+    /**
+     * Handles server-side initialization for new connections from a specific user
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     * @param {Socket} socket - Requesting Socket
+     */
+    async handleConnection(userDB, chanDB, socket){
+        //send metadata to client
+        this.sendClientMetadata();
+
+        //Send out emotes
+        this.sendSiteEmotes();
+        this.sendChanEmotes(chanDB);
+        this.sendPersonalEmotes(userDB);
+
+        //Send out used tokes
+        this.sendUsedTokes(userDB);
+
+        //Send out the currently playing item
+        this.channel.queue.sendMedia(socket);
+        
+        //If we're proxied
+        if(config.proxied){
+            //Tattoo hashed IP address from reverse proxy to user account for seven days
+            await userDB.tattooIPRecord(socket.handshake.headers['x-forwarded-for']);
+        }else{
+            //Tattoo hashed IP address to user account for seven days
+            await userDB.tattooIPRecord(socket.handshake.address);
+        }
+    }
+
+    /**
+     * Iterates through all known connections for a given user, running them through a supplied callback function
+     * @param {Function} cb - Callback to call against found sockets for a given user
+     */
+    socketCrawl(cb){
+        //Crawl through user's sockets (lol)
+        this.sockets.forEach((sockid) => {
+            //get socket based on ID
+            const socket = this.channel.server.io.sockets.sockets.get(sockid);
+            //Callback with socket
+            cb(socket);
+        });
+    }
+
+
+    /**
+     * Emits an event to all known sockets for a given user
+     * 
+     * My brain keeps going back to using dynamic per-user namespaces for this
+     * but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces
+     * and using per-user channels for this, but what of gold or mod-only features? or games?
+     * No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms).
+     * at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it.
+     * Having to crawl through these sockets is that. Because the other ways seem more gross somehow.
+     * @param {String} eventName - Event name to emit to client sockets
+     * @param {Object} data - Data to emit to client sockets
+     */
+    emit(eventName, data){
+        this.socketCrawl((socket)=>{
+            //Ensure our socket is initialized
+            if(socket != null){
+                socket.emit(eventName, data);
+            }
+        });
+    }
+
+    /**
+     * Disconnects all sockets for a given user
+     * @param {String} reason - Reason for being disconnected
+     * @param {String} type - Disconnection Type
+     */
+    disconnect(reason, type = "Disconnected"){
+        this.emit("kick",{type, reason});
+        this.socketCrawl((socket)=>{socket.disconnect()});
+    }
+
+    //This is the big first push upon connection
+    //It should only fire once, so things that only need to be sent once can be slapped into here
+    /**
+     * Sends glut of required initial metadata to the client upon a new connection
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access 
+     */
+    async sendClientMetadata(userDB, chanDB){
+        //Get flairList from DB and setup flairList array
+        const flairListDB = await flairModel.find({});
+        var flairList = [];
+
+        //if we wherent handed a user document
+        if(userDB == null){
+            //Pull it based on user name
+            userDB = await userModel.findOne({user: this.user});
+        }
+
+        //if we wherent handed a channel document
+        if(chanDB == null){
+            //Pull it based on channel name
+            chanDB = await channelModel.findOne({name: this.channel.name});
+        }
+
+        //If our perm map is un-initiated 
+        //can't set this in constructor easily since it's asyncornous
+        //need to wait for it to complete before sending this off, but shouldnt re-do the wait for later connections
+        if(this.permMap == null){
+            //Grab perm map
+            this.permMap = await chanDB.getPermMapByUserDoc(userDB);
+        }
+
+        //Setup our userObj
+        const userObj = {
+            id: this.id,
+            user: this.user,
+            rank: this.rank,
+            chanRank: this.chanRank,
+            highLevel: this.highLevel,
+            permMap: {
+                site: Array.from(this.permMap.site),
+                chan: Array.from(this.permMap.chan),
+            },
+            flair: this.flair,
+        }
+
+        //For each flair listed in the Database
+        flairListDB.forEach((flair)=>{
+            //Check if the user has permission to use the current flair
+            if(permissionModel.rankToNum(flair.rank) <= permissionModel.rankToNum(this.rank)){
+                //If so push a light version of the flair object into our final flair list
+                flairList.push({
+                    name: flair.name,
+                    displayName: flair.displayName
+                });
+            }
+        });
+
+        //Get schedule as a temporary array
+        const queue = await this.channel.queue.prepQueue(chanDB);
+
+        //Get schedule lock status
+        const queueLock = this.channel.queue.locked;
+
+        //Get chat buffer
+        const chatBuffer = this.channel.chatBuffer.buffer;
+
+        //Send off the metadata to our user's clients
+        this.emit("clientMetadata", {user: userObj, flairList, queue, queueLock, chatBuffer});
+    }
+
+    /**
+     * Send copy of site emotes to the user
+     */
+    async sendSiteEmotes(){
+        //Get emote list from DB
+        const emoteList = await emoteModel.getEmotes();
+
+        //Send it off to the user
+        this.emit('siteEmotes', emoteList);
+    }
+
+    /**
+     * Send copy of channel emotes to the user
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access 
+     */
+    async sendChanEmotes(chanDB){
+        //if we wherent handed a channel document
+        if(chanDB == null){
+            //Pull it based on channel name
+            chanDB = await channelModel.findOne({name: this.channel.name});
+        }
+
+        //Pull emotes from channel
+        const emoteList = chanDB.getEmotes();
+
+        //Send it off to the user
+        this.emit('chanEmotes', emoteList);
+    }
+
+    /**
+     * Send copy of channel emotes to the user
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async sendPersonalEmotes(userDB){
+        //if we wherent handed a user document
+        if(userDB == null){
+            //Pull it based on user name
+            userDB = await userModel.findOne({user: this.user});
+        }
+
+        //Pull emotes from channel
+        const emoteList = userDB.getEmotes();
+
+        //Send it off to the user
+        this.emit('personalEmotes', emoteList);
+    }
+
+    /**
+     * Send copy of channel emotes to the user
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async sendUsedTokes(userDB){
+        //if we wherent handed a user document
+        if(userDB == null){
+            //Pull it based on user name
+            userDB = await userModel.findOne({user: this.user});
+        }
+
+        //Create array of used toks from toke map and send it out to the user
+        this.emit('usedTokes',{
+            tokes: Array.from(userDB.tokes.keys())
+        });
+    }
+
+    /**
+     * Set flair for a given user and broadcast update to clients
+     * @param {String} flair - Flair string to update user's flair to
+     */
+    updateFlair(flair){
+        this.flair = flair;
+
+        this.channel.broadcastUserList();
+        this.sendClientMetadata();
+    }
+
+    /**
+     * Set high level for a given user and broadcast update to clients
+     * @param {Number} highLevel - Number to update user's high-level to
+     */
+    updateHighLevel(highLevel){
+        this.highLevel = highLevel;
+
+        //TODO: show high-level in userlist
+        this.channel.broadcastUserList();
+        this.sendClientMetadata();
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_media_media.js.html b/www/doc/app_channel_media_media.js.html new file mode 100644 index 0000000..37a1490 --- /dev/null +++ b/www/doc/app_channel_media_media.js.html @@ -0,0 +1,90 @@ + + + + + JSDoc: Source: app/channel/media/media.js + + + + + + + + + + +
+ +

Source: app/channel/media/media.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+/**
+ * Object representing a piece of media
+ */
+module.exports = class{
+    /**
+     * Creates a new media object from scraped information
+     * @param {String} title - Chosen title of media
+     * @param {String} fileName - Original filename/title of media provided by source
+     * @param {String} url - Original URL to file
+     * @param {String} id - Video ID from source (IE: youtube watch code/archive.org file path)
+     * @param {String} type - Original video source
+     * @param {Number} duration - Length of media in seconds
+     * @param {String} rawLink - URL to raw file copy of media, not applicable to all sources
+     */
+    constructor(title, fileName, url, id, type, duration, rawLink = url){
+        this.title = title;
+        this.fileName = fileName
+        this.url = url;
+        this.id = id;
+        this.type = type;
+        this.duration = duration;
+        this.rawLink = rawLink;
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_media_playlistHandler.js.html b/www/doc/app_channel_media_playlistHandler.js.html new file mode 100644 index 0000000..5773a86 --- /dev/null +++ b/www/doc/app_channel_media_playlistHandler.js.html @@ -0,0 +1,1187 @@ + + + + + JSDoc: Source: app/channel/media/playlistHandler.js + + + + + + + + + + +
+ +

Source: app/channel/media/playlistHandler.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM imports
+const validator = require('validator');
+
+//Local imports
+const queuedMedia = require('./queuedMedia');
+const loggerUtils = require('../../../utils/loggerUtils');
+const yanker = require('../../../utils/media/yanker');
+const channelModel = require('../../../schemas/channel/channelSchema');
+const { userModel } = require('../../../schemas/user/userSchema');
+
+/**
+ * Class containing playlist management logic for a single channel
+ */
+module.exports = class{
+    /**
+     * Instantiates a new object to handle playlist management for a single channel
+     * @param {channelManager} server - Parent server object
+     * @param {activeChannel} channel - Parent Channel object for desired channel queue
+     */
+    constructor(server, channel){
+        //Set server
+        this.server = server
+        //Set channel
+        this.channel = channel;
+    }
+
+    /**
+     * Defines server-side socket.io listeners for newly connected sockets
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     */
+    defineListeners(socket){
+        //Channel Playlist Listeners
+        socket.on("getChannelPlaylists", () => {this.getChannelPlaylists(socket)});
+        socket.on("createChannelPlaylist", (data) => {this.createChannelPlaylist(socket, data)});
+        socket.on("deleteChannelPlaylist", (data) => {this.deleteChannelPlaylist(socket, data)});
+        socket.on("addToChannelPlaylist", (data) => {this.addToChannelPlaylist(socket, data)});
+        socket.on("queueChannelPlaylist", (data) => {this.queueChannelPlaylist(socket, data)});
+        socket.on("queueFromChannelPlaylist", (data) => {this.queueFromChannelPlaylist(socket, data)});
+        socket.on("queueRandomFromChannelPlaylist", (data) => {this.queueRandomFromChannelPlaylist(socket, data)});
+        socket.on("renameChannelPlaylist", (data) => {this.renameChannelPlaylist(socket, data)});
+        socket.on("changeDefaultTitlesChannelPlaylist", (data) => {this.changeDefaultTitlesChannelPlaylist(socket, data)});
+        socket.on("deleteChannelPlaylistMedia", (data) => {this.deleteChannelPlaylistMedia(socket, data)});
+
+        //User Playlist Listeners
+        socket.on("getUserPlaylists", () => {this.getUserPlaylists(socket)});
+        socket.on("createUserPlaylist", (data) => {this.createUserPlaylist(socket, data)});
+        socket.on("deleteUserPlaylist", (data) => {this.deleteUserPlaylist(socket, data)});
+        socket.on("addToUserPlaylist", (data) => {this.addToUserPlaylist(socket, data)});
+        socket.on("queueUserPlaylist", (data) => {this.queueUserPlaylist(socket, data)});
+        socket.on("queueFromUserPlaylist", (data) => {this.queueFromUserPlaylist(socket, data)});
+        socket.on("queueRandomFromUserPlaylist", (data) => {this.queueRandomFromUserPlaylist(socket, data)});
+        socket.on("renameUserPlaylist", (data) => {this.renameUserPlaylist(socket, data)});
+        socket.on("changeDefaultTitlesUserPlaylist", (data) => {this.changeDefaultTitlesUserPlaylist(socket, data)});
+        socket.on("deleteUserPlaylistMedia", (data) => {this.deleteUserPlaylistMedia(socket, data)});
+    }
+
+    //Validation/Sanatization functions
+    /**
+     * Validates client requests to create a playlist
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     * @param {Object} data - Data handed over from the client
+     * @returns {Object} returns validated titles
+     */
+    createPlaylistValidator(socket, data){
+        //Create empty array to hold titles
+        const safeTitles = [];       
+
+        //If the title is too long
+        if(typeof data.playlist != 'string' || !validator.isLength(data.playlist, {min: 1, max:30})){
+            //Bitch, moan, complain...
+            loggerUtils.socketErrorHandler(socket, "Invalid Playlist Name!", "validation");
+            //and ignore it!
+            return;
+        }
+
+        if(data.defaultTitles != null){
+            //For each default title passed by the data
+            for(let title of data.defaultTitles){
+                //If the title isn't too long
+                if(typeof title != 'string' || validator.isLength(title, {min:1, max:30})){
+                    //Add it to the safe title list
+                    safeTitles.push(validator.escape(validator.trim(title)))
+                }
+            }
+        }
+
+        //Escape/trim the playlist name
+        return {
+            playlist: validator.escape(validator.trim(data.playlist)),
+            defaultTitles: safeTitles
+        }
+    }
+
+    /**
+     * Validates client requests to add media to a playlist
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     * @param {String} URL - URL String handed over from the client
+     * @returns {Array} List of media objects which where added
+     */
+    async addToPlaylistValidator(socket, url){
+        //If we where given a bad URL
+        if(typeof url != 'string' || !validator.isURL(url)){
+            //Attempt to fix the situation by encoding it
+            url = encodeURI(url);
+
+            //If it's still bad
+            if(typeof url != 'string' || !validator.isURL(url)){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, "Bad URL!", "validation");
+                //and ignore it!
+                return;
+            }
+        }
+
+        //Pull media metadata
+        const mediaList = await yanker.yankMedia(url);
+
+        //If we didn't get any media
+        if(mediaList.length == 0 || mediaList == null){
+            //Bitch, moan, complain...
+            loggerUtils.socketErrorHandler(socket, "No media found!", "queue");
+            //and ignore it!
+            return;               
+        }
+
+        return mediaList;
+    }
+
+    /**
+     * Validates client requests to queue media from a playlist
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     * @param {Object} data - Data handed over from the client
+     * @returns {Number} returns validated start time on success
+     */
+    queueFromChannelPlaylistValidator(socket, data){
+        //Validate UUID
+        if(typeof data.uuid != 'string' || !validator.isUUID(data.uuid)){
+            //Bitch, moan, complain...
+            loggerUtils.socketErrorHandler(socket, `'${data.uuid}' is not a valid UUID!`, "validation");
+            //and ignore it!
+            return;
+        }
+
+        //The UUID is only validated, not processed so we just return the new time :P
+        return this.channel.queue.getStart(data.start)
+    }
+
+    /**
+     * Validates client requests to rename the playlist validator
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     * @param {Object} data - Data handed over from the client
+     * @returns {String} returns escaped/trimmed name upon success
+     */
+    renameChannelPlaylistValidator(socket, data){
+        //If the title is too long
+        if(typeof data.name != 'string' || !validator.isLength(data.name, {min: 1, max:30})){
+            //Bitch, moan, complain...
+            loggerUtils.socketErrorHandler(socket, "Invalid playlist name!", "validation");
+            //and ignore it!
+            return;
+        }
+
+        //Escape/trim the playlist name
+        return validator.escape(validator.trim(data.name));
+    }
+
+    /**
+     * Validates client requests to change default titles for a given playlist
+     * @param {Object} data - Data handed over from the client
+     * @returns {Array} Array of strings containing valid titles from the output
+     */
+    changeDefaultTitlesValidator(data){
+        //Create empty array to hold titles
+        const safeTitles = [];
+
+        //For each default title passed by the data
+        for(let title of data.defaultTitles){
+            //If the title isn't too long or too short
+            if(typeof title != 'string' || validator.isLength(title, {min: 1, max:30})){
+                //Add it to the safe title list
+                safeTitles.push(validator.escape(validator.trim(title)))
+            }
+        }
+
+        //return safe titles
+        return safeTitles;
+    }
+
+    /**
+     * Validates client requests to rename the playlist validator
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     * @param {Object} data - Data handed over from the client
+     */
+    deletePlaylistMediaValidator(socket, data){
+        //If we don't have a valid UUID
+        if(typeof data.uuid != 'string' || !validator.isUUID(data.uuid)){
+            //Bitch, moan, complain...
+            loggerUtils.socketErrorHandler(socket, `'${data.uuid}' is not a valid UUID!`, "validation");
+            //and ignore it!
+            return;
+        }
+
+        return data.uuid;
+    }
+
+    //Get playlist functions
+    /**
+     * Sends channel playlist data to a requesting socket
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     */
+    async getChannelPlaylists(socket, chanDB){
+        try{
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //Return playlists
+            socket.emit('chanPlaylists', chanDB.getPlaylists());
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Sends user playlist data to a requesting socket
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     * @param {Mongoose.Document} userDB - Channnel Document Passthrough to save on DB Access
+     */
+    async getUserPlaylists(socket, userDB){
+        try{
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //Return playlists
+            socket.emit('userPlaylists', userDB.getPlaylists());
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //Create playlist functions
+    /**
+     * Creates a new channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     */
+    async createChannelPlaylist(socket, data, chanDB){
+        try{
+            //Validate Data
+            const validData = this.createPlaylistValidator(socket, data);
+
+            //If we got bad data
+            if(validData == null){
+                //Do nothing
+                return;
+            }
+
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
+                //If the channel already exists
+                if(chanDB.getPlaylistByName(validData.playlist) != null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, `Playlist named '${validData.playlist}' already exists!`, "validation");
+                    //and ignore it!
+                    return;
+                } 
+
+                //Add playlist to the channel doc
+                chanDB.media.playlists.push({
+                    name: validData.playlist,
+                    defaultTitles: validData.defaultTitles
+                });
+
+                //Save the channel doc
+                await chanDB.save();
+
+                //Return playlists from channel doc
+                this.getChannelPlaylists(socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Creates a new user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async createUserPlaylist(socket, data, userDB){
+        try{
+            //Validate Data
+            const validData = this.createPlaylistValidator(socket, data);
+
+            //If we got bad data
+            if(validData == null){
+                //Do nothing
+                return;
+            }
+
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //If the channel already exists
+            if(userDB.getPlaylistByName(validData.playlist) != null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, `Playlist named '${validData.playlist}' already exists!`, "validation");
+                //and ignore it!
+                return;
+            } 
+
+            //Add playlist to the channel doc
+            userDB.playlists.push({
+                name: validData.playlist,
+                defaultTitles: validData.defaultTitles
+            });
+
+            //Save the channel doc
+            await userDB.save();
+
+            //Return playlists from channel doc
+            this.getUserPlaylists(socket, userDB);
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //Delete playlist functions
+    /**
+     * Deletes a user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async deleteChannelPlaylist(socket, data, chanDB){
+        try{
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //If the channel doesn't exist
+            if(chanDB.getPlaylistByName(data.playlist) == null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, `Playlist named '${data.playlist}' doesn't exist!`, "validation");
+                //and ignore it!
+                return;
+            } 
+
+            if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
+                //Delete playlist name
+                await chanDB.deletePlaylistByName(data.playlist);
+
+                //Return playlists from channel doc
+                this.getChannelPlaylists(socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Deletes a Channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     */
+    async deleteUserPlaylist(socket, data, userDB){
+        try{
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //If the channel doesn't exist
+            if(userDB.getPlaylistByName(data.playlist) == null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, `Playlist named '${data.playlist}' doesn't exist!`, "validation");
+                //and ignore it!
+                return;
+            } 
+
+            //Delete playlist name
+            await userDB.deletePlaylistByName(data.playlist);
+
+            //Return playlists from channel doc
+            this.getUserPlaylists(socket, userDB);
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //Add Media Functions
+    /**
+     * Adds media to channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     */
+    async addToChannelPlaylist(socket, data, chanDB){
+        try{
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
+                //Normally I put validators before the DB call
+                //But this reqs a server-side fetch, so I'll do the perm check first :P
+                //Validate URL and pull media
+                const mediaList = await this.addToPlaylistValidator(socket, data.url);
+
+                //If we encountered an error during validation
+                if(mediaList == null){
+                    //Fuck off and die
+                    return;
+                }
+
+                //Find the playlist
+                const playlist = chanDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //delete media from playlist
+                chanDB.media.playlists[playlist.listIndex].addMedia(mediaList);
+
+                //save the channel document
+                await chanDB.save();
+
+                //Return playlists from channel doc
+                this.getChannelPlaylists(socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Adds media to user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async addToUserPlaylist(socket, data, userDB){
+        try{
+            //Validate URL and pull media
+            const mediaList = await this.addToPlaylistValidator(socket, data.url);
+
+            //If we encountered an error during validation
+            if(mediaList == null){
+                //Fuck off and die
+                return;
+            }
+
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //Find the playlist
+            const playlist = userDB.getPlaylistByName(data.playlist);
+
+            //If we didn't find a real playlist
+            if(playlist == null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                //and ignore it!
+                return;
+            }
+
+            //delete media from playlist
+            userDB.playlists[playlist.listIndex].addMedia(mediaList);
+
+            //save the channel document
+            await userDB.save();
+
+            //Return playlists from channel doc
+            this.getUserPlaylists(socket, userDB);
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //Queuing Functions
+    /**
+     * Queues an entire channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async queueChannelPlaylist(socket, data, chanDB){
+        try{
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //Permcheck to make sure the user can fuck w/ the queue
+            if((!this.channel.queue.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){       
+                //Pull a valid start time from input, or make one up if we can't
+                let start = this.channel.queue.getStart(data.start);
+
+                //Grab playlist from the DB
+                let playlist = chanDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Create an empty array to hold our media list
+                const mediaList = [];
+
+                //Iterate through playlist media
+                for(let item of playlist.media){
+                    //Rehydrate a full phat media object from the flat DB entry
+                    let mediaObj = item.rehydrate();
+
+                    //Set media title from default titles
+                    mediaObj.title = playlist.pickDefaultTitle(mediaObj.title);
+
+                    //Push rehydrated item on to the mediaList
+                    mediaList.push(mediaObj);
+                }
+
+                //Convert array of standard media objects to queued media objects, and push to schedule
+                this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray(mediaList, start), socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Queues an entire user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async queueUserPlaylist(socket, data, userDB, chanDB){
+        try{
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //Permcheck to make sure the user can fuck w/ the queue
+            if((!this.channel.queue.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){       
+                //Pull a valid start time from input, or make one up if we can't
+                let start = this.channel.queue.getStart(data.start);
+
+                //Grab playlist from the DB
+                let playlist = userDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Create an empty array to hold our media list
+                const mediaList = [];
+
+                //Iterate through playlist media
+                for(let item of playlist.media){
+                    //Rehydrate a full phat media object from the flat DB entry
+                    let mediaObj = item.rehydrate();
+
+                    //Set media title from default titles
+                    mediaObj.title = playlist.pickDefaultTitle(mediaObj.title);
+
+                    //Push rehydrated item on to the mediaList
+                    mediaList.push(mediaObj);
+                }
+
+                //Convert array of standard media objects to queued media objects, and push to schedule
+                this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray(mediaList, start), socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Queues media from a given channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async queueFromChannelPlaylist(socket, data, chanDB){
+        try{
+            //Validate data
+            const start = this.queueFromChannelPlaylistValidator(socket, data);
+
+            //If we had a validation issue
+            if(start == null){
+                //Fuck off and die
+                return;
+            }
+
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //Permcheck the user
+            if((!this.channel.queue.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){       
+                //Grab playlist
+                const playlist = chanDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                } 
+
+                //Pull and rehydrate media from playlist
+                const media = playlist.findMediaByUUID(data.uuid).rehydrate();
+
+                //Set title from default titles
+                media.title = playlist.pickDefaultTitle(media.title);
+
+                //Queue found media
+                this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray([media], start), socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Queues media from a given user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async queueFromUserPlaylist(socket, data, userDB, chanDB){
+        try{
+            //Validate data
+            const start = this.queueFromChannelPlaylistValidator(socket, data);
+
+            //If we had a validation issue
+            if(start == null){
+                //Fuck off and die
+                return;
+            }
+
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //Permcheck the user
+            if((!this.channel.queue.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){       
+                //Grab playlist
+                const playlist = userDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                } 
+
+                //Pull and rehydrate media from playlist
+                const media = playlist.findMediaByUUID(data.uuid).rehydrate();
+
+                //Set title from default titles
+                media.title = playlist.pickDefaultTitle(media.title);
+
+                //Queue found media
+                this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray([media], start), socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Queues random media from a given channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async queueRandomFromChannelPlaylist(socket, data, chanDB){
+        try{
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //Permcheck the user
+            if((!this.channel.queue.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){       
+                //Pull a valid start time from input, or make one up if we can't
+                let start = this.channel.queue.getStart(data.start);               
+
+                //Grab playlist
+                const playlist = chanDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Pick a random video ID based on the playlist's length
+                const foundID = Math.round(Math.random() * (playlist.media.length - 1));
+
+                //Pull and rehydrate media from playlist
+                const foundMedia = playlist.media[foundID].rehydrate();
+
+                //Set title from default titles
+                foundMedia.title = playlist.pickDefaultTitle(foundMedia.title);
+
+                //Queue found media
+                this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray([foundMedia], start), socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Queues random media from a given user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async queueRandomFromUserPlaylist(socket, data, userDB, chanDB){
+        try{
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //Permcheck the user
+            if((!this.channel.queue.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){       
+                //Pull a valid start time from input, or make one up if we can't
+                let start = this.channel.queue.getStart(data.start);               
+
+                //Grab playlist
+                const playlist = userDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Pick a random video ID based on the playlist's length
+                const foundID = Math.round(Math.random() * (playlist.media.length - 1));
+
+                //Pull and rehydrate media from playlist
+                const foundMedia = playlist.media[foundID].rehydrate();
+
+                //Set title from default titles
+                foundMedia.title = playlist.pickDefaultTitle(foundMedia.title);
+
+                //Queue found media
+                this.channel.queue.scheduleMedia(queuedMedia.fromMediaArray([foundMedia], start), socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //Rename playlist functions
+    /**
+     * Renames a channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async renameChannelPlaylist(socket, data, chanDB){
+        try{
+            //Validate and Sanatize name
+            const name = this.renameChannelPlaylistValidator(socket, data);
+
+            //If validation fucked up
+            if(name == null){
+                //STOP
+                return;
+            }           
+
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
+                //If the new name already exists
+                if(chanDB.getPlaylistByName(name) != null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, `Playlist named '${name}' already exists!`, "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Find playlist
+                let playlist = chanDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Change playlist name
+                chanDB.media.playlists[playlist.listIndex].name = name;
+
+                //Save channel document
+                await chanDB.save();
+
+                //Return playlists from channel doc
+                this.getChannelPlaylists(socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Renames a user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async renameUserPlaylist(socket, data, userDB){
+        try{
+            //Validate and Sanatize name
+            const name = this.renameChannelPlaylistValidator(socket, data);
+
+            //If validation fucked up
+            if(name == null){
+                //STOP
+                return;
+            }           
+
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //If the new name already exists
+            if(userDB.getPlaylistByName(name) != null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, `Playlist named '${name}' already exists!`, "validation");
+                //and ignore it!
+                return;
+            }
+
+            //Find playlist
+            let playlist = userDB.getPlaylistByName(data.playlist);
+
+            //If we didn't find a real playlist
+            if(playlist == null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                //and ignore it!
+                return;
+            }
+
+            //Change playlist name
+            userDB.playlists[playlist.listIndex].name = name;
+
+            //Save channel document
+            await userDB.save();
+
+            //Return playlists from channel doc
+            this.getUserPlaylists(socket, userDB);
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //Change default title list functions
+    /**
+     * Changes default titles for a given channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async changeDefaultTitlesChannelPlaylist(socket, data, chanDB){
+        try{
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
+                //Find playlist
+                let playlist = chanDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Keep valid default titles
+                chanDB.media.playlists[playlist.listIndex].defaultTitles = this.changeDefaultTitlesValidator(data);
+
+                //Save channel document
+                await chanDB.save();
+
+                //Return playlists from channel doc
+                this.getChannelPlaylists(socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Changes default titles for a given user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async changeDefaultTitlesUserPlaylist(socket, data, userDB){
+        try{
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //Find playlist
+            let playlist = userDB.getPlaylistByName(data.playlist);
+
+            //If we didn't find a real playlist
+            if(playlist == null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                //and ignore it!
+                return;
+            }
+
+            
+            //Keep valid de.mediafault titles
+            userDB.playlists[playlist.listIndex].defaultTitles = this.changeDefaultTitlesValidator(data);
+
+            //Save user document
+            await userDB.save();
+
+            //Return playlists from user doc
+            this.getUserPlaylists(socket, userDB);
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //Delete playlist media functions
+    /**
+     * Deletes media from a given channel playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} chanDB - Channel Document Passthrough to save on DB Access
+     */
+    async deleteChannelPlaylistMedia(socket, data, chanDB){
+        try{
+            //Validate UUID
+            const uuid = this.deletePlaylistMediaValidator(socket, data);
+
+            //If we failed validation
+            if(uuid == null){
+                //fuck off
+                return;
+            }
+
+            //if we wherent handed a channel document
+            if(chanDB == null){
+                //Pull it based on channel name
+                chanDB = await channelModel.findOne({name: this.channel.name});
+            }
+
+            if(await chanDB.permCheck(socket.user, 'editChannelPlaylists')){
+                //Find the playlist
+                let playlist = chanDB.getPlaylistByName(data.playlist);
+
+                //If we didn't find a real playlist
+                if(playlist == null){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //delete media from playlist
+                chanDB.media.playlists[playlist.listIndex].deleteMedia(data.uuid);
+
+                //save the channel document
+                await chanDB.save();
+
+                //Return playlists from channel doc
+                this.getChannelPlaylists(socket, chanDB);
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Deletes media from a given user playlist
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Data handed over from the client
+     * @param {Mongoose.Document} userDB - User Document Passthrough to save on DB Access
+     */
+    async deleteUserPlaylistMedia(socket, data, userDB){
+        try{
+            //Validate UUID
+            const uuid = this.deletePlaylistMediaValidator(socket, data);
+
+            //If we failed validation
+            if(uuid == null){
+                //fuck off
+                return;
+            }
+
+            //if we wherent handed a user document
+            if(userDB == null){
+                //Find the user in the Database
+                userDB = await userModel.findOne({user: socket.request.session.user.user});
+            }
+
+            //Find the playlist
+            let playlist = userDB.getPlaylistByName(data.playlist);
+
+            //If we didn't find a real playlist
+            if(playlist == null){
+                //Bitch, moan, complain...
+                loggerUtils.socketErrorHandler(socket, "Playlist not found!", "validation");
+                //and ignore it!
+                return;
+            }
+
+            //delete media from playlist
+            userDB.playlists[playlist.listIndex].deleteMedia(data.uuid);
+
+            //save the user document
+            await userDB.save();
+
+            //Return playlists from user doc
+            this.getUserPlaylists(socket, userDB);
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_media_queue.js.html b/www/doc/app_channel_media_queue.js.html new file mode 100644 index 0000000..6c98c13 --- /dev/null +++ b/www/doc/app_channel_media_queue.js.html @@ -0,0 +1,1802 @@ + + + + + JSDoc: Source: app/channel/media/queue.js + + + + + + + + + + +
+ +

Source: app/channel/media/queue.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM imports
+const validator = require('validator');
+
+//Local imports
+const queuedMedia = require('./queuedMedia');
+const yanker = require('../../../utils/media/yanker');
+const loggerUtils = require('../../../utils/loggerUtils');
+const channelModel = require('../../../schemas/channel/channelSchema');
+
+/**
+ * Object represneting a single channel's media queue
+ */
+module.exports = class{
+    /**
+     * Instantiates a new media queue for a given channel
+     * @param {channelManager} server - Parent server object
+     * @param {Document} chanDB - Related Channel Document from DB
+     * @param {activeChannel} channel - Parent Channel object for desired channel queue
+     */
+    constructor(server, chanDB, channel){
+        //Set server
+        this.server = server
+        //Set channel
+        this.channel = channel;
+
+        //Create map to hold currently queued media
+        this.schedule = new Map();
+
+        //Create variable to hold sync delta in ms
+        this.syncDelta = 1000;
+        //Create variable to hold current timestamp within the video
+        this.timestamp = 0;
+        //Delay between pre-switch function call and start of media
+        //This should be enough time to do things like pre-fetch updated raw links from youtube
+        this.preSwitchDelta = 10 * 1000;
+
+        //Create variable to hold sync timer
+        this.syncTimer = null;
+        //Create variable to hold next playing item timer
+        this.nextTimer = null;
+        //Create vairable to hold pre-switch timer
+        this.preSwitchTimer = null;
+        //Create variable to hold currently playing media object
+        this.nowPlaying = null;
+        //Create variable to hold item that was playing during the last liveStream (can't check against full duration since it might've been stopped for other reasons)
+        this.liveRemainder = null;
+        //Create variable to hold current live mode
+        this.liveMode = null;
+
+        //Create variable to lock standard queuing functions during livestreams
+        this.streamLock = false;
+        //create boolean to hold schedule lock
+        this.locked = false;
+
+        //Rehydrate channel queue from database
+        this.rehydrateQueue(chanDB);
+    }
+
+    /**
+     * Defines server-side socket.io listeners for newly connected sockets
+     * @param {Socket} socket - Newly connected socket to define listeners against
+     */
+    defineListeners(socket){
+        //Queueing Functions
+        socket.on("queue", (data) => {this.queueURL(socket, data)});
+        socket.on("stop", () => {this.stopMedia(socket)}); //needs perms
+        socket.on("delete", (data) => {this.deleteMedia(socket, data)});
+        socket.on("clear", (data) => {this.deleteRange(socket, data)});
+        socket.on("move", (data) => {this.moveMedia(socket, data)});
+        socket.on("lock", () => {this.toggleLock(socket)});
+        socket.on("goLive", (data) => {this.goLive(socket, data)});
+    }
+
+    //--- USER FACING QUEUEING FUNCTIONS ---
+    /**
+     * Accepts new URL's to queue from the client 
+     * @param {Socket} socket - Socket we're receiving the URL from
+     * @param {Object} data - Event payload
+     */
+    async queueURL(socket, data){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: socket.chan});
+
+        if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+            try{
+                //Set url
+                let url = data.url;
+
+                //If we where given a bad URL
+                if(!validator.isURL(url)){
+                    //Attempt to fix the situation by encoding it
+                    url = encodeURI(url);
+
+                    //If it's still bad
+                    if(!validator.isURL(url)){
+                        //Bitch, moan, complain...
+                        loggerUtils.socketErrorHandler(socket, "Bad URL!", "validation");
+                        //and ignore it!
+                        return;
+                    }
+                }
+
+                //If the title is too long
+                if(!validator.isLength(data.title, {max:30})){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Title too long!", "validation");
+                    //and ignore it!
+                    return;
+                }
+    
+                //Set title
+                const title = validator.escape(validator.trim(data.title));
+
+                //Pull media list
+                const mediaList = await yanker.yankMedia(url, title);
+
+                //set start
+                let start = this.getStart(data.start);
+
+                //If we didn't find any media
+                if(mediaList == null || mediaList.length <= 0){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "No media found!", "queue");
+                    //and ignore it!
+                    return;
+                } 
+
+                //Convert media list
+                let queuedMediaList = queuedMedia.fromMediaArray(mediaList, start);
+
+                //schedule the media
+                this.scheduleMedia(queuedMediaList, socket);
+            }catch(err){
+                return loggerUtils.socketExceptionHandler(socket, err);
+            }
+        }
+    }
+
+    /**
+     * Processes requests to stop currently playing media from client
+     * @param {Socket} socket - Socket we received the request from
+     */
+    async stopMedia(socket){
+        try{
+            //Get the current channel from the database
+            const chanDB = await channelModel.findOne({name: socket.chan});
+
+            //Permcheck to make sure the user can fuck w/ the queue
+            if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){       
+                await this.stop();
+            }
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    /**
+     * Processes client requests to delete queued media
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Event payload
+     */
+    async deleteMedia(socket, data){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: socket.chan});
+
+        if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+            try{
+                //If we don't have a valid UUID
+                if(!validator.isUUID(data.uuid)){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Bad UUID!", "queue");
+                    //and ignore it!
+                    return;
+                }
+
+                //Remove media by UUID
+                await this.removeMedia(data.uuid, socket);
+            }catch(err){
+                return loggerUtils.socketExceptionHandler(socket, err);
+            }
+        }
+    }
+
+    /**
+     * Processes request to delete a range of media items from the queue
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Event payload
+     */
+    async deleteRange(socket, data){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: socket.chan});
+
+        if((!this.locked && await chanDB.permCheck(socket.user, 'clearSchedule')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+            try{
+                //If start time isn't an integer
+                if(data.start != null && !validator.isInt(String(data.start))){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Bad start date!", "queue");
+                    //and ignore it!
+                    return;
+                }
+                //If end time isn't an integer
+                if(data.end != null && !validator.isInt(String(data.end))){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Bad end date!", "queue");
+                    //and ignore it!
+                    return;
+                }
+
+                this.removeRange(data.start, data.end, socket);
+            }catch(err){
+                return loggerUtils.socketExceptionHandler(socket, err);
+            }
+        }
+    }
+
+    /**
+     * Processes request to move queued media item
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Event payload
+     */
+    async moveMedia(socket, data){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: socket.chan});
+
+        if((!this.locked && await chanDB.permCheck(socket.user, 'scheduleMedia')) || await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+            try{
+                //If we don't have a valid UUID
+                if(!validator.isUUID(data.uuid)){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Bad UUID!", "queue");
+                    //and ignore it!
+                    return;
+                }
+
+                //If start time isn't an integer
+                if(data.start != null && !validator.isInt(String(data.start))){
+                    //Null out time to tell the later parts of the function to start it now
+                    data.start = undefined;
+                }
+
+                //Move media by UUID
+                this.rescheduleMedia(data.uuid, data.start, socket);
+            }catch(err){
+                return loggerUtils.socketExceptionHandler(socket, err);
+            }
+        }
+    }
+
+    /**
+     * Handle client request to (un)lock queue
+     * @param {Socket} socket - Requesting socket
+     */
+    async toggleLock(socket){
+        //Get the current channel from the database
+        const chanDB = await channelModel.findOne({name: socket.chan});
+
+        //If the user is a schedule admin
+        if(await chanDB.permCheck(socket.user, 'scheduleAdmin')){
+            //Toggle the schedule lock
+            this.locked = !this.locked;
+            
+            //Update schedule lock status for everyone in the channel
+            this.server.io.in(this.channel.name).emit("lock", {locked: this.locked});
+        }
+    }
+
+    /**
+     * Handle client request to start an HLS live stream
+     * @param {Socket} socket - Requesting socket
+     * @param {Object} data - Event payload
+     */
+    async goLive(socket, data){
+        try{
+            let title = "Livestream";
+
+            if(data != null && data.title != null){
+                //If the title is too long
+                if(!validator.isLength(data.title, {max:30})){
+                    //Bitch, moan, complain...
+                    loggerUtils.socketErrorHandler(socket, "Title too long!", "validation");
+                    //and ignore it!
+                    return;
+                }
+
+                //Set title
+                title = validator.escape(validator.trim(data.title));
+
+                //If we've got no title
+                if(title == null || title == ''){
+                    title = "Livestream";
+                }
+            }
+
+            //Grab the channel from DB
+            const chanDB = await channelModel.findOne({name:this.channel.name});
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
+            }
+
+            //If something is playing
+            if(this.nowPlaying != null){
+                //Capture currently playing object
+                this.liveRemainder = this.nowPlaying;
+                chanDB.media.liveRemainder = this.nowPlaying.uuid;
+
+                //Save the chanDB
+                await chanDB.save();
+            }
+
+            //Kill schedule timers to prevent items from starting during the stream
+            await this.stopScheduleTimers();
+
+            //Syntatic sugar because I'm lazy :P
+            const streamURL = chanDB.settings.streamURL;
+
+            if(streamURL == ''){
+                throw loggerUtils.exceptionSmith('This channel\'s HLS Livestream Source has not been set!', 'queue');
+            }
+
+
+            //Pull filename from streamURL
+            let filename = streamURL.match(/^.+\..+\/(.+)$/);
+
+            //If we're streaming from the root of the domain
+            if(filename == null){
+                //Set filename to root
+                filename = '/';
+            }else{
+                //Otherwise, hand over the filename
+                filename = filename[1];
+            }
+
+            //Create queued media object from stream URL and set it to nowPlaying
+            this.nowPlaying = new queuedMedia(
+                title,
+                filename,
+                streamURL,
+                streamURL,
+                "livehls",
+                0,
+                streamURL,
+                new Date().getTime()
+            );
+
+            //Validate mode input, and default to overwrite
+            this.liveMode = (data.mode == "pushback") ? "pushback" : "overwrite";
+
+            //Throw stream lock
+            this.streamLock = true;
+
+            //Broadcast new media object to users
+            this.sendMedia();
+        }catch(err){
+            return loggerUtils.socketExceptionHandler(socket, err);
+        }
+    }
+
+    //--- INTERNAL USE ONLY QUEUEING FUNCTIONS ---
+    /**
+     * Clears and scheduling timers
+     * @param {Boolean} noArchive - Disables Archiving
+     */
+    async stopScheduleTimers(noArchive = true){
+        //End any currently playing media media w/o archiving
+        await this.stop();
+
+        //Clear sync timer
+        clearTimeout(this.syncTimer);
+        //Clear next timer
+        clearTimeout(this.nextTimer);
+        //Clear the pre-switch timer
+        clearTimeout(this.preSwitchTimer);
+
+        //Null out the sync timer
+        this.syncTimer = null;
+        //Null out the next playing item timer
+        this.nextTimer = null;
+        //Null out the pre-switch timer
+        this.preSwitchTimer = null;
+    }
+
+    /**
+     * Validates start times, and replaces bad ones with 5ms in the future 
+     * @param {Number} start - Start time to validate by JS Epoch (millis)
+     * @returns Start time as JS Epoch (millis)
+     */
+    getStart(start){
+        //Pull current time
+        const now = new Date().getTime();
+
+        //If start time is null, or it isn't a valid integer after the current epoch
+        if(start == null || !validator.isInt(String(start), {min: now})){
+            //Get last item from schedule
+            const lastItem = (Array.from(this.schedule)[this.schedule.size - 1]);
+
+            //if we have a last item
+            if(lastItem != null){
+                //If the last item has ended
+                if(lastItem[1].getEndTime() < now){
+                    //Throw it on in five ms
+                    return now;
+                //If it hasn't ended yet
+                }else{
+                    //Throw it on five ms after the last item
+                    return lastItem[1].getEndTime() + 5;
+                }
+            //If we don't have a last item
+            }else{
+                //Throw it on in five ms
+                return now;
+            }
+        }
+
+        //If we fell through, just return input
+        return start;
+    }
+
+    /**
+     * Calculates next item to play, and sets timer to play it at it's scheduled start 
+     * @param {Boolean} volatile - Disables DB Transactions if true
+     */
+    refreshNextTimer(volatile = false){
+        //If we're streamlocked
+        if(this.streamLock){
+            //Stop while we're ahead since the stream hasn't ended yet
+            return;
+        }
+
+        //Grab the next item
+        const nextItem = this.getNextItem();
+
+        //Get current item
+        const currentItem = this.getItemAtEpoch()
+
+        //Clear out any stale timers to prevent ghost queueing
+        clearTimeout(this.nextTimer);
+        clearTimeout(this.preSwitchTimer);
+
+        //If we have a current item and it isn't currently playing
+        if(currentItem != null && (this.nowPlaying == null || currentItem.uuid != this.nowPlaying.uuid)){
+            //Start the found item at w/ a pre-calculated time stamp to reflect the given start time
+            this.start(currentItem, Math.round((new Date().getTime() - currentItem.startTime) / 1000) + currentItem.startTimeStamp, volatile);
+        //If we have a next item
+        }else if(nextItem != null){
+            //Get current time as epoch
+            const now = new Date().getTime();
+            //Calculate the amount of time in ms that the next item will start in
+            const startsIn = nextItem.startTime - now;
+            //Calculate when the pre-switch timer would be called
+            const preSwitchTime = nextItem.startTime - this.preSwitchDelta;
+            //Calculate how long the pre-switch timer will be called in
+            const preSwitchIn = preSwitchTime - now;
+
+            //If we have enough time to call the pre-switch timer
+            if(preSwitchIn > this.preSwitchDelta){
+                //Set the pre-switch timer
+                this.preSwitchTimer = setTimeout(()=>{this.preSwitch(nextItem)}, preSwitchIn);
+            }
+
+            //Set the next timer
+            this.nextTimer = setTimeout(()=>{this.start(nextItem, nextItem.startTimeStamp, volatile)}, startsIn);
+        }
+    }
+
+    /**
+     * Removes range of media items from the queue
+     * @param {Number} start - Start date by JS Epoch (millis)
+     * @param {Number} end - End date by JS Epoch (millis)
+     * @param {Socket} socket - Requesting Socket
+     * @param {Boolean} noUnfinished - Set to true to include items that may be currently playing
+     */
+    async removeRange(start = new Date().getTime() - 60 * 1000, end = new Date().getTime(), socket, noUnfinished = false){
+        //If we're streamlocked
+        if(this.streamLock){
+            //If an originating socket was provided for this request
+            if(socket != null){
+                //Yell at the user for being an asshole
+                loggerUtils.socketErrorHandler(socket, "You cannot edit the schedule while livestreaming!", "queue");
+            }
+
+            //Stop while we're ahead since the stream hasn't ended yet
+            return;
+        }
+
+        //Find items within given range
+        const foundItems = this.getItemsBetweenEpochs(start, end, noUnfinished);
+
+        try{
+            //DO everything ourselves since we don't have a fance end() function to do it
+            const chanDB = await channelModel.findOne({name:this.channel.name});
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
+            }
+
+            //For each item
+            for(let item of foundItems){
+                //Remove media, passing down chanDB so we're not looking again and again
+                await this.removeMedia(item.uuid, socket, chanDB);
+            }
+
+        }catch(err){
+            //If this was originated by someone
+            if(socket != null){
+                //Bitch at them
+                loggerUtils.socketExceptionHandler(socket, err);
+            //If not 
+            }else{
+                //Bitch to the console
+                loggerUtils.localExceptionHandler(err);
+            }
+        }
+    }
+
+    /**
+     * Reschedules a media item
+     * @param {String} uuid - UUID of item to reschedule
+     * @param {Number} start - New start time by JS Epoch (Millis)
+     * @param {Socket} socket - Requesting Socket
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     */
+    async rescheduleMedia(uuid, start = new Date().getTime(), socket, chanDB){
+        //If we're streamlocked
+        if(this.streamLock){
+            //If an originating socket was provided for this request
+            if(socket != null){
+                //Yell at the user for being an asshole
+                loggerUtils.socketErrorHandler(socket, "You cannot edit the schedule while livestreaming!", "queue");
+            }
+            //Stop while we're ahead since the stream hasn't ended yet
+            return;
+        }       
+
+        try{
+            //If we wheren't handed a channel
+            if(chanDB == null){
+                //DO everything ourselves since we don't have a fance end() function to do it
+                chanDB = await channelModel.findOne({name:this.channel.name});
+            }
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
+            }
+
+            //Find our media, don't remove it yet since we want to do some more testing first
+            const media = this.getItemByUUID(uuid);
+
+            //If we got a bad request
+            if(media == null){
+                //If an originating socket was provided for this request
+                if(socket != null){
+                    //Yell at the user for being an asshole
+                    loggerUtils.socketErrorHandler(socket, "Cannot move non-existant item!", "queue");
+                }
+                //Ignore it
+                return;
+            }
+
+            //If someone is trying to re-schedule something that starts in the past
+            if(media.startTime < new Date().getTime()){
+                //If an originating socket was provided for this request
+                if(socket != null){
+                    //If the item is currently playing
+                    if(media.getEndTime() > new Date().getTime()){
+                        //Yell at the user for being an asshole
+                        loggerUtils.socketErrorHandler(socket, "You cannot move an actively playing video!", "queue");
+                    //Otherwise, if it's already ended 
+                    }else{
+                        //Yell at the user for being an asshole
+                        loggerUtils.socketErrorHandler(socket, "You cannot alter the past!", "queue");
+                    }
+                }
+
+
+                //Ignore it
+                return;
+            }
+
+            //Remove the media from the schedule
+            await this.removeMedia(uuid, socket, chanDB);
+
+            //Grab the old start time for safe keeping
+            const oldStart = media.startTime;
+
+            //Set media time
+            media.startTime = start;
+
+            //Reset the start time stamp for re-calculation
+            media.startTimeStamp = 0;
+
+            //Attempt to schedule media at given time
+            //Otherwise, if it returns false for fuckup, with noSave enabled
+            if(!(await this.scheduleMedia([media], socket, chanDB))){
+                //Reset start time
+                media.startTime = oldStart;
+
+                //Reset the start time stamp for re-calculation
+                media.startTimeStamp = 0;
+
+                //Schedule in old slot with noSave enabled
+                await this.scheduleMedia([media], socket, chanDB, true);
+            }
+
+        }catch(err){
+            //If this was originated by someone
+            if(socket != null){
+                //Bitch at them
+                loggerUtils.socketExceptionHandler(socket, err);
+            //If not 
+            }else{
+                //Bitch to the console
+                loggerUtils.localExceptionHandler(err);
+            }
+        }
+    }
+
+    /**
+     * Removes a media item
+     * @param {String} uuid - UUID of item to reschedule
+     * @param {Socket} socket - Requesting Socket
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     * @param {Boolean} noScheduling - Disables schedule timer refresh if true
+     * @returns {Media} Deleted Media Item
+     */
+    async removeMedia(uuid, socket, chanDB, noScheduling = false){
+        //If we're streamlocked
+        if(this.streamLock){
+            //If an originating socket was provided for this request
+            if(socket != null){
+                //Yell at the user for being an asshole
+                loggerUtils.socketErrorHandler(socket, "You cannot edit the schedule while livestreaming!", "queue");
+            }
+            //Stop while we're ahead since the stream hasn't ended yet
+            return;
+        }
+
+        //Get requested media
+        const media = this.getItemByUUID(uuid);
+
+        //If we got a bad request
+        if(media == null){
+            try{
+                //If we wheren't handed a channel
+                if(chanDB == null){
+                    //DO everything ourselves since we don't have a fance end() function to do it
+                    chanDB = await channelModel.findOne({name:this.channel.name});
+                }
+
+                //If we couldn't find the channel
+                if(chanDB == null){
+                    //FUCK
+                    throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
+                }
+
+                //Keep a copy of the archive that hasn't been changed
+                const preArchive = chanDB.media.archived;
+
+                //Filter out the requested item from the archive
+                chanDB.media.archived = chanDB.media.archived.filter((record)=>{
+                    return record.uuid.toString() != uuid;
+                })
+
+                //If nothing changed in the archive
+                if(preArchive.length == chanDB.media.archived.length){
+                    //If an originating socket was provided for this request
+                    if(socket != null){
+                        //Yell at the user for being an asshole
+                        loggerUtils.socketErrorHandler(socket, "Cannot delete non-existant item!", "queue");
+                    }
+                //Otherwise
+                }else{
+                    //Broadcast changes
+                    this.broadcastQueue(chanDB);
+                    //Save changes to the DB
+                    await chanDB.save();
+                }
+            }catch(err){
+                //If this was originated by someone
+                if(socket != null){
+                    //Bitch at them
+                    loggerUtils.socketExceptionHandler(socket, err);
+                //If not 
+                }else{
+                    //Bitch to the console
+                    loggerUtils.localExceptionHandler(err);
+                }
+            }
+
+            //Ignore it
+            return false;
+        }
+
+        //Take the item out of the schedule map
+        this.schedule.delete(media.startTime);
+
+        if(!noScheduling){
+            //Refresh next timer
+            this.refreshNextTimer();
+        }
+
+        //If we're currently playing the requested item.
+        if(this.nowPlaying != null && this.nowPlaying.uuid == uuid){
+            //If scheduling is enabled
+            if(!noScheduling){
+                //End playback
+                this.end(false, true);
+            }
+        //otherwise
+        }else{
+            try{
+                //If we wheren't handed a channel
+                if(chanDB == null){
+                    //DO everything ourselves since we don't have a fance end() function to do it
+                    chanDB = await channelModel.findOne({name:this.channel.name});
+                }
+
+                //If we couldn't find the channel
+                if(chanDB == null){
+                    //FUCK
+                    throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while queue item!`, "queue");
+                }
+
+                //Filter media out by UUID
+                chanDB.media.scheduled = chanDB.media.scheduled.filter((record) => {
+                    return record.uuid != uuid;
+                });
+
+                //If saving is enabled (seperate from all DB transactions since caller function may want modifications but handle saving on its own)
+                if(!noScheduling){
+                    await chanDB.save();
+                }
+
+                //Broadcast the channel
+                this.broadcastQueue(chanDB);
+
+            }catch(err){
+                //Broadcast the channel
+                this.broadcastQueue();
+
+                //If this was originated by someone
+                if(socket != null){
+                    //Bitch at them
+                    loggerUtils.socketExceptionHandler(socket, err);
+                //If not 
+                }else{
+                    //Bitch to the console
+                    loggerUtils.localExceptionHandler(err);
+                }
+            }
+        }
+
+        //return found media in-case our calling function needs it :P
+        return media;
+    }
+
+    /**
+     * Schedules a Media Item
+     * 
+     * This is a fun method and I think it deserves it's own little explination...
+     * Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option
+     * I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass.
+     * Maps seem like a good choice, if it wheren't for the issue of keeping them ordered...
+     *
+     * That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map,
+     * we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally.
+     *
+     * Also a note on preformance:
+     * While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background,
+     * simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely,
+     * since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about.
+     * Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely.
+     * This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider
+     * that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways...
+     * 
+     * 
+     * Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds.
+     * This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC)
+     * Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P
+     * 
+     * If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication
+     * 
+     * Further Reading:
+     * https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays
+     * https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it
+     *  
+     * @param {Media} - Media item to schedule
+     * @param {Socket} socket - Requesting Socket
+     * @param {Mongoose.Document} chanDB - Channnel Document Passthrough to save on DB Access
+     * @param {Boolean} force - Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
+     * @param {Boolean} volatile - Prevent DB Writes, used for internal function calls
+     * @param {Boolean} startVolatile - Runs refreshNextTimer calls without DB writes, used for internal function calls
+     * @param {Boolean} saveLate - Saves items even if they're about to, or have already started. Used for internal function calls
+     * @param {Boolean} noSave - Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+     */
+    async scheduleMedia(media, socket, chanDB, force = false, volatile = false, startVolatile = false, saveLate = false, noSave = false){
+        //If we're streamlocked and this isn't being forced
+        if(this.streamLock && !force){
+            //If an originating socket was provided for this request
+            if(socket != null){
+                //Yell at the user for being an asshole
+                loggerUtils.socketErrorHandler(socket, "You cannot edit the schedule while livestreaming!", "queue");
+            }
+            //Stop while we're ahead since the stream hasn't ended yet
+            return;
+        }
+
+        for(let mediaObj of media){
+            const now = new Date().getTime();
+
+            //If someone is trying to schedule something that starts and ends in the past
+            if((mediaObj.getEndTime() < now) && !force){
+                //If an originating socket was provided for this request
+                if(socket != null){
+                    //Yell at the user for being an asshole
+                    loggerUtils.socketErrorHandler(socket, "You cannot alter the past!", "queue");
+                }
+                return false;
+            }
+
+            //If the item has already started
+            if((mediaObj.startTime < now) && !force){
+                //Set time stamp to existing timestamp plus the difference between the orginal start-date and now
+                const calculatedTimeStamp = mediaObj.startTimeStamp + ((now - mediaObj.startTime) / 1000)
+
+                //If the calculated time stamp is more than negligible, and therefore not simply caused by serverside processing time
+                if(calculatedTimeStamp > 5){
+                    //Set the media timestamp
+                    mediaObj.startTimeStamp = calculatedTimeStamp;
+
+                    //Start the item now
+                    mediaObj.startTime = now;
+                }
+            }
+
+            //If there's already something queued right now
+            if(this.getItemAtEpoch(mediaObj.startTime) != null || this.getItemAtEpoch(mediaObj.getEndTime())){
+                //If an originating socket was provided for this request
+                if(socket != null){
+                    //Yell at the user for being an asshole
+                    loggerUtils.socketErrorHandler(socket, "This time slot has already been taken in the queue!", "queue");
+                }
+                //Ignore it
+                return false;
+            } 
+
+            //If we start in less than 10 seconds
+            if((mediaObj.startTime - this.preSwitchDelta) < now){
+                //Asyncrhounosly Check if we need to refresh the raw link
+                this.handleRawRefresh(mediaObj);
+            }
+
+            //Create an empty temp array to sparsley populate with our schedule
+            const tempSchedule = [];
+            //Create new map to replace our current schedule map
+            const newSchedule = new Map();
+
+            //For every item that's already been scheduled
+            for(let item of this.schedule){
+                //add it to the slot corresponding to it's start epoch in seconds
+                tempSchedule[Math.round(item[0] / 1000)] = item[1];
+            }
+
+            //Inject the media object into the slot corresponding to it's epoch in the temp schedule array
+            tempSchedule[Math.round(mediaObj.startTime / 1000)] = mediaObj;
+
+            //For every populated key in our array
+            for(let startTime of Object.keys(tempSchedule)){
+                //Add item to replacement schedule map
+                newSchedule.set(tempSchedule[startTime].startTime, tempSchedule[startTime]);
+            }
+
+            //Replace the existing schedule map with our new one
+            this.schedule = newSchedule;
+
+            //Broadcast the channel queue
+            this.broadcastQueue();
+
+            //Refresh the next timer to ensure whatever comes on next is right
+            this.refreshNextTimer(startVolatile);
+
+            //If media has more than a minute before starting OR saveLate is enabled and DB transactions are enabled
+            if((mediaObj.startTime - new Date().getTime() > 1000 || saveLate) && !volatile){
+                //fuck you yoda you fucking nerd
+                try{
+                    //If we didn't get handed a freebie
+                    if(chanDB == null){
+                        //Go out and get it done ourselves
+                        chanDB = await channelModel.findOne({name:this.channel.name});
+                    }
+
+                    //If we couldn't find the channel
+                    if(chanDB == null){
+                        //FUCK
+                        throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while saving item to queue!`, "queue");
+                    }
+
+                    //Add media to the persistant schedule
+                    chanDB.media.scheduled.push(mediaObj);
+
+                //If something fucked up
+                }catch(err){
+                    //If this was originated by someone
+                    if(socket != null){
+                        //Bitch at them
+                        loggerUtils.socketExceptionHandler(socket, err);
+                    //If not 
+                    }else{
+                        //Bitch to the console
+                        loggerUtils.localExceptionHandler(err);
+                    }
+                }
+            }
+        }
+
+        //If we fucked with the DB during the main loop
+        if(chanDB != null && !volatile){
+            try{
+                //If saving is enabled (seperate from all DB transactions since caller function may want modifications but handle saving on its own)
+                if(!noSave){
+                    //Save the database
+                    await chanDB.save();
+                }
+            //If something fucked up
+            }catch(err){
+                //If this was originated by someone
+                if(socket != null){
+                    //Bitch at them
+                    loggerUtils.socketExceptionHandler(socket, err);
+                //If not 
+                }else{
+                    //Bitch to the console
+                    loggerUtils.localExceptionHandler(err);
+                }
+            }
+        }
+
+        //return true to let everyone know this shit worked
+        return true;
+    }
+
+    /**
+     * Called 10 seconds before media begins to play
+     * @param {queuedMedia} mediaObj - Media object that's about to play
+     */
+    async preSwitch(mediaObj){
+        this.handleRawRefresh(mediaObj);
+    }
+
+    /**
+     * Refreshes expired raw links before media plays
+     * @param {queuedMedia} mediaObj - Media object that's about to play
+     * @returns {queuedMedia} passes through Media object with updated link upon success
+     */
+    async handleRawRefresh(mediaObj){
+        //Check if media needs a new raw link and update if it does
+        if(await yanker.refreshRawLink(mediaObj)){
+            //If the fetch took so god damned long we've already started the video (isn't 10 seconds enough?)
+            if(this.nowPlaying != null && this.nowPlaying.uuid == mediaObj.uuid){
+                //Tell the clients to update the raw file for the current item fore.st-style, as it probably got sent out with a stale link
+                this.server.io.in(this.channel.name).emit("updateCurrentRawFile", {file: mediaObj.rawLink});
+            }
+
+            //Return media obj to tell of success
+            return mediaObj;
+        }
+    }
+
+    /**
+     * Kicks off a media item
+     * @param {queuedMedia} mediaObj - Media object that's about to play
+     * @param {Number} timestamp - Media start timestamp in seconds
+     * @param {Boolean} volatile - Disables DB Transactions
+     */
+    async start(mediaObj, timestamp = mediaObj.startTimeStamp, volatile = false){
+        //If something is already playing
+        if(this.nowPlaying != null){
+            //Silently end the media in RAM so the database isn't stepping on itself up ahead
+            //Alternatively we could've used await, but then we'd be doubling up on DB transactions :P
+            this.end(true, true, true);
+        }
+
+        //reset current timestamp
+        this.timestamp = timestamp;
+
+        //Set current playing media
+        this.nowPlaying = mediaObj;
+
+        //You might think it'd make sense to remove this item from the schedule like we will in the DB to keep it in nowPlaying only
+        //That however, is not how this was originally made, and updating it would take more work and break more shit than is worth
+        //Especially since one could argue that not deleting now-playing items in the RAM schedule makes it easier to iterate through
+        //We can get away with doing so in the DB since it only needs to be iterated once, 
+        //If I was to re-do this from scratch I'd probably at least try it out with it deleting them here
+        //But agin, this is months in, not really worth it since it doesn't really cause any issues...
+
+        //if DB transactions are enabled
+        if(!volatile){
+            try{
+                //Get our channel
+                const chanDB = await channelModel.findOne({name: this.channel.name});
+
+                //If nowPlaying isn't null and isn't what we're about to throw on
+                if(chanDB.media.nowPlaying != null && chanDB.media.nowPlaying.uuid.toString() != mediaObj.uuid){
+                    //Archive whats already in there since we're about to clobber the fuck out of it
+                    chanDB.media.archived.push(chanDB.media.nowPlaying);
+                }
+
+                //Set the now playing queued media document
+                chanDB.media.nowPlaying = mediaObj;
+
+                //Filter media out of schedule by UUID
+                chanDB.media.scheduled = chanDB.media.scheduled.filter((record) => {
+                    return record.uuid != mediaObj.uuid;
+                });
+
+                //Save the channel
+                await chanDB.save();
+            }catch(err){
+                loggerUtils.localExceptionHandler(err);
+            }
+        }
+
+        //Send play signal out to the channel
+        this.sendMedia();
+
+        //Kill existing sync timers to prevent kicking-off ghost timer loops
+        clearTimeout(this.syncTimer);
+
+        //Kick off the sync timer
+        this.syncTimer = setTimeout(this.sync.bind(this), this.syncDelta);
+
+        //Setup the next video
+        this.refreshNextTimer();
+
+        //return media object for use
+        return mediaObj;
+    }
+
+    /**
+     * Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta
+     * Called auto-magically by the Synchronization Timer
+     */
+    sync(){
+        //Send sync signal out to the channel
+        this.server.io.in(this.channel.name).emit("sync", {timestamp: this.timestamp});
+
+        //If the media has been cleared out
+        if(this.nowPlaying == null){
+            //Fuck off and don't bother
+            return;
+        }
+
+        //If the media has over a second to go
+        if((this.timestamp + 1) < this.nowPlaying.duration){
+            //Increment the time stamp
+            this.timestamp += (this.syncDelta / 1000);
+
+            //Call the sync function in another second
+            this.syncTimer = setTimeout(this.sync.bind(this), this.syncDelta);
+        }else{
+            //Get leftover video length in ms
+            const leftover = (this.nowPlaying.duration - this.timestamp) * 1000;
+
+            //Call the end function once the video is over
+            this.syncTimer = setTimeout(this.end.bind(this), leftover);
+        }
+    }
+
+    /**
+     * End currently playing media
+     * @param {Boolean} quiet - Enable to prevent ending the media client-side
+     * @param {Boolean} noArchive - Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
+     * @param {Boolean} volatile - Enable to prevent DB Transactions
+     * @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
+     */
+    async end(quiet = false, noArchive = false, volatile = false, chanDB){
+        try{
+            //If we're not playing anything
+            if(this.nowPlaying == null){
+                //Silently ignore the request
+                return;
+            }
+
+            //Call off any existing sync timer
+            clearTimeout(this.syncTimer);
+
+            //Clear out the sync timer
+            this.syncTimer = null;
+
+            //Keep a copy of whats playing for later when we need to clear the DB
+            const wasPlaying = this.nowPlaying;
+
+            //Clear now playing
+            this.nowPlaying = null;
+
+            //Clear timestamp
+            this.timestamp = 0;
+
+            //If we're not being quiet
+            if(!quiet){
+                //Tell everyone of the end-times
+                this.server.io.in(this.channel.name).emit('end', {});
+            }
+
+            //If we're ending an HLS Livestream
+            if(wasPlaying.type == "livehls"){
+                //Redirect to the endLivestream function
+                return this.endLivestream(wasPlaying, chanDB)
+            }
+
+            //If we're not in volatile mode and we're not ending a livestream
+            if(!volatile){
+                //If we wheren't handed a channel
+                if(chanDB == null){
+                    //Now that everything is clean, we can take our time with the DB :P
+                    chanDB = await channelModel.findOne({name:this.channel.name});
+                }
+
+                //If we couldn't find the channel
+                if(chanDB == null){
+                    //FUCK
+                    throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while ending queue item!`, "queue");
+                }
+
+                //If we haven't changed 'nowPlaying' in the play list
+                if(chanDB.media.nowPlaying != null && chanDB.media.nowPlaying.uuid == wasPlaying.uuid){
+                    //Take it out
+                    await chanDB.media.nowPlaying.deleteOne();
+                }
+
+                //Take it out of the active schedule
+                this.schedule.delete(wasPlaying.startTime);
+
+                //If archiving is enabled
+                if(!noArchive){
+                    //Add the item to the channel archive
+                    chanDB.media.archived.push(wasPlaying);
+                }
+
+                //broadcast queue using unsaved archive, run this before chanDB.save() for better responsiveness
+                this.broadcastQueue(chanDB);
+
+                //Save our changes to the DB
+                await chanDB.save();
+            }else{
+                //broadcast queue using unsaved archive
+                this.broadcastQueue(chanDB);
+            }
+        }catch(err){
+            this.broadcastQueue();
+            loggerUtils.localExceptionHandler(err);
+        }
+    }
+
+    /**
+     * Ends running Livestream
+     * @param {queuedMedia} wasPlaying  - Media object that was playing while we started the Livestream
+     * @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
+     */
+    async endLivestream(wasPlaying, chanDB){
+        try{
+            //If we wheren't handed a channel
+            if(chanDB == null){
+                //Now that everything is clean, we can take our time with the DB :P
+                chanDB = await channelModel.findOne({name:this.channel.name});
+            }
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while ending queue item!`, "queue");
+            }
+            //Disable stream lock
+            this.streamLock = false;
+
+            //We don't have to save here since someone else will do it for us :)
+            chanDB.media.liveRemainder = null;
+
+            //Get current epoch
+            const now = new Date().getTime()
+
+            //Set duration from start and end time
+            wasPlaying.duration = (now - wasPlaying.startTime) / 1000;
+
+            //If we're in pushback mode
+            if(this.liveMode == "pushback"){
+                await this.livestreamPushbackSchedule(wasPlaying, chanDB);
+            //Otherwise
+            }else{
+                //This is where I'd stick the IF statetement I'd add to switch between overwrite 
+                await this.livestreamOverwriteSchedule(wasPlaying, chanDB)
+            }
+
+            //Refresh next timer
+            this.refreshNextTimer();
+
+            //Null out live mode
+            this.liveMode = null;
+
+            //Broadcast Queue
+            this.broadcastQueue();
+        //ACK
+        }catch(err){
+            //Broadcast queue
+            this.broadcastQueue();
+            //Handle the error
+            loggerUtils.localExceptionHandler(err);
+        }
+    }
+
+    /**
+     * Overwrites livestream over scheduled media content after it has ended
+     * @param {queuedMedia} wasPlaying  - Media object that was playing while we started the Livestream
+     * @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
+     */
+    async livestreamOverwriteSchedule(wasPlaying, chanDB){
+        try{
+            //Get current epoch
+            const now = new Date().getTime()
+
+            //If we wheren't handed a channel
+            if(chanDB == null){
+                //Now that everything is clean, we can take our time with the DB :P
+                chanDB = await channelModel.findOne({name:this.channel.name});
+            }
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while ending queue item!`, "queue");
+            }
+
+            //mark overwrite job as finished so we don't run two sets of logic, as one needs to do a null check before it can run it's conditional
+            //while the other needs to run regardless of this.liveRemainders definition
+            let finished = false;
+
+            //Throw the livestream into the archive
+            chanDB.media.archived.push(wasPlaying);
+
+            //Save the DB
+            await chanDB.save();
+
+            //If we have a live remainder
+            if(this.liveRemainder != null){
+                //If the item hasn't ended
+                if(finished = (this.liveRemainder.getEndTime(true) > now)){
+                    //Rip out early end
+                    this.liveRemainder.earlyEnd = undefined;
+
+                    //regenerate UUID to differentiate between this and the original item
+                    this.liveRemainder.genUUID();
+
+                    //Re-schedule the remainder
+                    await this.scheduleMedia([this.liveRemainder], undefined, chanDB);
+                }
+            }
+
+            //if "THIS ISN'T OVER, PUNK!"
+            if(!finished){
+                //Pull item from end
+                const wasPlayingDuringEnd = this.getItemAtEpoch(now);
+
+                //If we ended in the middle of something
+                if(wasPlayingDuringEnd != null){
+                    const difference = (now - wasPlayingDuringEnd.startTime);
+
+                    //Take item out
+                    await this.removeMedia(wasPlayingDuringEnd.uuid, null, chanDB);
+
+                    //Push the item up to match the difference
+                    wasPlayingDuringEnd.startTime += difference;
+
+                    //re-set start time stamp based on media start and stream end
+                    wasPlayingDuringEnd.startTimeStamp = Math.round(difference / 1000);
+
+                    //Make unique, true
+                    wasPlayingDuringEnd.genUUID();
+
+                    //Re-schedule media now that it's been cut
+                    await this.scheduleMedia([wasPlayingDuringEnd], null, chanDB);
+                }
+
+                //Remove all the in-betweeners
+                await this.removeRange(wasPlaying.startTime, now, null, true);
+            }
+
+
+            //Null out live remainder for the next stream
+            this.liveRemainder = null;
+        }catch(err){
+            //Null out live remainder for the next stream
+            this.liveRemainder = null;
+
+            //Handle the error
+            loggerUtils.localExceptionHandler(err);
+        }
+
+    }
+
+    /**
+     * Pushes back any missed content scheduled during Livestream after Livestream has ended.
+     * @param {queuedMedia} wasPlaying  - Media object that was playing while we started the Livestream
+     * @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
+     */
+    async livestreamPushbackSchedule(wasPlaying, chanDB){
+        try{
+            //Get current epoch
+            const now = new Date().getTime()
+
+            //If we wheren't handed a channel
+            if(chanDB == null){
+                //Now that everything is clean, we can take our time with the DB :P
+                chanDB = await channelModel.findOne({name:this.channel.name});
+            }
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while ending queue item!`, "queue");
+            }
+
+            //Throw the livestream into the archive
+            chanDB.media.archived.push(wasPlaying);
+
+            //Set the current place to schedule items at 5ms after the end of the live stream
+            let curPlace = wasPlaying.getEndTime() + 5;
+            const newSched = [];
+
+            //if we have a live remainder
+            if(this.liveRemainder != null){
+                //Set item to continue where it left off
+                this.liveRemainder.startTimeStamp = this.liveRemainder.earlyEnd;
+
+                //Rip out the early end so it finish up
+                this.liveRemainder.earlyEnd = null;
+
+                //Generate new UUID for uniqueness
+                this.liveRemainder.genUUID();
+
+                //Set start time to the end of the stream
+                this.liveRemainder.startTime = curPlace;
+
+                //Reset starter time to end of current item + 5ms
+                curPlace = this.liveRemainder.getEndTime(true) + 5;
+
+                //Throw live remainder into the new schedule
+                newSched.push(this.liveRemainder);
+
+                //Null out live remainder for the next stream
+                this.liveRemainder = null;
+                chanDB.liveRemainder = null;
+            }
+
+            //Iterate through objects in schedule
+            for(const entry of this.schedule){
+                //Pull media object from map entry
+                const mediaObj = entry[1];
+
+                //Remove media from queue without calling chanDB.save() to make room before we move everything
+                await this.removeMedia(mediaObj.uuid, null, chanDB, true);
+
+                mediaObj.genUUID();
+
+                //Change start time to current starter place
+                mediaObj.startTime = curPlace;
+
+                //Throw item into the temp sched
+                newSched.push(mediaObj);
+
+                //Set cur place to 5ms after the item we just queued
+                curPlace = mediaObj.getEndTime() + 5;
+            }
+
+            //Schedule the moved schedule, letting scheduleMedia save our changes for us, starting w/o saves to prevent over-saving
+            await this.scheduleMedia(newSched, null, chanDB);
+        }catch(err){
+            //Null out live remainder for the next stream
+            this.liveRemainder = null;
+
+            //Handle the error
+            loggerUtils.localExceptionHandler(err);
+        }
+
+    }
+
+    /**
+     * Stops currently playing media item
+     * @param {Socket} socket - Requesting Socket
+     * @returns returns false if there is nothing to stop
+     */
+    stop(socket){
+        //If we're not currently playing anything
+        if(this.nowPlaying == null){
+            //If an originating socket was provided for this request
+            if(socket != null){
+                //Yell at the user for being an asshole
+                throw loggerUtils.exceptionSmith(`No media playing`, "queue");
+            }
+            //Ignore it
+            return false;
+        }
+
+        //Stop playing
+        const stoppedMedia = this.nowPlaying;
+
+        //Ignore early end for livestreams
+        if(this.nowPlaying.type != 'livehls'){
+            //Get difference between current time and start time and set as early end
+            stoppedMedia.earlyEnd = (new Date().getTime() - stoppedMedia.startTime) / 1000;
+        }
+
+        //End the media
+        this.end();
+    }
+
+    /**
+     * Returns scheduled media between two given datetimes
+     * @param {Number} start - Start date by JS Epoch (Millis)
+     * @param {Number} end - End date by JS Epoch (Millis)
+     * @param {Boolean} noUnfinished - Enable to include currently playing media
+     * @returns {queuedMedia} Found Media Objects
+     */
+    getItemsBetweenEpochs(start, end, noUnfinished = false){
+        //Create an empty array to hold found items
+        const foundItems = [];
+
+        //Loop through scheduled items
+        for(let item of this.schedule){
+            //If the item starts after our start date and before our end date
+            if(item[0] >= start && item[0] <= end ){
+                //If we're allowed to add unifnished items, or the item has finished
+                if(!noUnfinished || item[1].getEndTime() <= end){
+                    //Add the current item to the list
+                    foundItems.push(item[1]);
+                }
+            }
+        }
+
+        //Return any found items
+        return foundItems;
+    }
+
+    /**
+     * Gets a media item by epoch 
+     * @param {Number} epoch - Date to check by JS Epoch (Millis)
+     * @returns {queuedMedia} found media item
+     */
+    getItemAtEpoch(epoch = new Date().getTime()){
+        //Loop through scheduled items
+        for(let item of this.schedule){
+            //If we're past or at the start time and at or before the end time
+            if(item[0] <= epoch && item[1].getEndTime() >= epoch){
+                //return the current item
+                return item[1]
+            }
+        }
+
+        //If we fell through the loop return null
+        return null;
+    }
+
+    /**
+     * Gets last item from a given epoch
+     * @param {Number} epoch - Date to check by JS Epoch (Millis), defaults to now
+     * @returns Last played item
+     */
+    getLastItem(epoch = new Date().getTime()){
+        //Create variable to hold the last item
+        let last;
+
+        //Loop through scheduled items
+        for(let item of this.schedule){
+            //If we've stumbled on to the next item
+            if(item[0] >= epoch){
+                //Break the loop
+                break;
+            //If we've stumbled upon an item that is currently playing
+            }else if(item[1].getEndTime() >= epoch){
+                //Break the loop
+                break;
+            //If we made it through this iteration without breaking the loop
+            }
+
+            //Set current item to last item
+            last = item[1];
+        }
+
+        //If the loop has been broken or fallen through, return last.
+        return last;
+    }
+
+    /**
+     * Gets next item from a given epoch
+     * @param {Number} epoch - Date to check by JS Epoch (Millis), defaults to now
+     * @returns {queuedMedia} Next item on the schedule
+     */
+    getNextItem(epoch = new Date().getTime()){
+        //Iterate through the schedule
+        for(let item of this.schedule){
+            if(item[0] >= epoch){
+                //Pull the scheduled media object from the map entry array
+                return item[1];
+            }
+        }
+    }
+
+    /**
+     * Get Scheduled Item by UUID
+     * @param {String} uuid - UUID of item to reschedule
+     * @returns {queuedMedia} found item
+     */
+    getItemByUUID(uuid){
+        //Iterate through the schedule
+        for(let item of this.schedule){
+            //If the uuid matches
+            if(item[1].uuid == uuid){
+                //return the found item
+                return item[1];
+            }
+        }
+    }
+
+    /**
+     * Send media update to a specific socket or broadcast it to the entire channel
+     * @param {Socket} socket - Requesting Socket
+     */
+    sendMedia(socket){
+        //Create data object
+        const data = {
+            media: this.nowPlaying,
+            timestamp: this.timestamp
+        }
+
+        //If a socket is specified
+        if(socket != null){
+            //Send data out to specified socket
+            socket.emit("start", data);
+        //Otherwise
+        }else{
+            //Send that shit out to the entire channel
+            this.server.io.in(this.channel.name).emit("start", data);
+        }
+
+    }
+
+    /**
+     * Broadcasts channel queue
+     * @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
+     */
+    async broadcastQueue(chanDB){
+        this.server.io.in(this.channel.name).emit('queue',{queue: await this.prepQueue(chanDB)});
+    }
+
+    /**
+     * Prepares channel queue for network transmission
+     * @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
+     * @returns de-hydrated scehdule information
+     */
+    async prepQueue(chanDB){
+        try{
+            //If we didn't get handed a freebie
+            if(chanDB == null){
+                //Go out and get it done ourselves
+                chanDB = await channelModel.findOne({name:this.channel.name});
+            }
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while rehydrating queue!`, "queue");
+            }
+
+            //Create an empty array to hold our schedule
+            let schedule = [];
+
+            //Get yestedays epoch
+            const yesterday = new Date().setDate(new Date().getDate() - 1);
+
+            //Iterate through the channel archive backwards to save time
+            for(let mediaIndex = chanDB.media.archived.length - 1; mediaIndex >= 0; mediaIndex--){
+                //Grab the current media record
+                let media = chanDB.media.archived[mediaIndex].rehydrate();
+
+                //If the media started within the last 24 hours
+                if(media.startTime > yesterday){
+                    //If we're sending out the live remainder during a live stream
+                    if(this.liveRemainder != null && media.uuid.toString() == this.liveRemainder.uuid.toString()){
+                        //Throw out the early end before sending it off, so it looks like it hasn't been cut off yet (smoke n mirrors :P)
+                        media.earlyEnd = null;
+                    }
+
+                    //Add it to the schedule array as if it where part of the actual schedule map
+                    schedule.push([media.startTime, media]);
+                //Otherwise if it's older
+                }else{
+                    //Then we should be done as archived items are added as they are played/end.
+                    //No newer items should be beyond this point!
+                    break;
+                }
+            }
+
+            //Concatonate the actual schedule to the items we pulled out of the archive return it
+            return schedule.concat(Array.from(this.schedule));
+        //If we can't get shit from the database
+        }catch(err){
+            //Complain
+            loggerUtils.localExceptionHandler(err);
+            //broadcast what we can from RAM
+            return Array.from(this.schedule);
+        }
+    }
+
+    /**
+     * Rehydrates media schedule from DB 
+     * @param {Mongoose.Document} chanDB - Pass through Channel Document to save on DB Transactions
+     */
+    async rehydrateQueue(chanDB){
+        try{
+            //If we didn't get handed a freebie
+            if(chanDB == null){
+                //Go out and get it done ourselves
+                chanDB = await channelModel.findOne({name:this.channel.name});
+            }
+
+            //If we couldn't find the channel
+            if(chanDB == null){
+                //FUCK
+                throw loggerUtils.exceptionSmith(`Unable to find channel document ${this.channel.name} while rehydrating queue!`, "queue");
+            }
+
+            //Get current time
+            const now = new Date().getTime();
+
+            //If something was playing
+            if(chanDB.media.nowPlaying != null && chanDB.media.nowPlaying.type != 'livehls'){
+                //Rehydrate the currently playing item int oa queued media object
+                const wasPlaying = chanDB.media.nowPlaying.rehydrate();
+
+                //If the media hasn't ended yet
+                if(wasPlaying.getEndTime() > now){
+                    //Re-Schedule it in RAM
+                    await this.scheduleMedia([wasPlaying], null, chanDB, true, true, true);
+                //Otherwise, if it has
+                }else{
+                    //Null out nowPlaying
+                    chanDB.media.nowPlaying = null;
+
+                    //Archive the bitch
+                    chanDB.media.archived.push(wasPlaying);
+                }
+            }
+
+            //Create a new array to hold the new schedule since we'll only be keeping select items
+            let newSched = [];
+
+            //For every saved scheduled item
+            for(let record of chanDB.media.scheduled){
+                //Rehydrate the current record into a queued media object
+                const mediaObj = record.rehydrate();
+
+                //If the item hasn't started
+                if(mediaObj.startTime > now){
+                    //Add record to new schedule
+                    newSched.push(record);
+
+                    //Re-Schedule it in RAM, with the start function running w/ DB transactions enabled, since it won't happen right away
+                    await this.scheduleMedia([mediaObj], null, chanDB, true, true, false);
+                }else{
+                    //If the media should be playing now
+                    if(mediaObj.getEndTime() > now){
+                        //Save record to nowPlaying in the DB
+                        chanDB.media.nowPlaying = record;
+
+                        //Schedule the fucker in RAM, w/ the start function also running in RAM-Only mode
+                        await this.scheduleMedia([mediaObj], null, chanDB, true, true, true);
+                    //If it's been ended
+                    }else{
+                        //Archive ended media
+                        chanDB.media.archived.push(record);
+                    }
+                }
+            }
+
+            //If we have a remainder from a livestream
+            if(chanDB.media.liveRemainder){
+                //Iterate backwards through the archive to pull the newest first, since that's probably where this fucker is
+                for(let archiveIndex = (chanDB.media.archived.length - 1); archiveIndex > 0; archiveIndex--){
+                    //Grab the current media object
+                    const archivedMedia = chanDB.media.archived[archiveIndex];
+
+                    //If the current object matches our remainder UUID
+                    if((archivedMedia.uuid.toString() == chanDB.media.liveRemainder.toString())){
+                        //Null out any early end
+                        archivedMedia.earlyEnd = null;
+
+                        //Re-hydrate the item
+                        const archivedMediaObject = archivedMedia.rehydrate();
+
+                        //if we still have a video to finish
+                        if(archivedMediaObject.getEndTime() > now){
+                            //Set the fucker as now playing
+                            chanDB.media.nowPlaying = archivedMediaObject; 
+
+                            //Schedule the fucker in RAM, w/ the start function also running in RAM-Only mode
+                            this.scheduleMedia([archivedMediaObject], null, chanDB, true, true, true);
+
+                            //Splice the fucker out of the archive
+                            chanDB.media.archived.splice(archiveIndex, 1);
+                        }
+
+                        //Break out of the loop
+                        break;
+                    }
+                }
+            }
+
+            //Update schedule to only contain what hasn't been played yet
+            chanDB.media.scheduled = newSched;
+
+            //Save the DB
+            await chanDB.save();
+
+        //if something fucked up
+        }catch(err){
+            //bitch about it in the server console
+            loggerUtils.localExceptionHandler(err);
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_media_queuedMedia.js.html b/www/doc/app_channel_media_queuedMedia.js.html new file mode 100644 index 0000000..6add7c3 --- /dev/null +++ b/www/doc/app_channel_media_queuedMedia.js.html @@ -0,0 +1,172 @@ + + + + + JSDoc: Source: app/channel/media/queuedMedia.js + + + + + + + + + + +
+ +

Source: app/channel/media/queuedMedia.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Local Imports
+const media = require('./media');
+
+/**
+ * Class extending media which represents a queued piece of media
+ * @extends media
+ */
+module.exports = class extends media{
+    /**
+     * Creates a new queued media object
+     * @param {Number} startTime - JS Epoch representing start time
+     * @param {Number} startTimeStamp - Media start time stamp in seconds (relative to duration)
+     * @param {Number} earlyEnd - Media end timestamp in seconds (relative to duration)
+     * @param {String} uuid - Media object's unique identifier
+     */
+    constructor(title, fileName, url, id, type, duration, rawLink, startTime, startTimeStamp = 0, earlyEnd, uuid){
+        //Call derived constructor
+        super(title, fileName, url, id, type, duration, rawLink);
+        //Set media start time
+        this.startTime = startTime;
+        //Set the media start time stamp
+        this.startTimeStamp = startTimeStamp;
+        //Create empty variable to hold early end if media is stopped early
+        this.earlyEnd = earlyEnd;
+        //Set status for discriminator key
+        this.status = 'queued';
+
+        //If we have a null uuid (can't use default argument because of 'this')
+        if(uuid == null){
+            //Generate id unique to this specific entry of this specific file within this specific channel's queue
+            //That way even if we have six copies of the same video queued, we can still uniquely idenitify each instance
+            this.genUUID();
+        }else{
+            this.uuid = uuid;
+        }
+    }
+
+    //statics
+    /**
+     * Creates a queuedMedia object from a media object
+     * @param {media} media - Media object to queue
+     * @param {Number} startTime - Start time formatted as a JS Epoch
+     * @param {Number} startTimeStamp - Start time stamp in seconds
+     * @returns {queuedMedia} queuedMedia object created from given media object
+     */
+    static fromMedia(media, startTime, startTimeStamp){
+        //Create and return queuedMedia object from given media object and arguments 
+        return new this(
+            media.title,
+            media.fileName,
+            media.url,
+            media.id,
+            media.type,
+            media.duration,
+            media.rawLink,
+            startTime,
+            startTimeStamp);
+    }
+
+    /**
+     * Converts array of media objects into array of queuedMedia objects
+     * @param {Array} mediaList - Array of media objects to queue
+     * @param {Number} start - Start time formatted as JS Epoch
+     * @returns Array of converted queued media objects
+     */
+    static fromMediaArray(mediaList, start){
+        //Queued Media List
+        const queuedMediaList = [];
+        //Start Time Offset
+        let startOffset = 0;
+
+        for(let media of mediaList){
+            //Convert mediaObj to queuedMedia and push to the back of the list
+            queuedMediaList.push(this.fromMedia(media, start + startOffset, 0));
+
+            //Set start offset to end of the current item
+            startOffset += (media.duration * 1000) + 5;
+        }
+
+        return queuedMediaList;
+    }
+
+    //methods
+    /**
+     * Generates new unique identifier for queued media
+     */
+    genUUID(){
+        this.uuid = crypto.randomUUID();
+    }
+
+    /**
+     * return the end time of a given queuedMedia object
+     * @param {boolean} fullTime - Overrides early ends
+     * @returns end time of given queuedMedia object
+     */
+    getEndTime(fullTime = false){
+        //If we have an early ending
+        if(this.earlyEnd == null || fullTime){
+            //Calculate our ending
+            return this.startTime + ((this.duration - this.startTimeStamp) * 1000);
+        }else{
+            //Return our early end
+            return this.startTime + (this.earlyEnd * 1000);
+        }
+    }
+}
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/app_channel_tokebot.js.html b/www/doc/app_channel_tokebot.js.html new file mode 100644 index 0000000..cbb9662 --- /dev/null +++ b/www/doc/app_channel_tokebot.js.html @@ -0,0 +1,281 @@ + + + + + JSDoc: Source: app/channel/tokebot.js + + + + + + + + + + +
+ +

Source: app/channel/tokebot.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Local Imports
+const tokeCommandModel = require('../../schemas/tokebot/tokeCommandSchema');
+const {userModel} = require('../../schemas/user/userSchema');
+const statSchema = require('../../schemas/statSchema');
+
+
+/**
+ * Class containing global server-side tokebot logic
+ */
+module.exports = class tokebot{
+    /**
+     * Instantiates a tokebot object
+     * @param {channelManager} server - Parent Server Object
+     * @param {chatHandler} chatHandler - Parent Chat Handler Object
+     */
+    constructor(server, chatHandler){
+        //Set parents
+        this.server = server;
+        this.chatHandler = chatHandler;
+
+        //Set timeouts to null
+        this.tokeTimer = null;
+        this.cooldownTimer = null;
+
+        //Set start times
+        this.tokeTime = 60;
+        this.cooldownTime = 120;
+
+        //Create counter variable
+        this.tokeCounter = 0;
+        this.cooldownCounter = 0;
+
+        //Create tokers list
+        this.tokers = new Map();
+
+        //Load in toke commands from the DB
+        this.refreshCommands();
+    }
+
+    /**
+     * Reloads toke commands from DB into RAM-based toke command store
+     */
+    async refreshCommands(){
+        //Pull Command Strings from DB
+        this.tokeCommands = await tokeCommandModel.getCommandStrings();
+    }
+
+    /**
+     * Processes toke commands from Command Pre-Processor
+     * @param {Object} commandObj - Object representing a single given command/chat request, passed down from the Command Pre-Processor
+     * @returns {Boolean} True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat)
+     */
+    tokeProcessor(commandObj){
+        //Check for site-wide toke commands
+        if(this.tokeCommands.indexOf(commandObj.argumentArray[0].toLowerCase()) != -1){
+            //Seems lame to set a bool in an if statement but this would've made a really ugly turinary
+            var foundToke = true;
+        }else if(commandObj.argumentArray[0].toLowerCase() == 'r'){
+            //Find the users active channel
+            const activeChan = this.server.activeChannels.get(commandObj.socket.chan);
+            
+            //Combile site-wide and channel tokes into one list
+            const tokeList = this.tokeCommands.concat(activeChan.tokeCommands);
+
+            //Pick a random number between 0 and one less than the number of tokes
+            const foundIndex = Math.round(Math.random() * (tokeList.length - 1));
+
+            //Set override command argument 0 w/ the found toke
+            commandObj.argumentArray[0] = tokeList[foundIndex];
+
+            //throw toke flag
+            var foundToke = true;
+        }else{
+            //Find the users active channel
+            const activeChan = this.server.activeChannels.get(commandObj.socket.chan);
+
+            //Check if they're using a channel-only toke
+            //This should be safe to do without a null check but someone prove me wrong lmao
+            var foundToke = (activeChan.tokeCommands.indexOf(commandObj.argumentArray[0].toLowerCase()) != -1);
+        }
+
+
+        //If we found a toke
+        if(foundToke){
+            //If there is no active toke or cooldown (new toke)
+            if(this.tokeTimer == null && this.cooldownTimer == null){
+                //Call-out toke start
+                this.chatHandler.relayTokeCallout(`A group toke has been started by ${commandObj.socket.user.user} from #${commandObj.socket.chan}! We'll be taking a toke in 60 seconds - join in by posting !${commandObj.argumentArray[0]}`);
+                //Set a full minute on our toke timer
+                this.tokeCounter = this.tokeTime;
+
+                //Add the toking user to the tokers map
+                this.tokers.set(commandObj.socket.user.user, commandObj.argumentArray[0].toLowerCase());
+
+                //kick-off the count-down
+                this.tokeTimer = setTimeout(this.countdown.bind(this), 1000)
+            //If the tokeTimer is popping but the cooldownTimer has fucked off (a toke is in progress)
+            }else if(this.cooldownTimer == null){
+                //look for user in tokers map
+                const foundToker = this.tokers.get(commandObj.socket.user.user);
+
+                //if the user has not yet joined the toke
+                if(foundToker == null){
+                    //Call-out toke join
+                    this.chatHandler.relayTokeCallout(`${commandObj.socket.user.user} has joined the toke from #${commandObj.socket.chan}! Post !${commandObj.argumentArray[0]} to take part!`);
+
+                    //Add the toking user to the tokers map
+                    this.tokers.set(commandObj.socket.user.user, commandObj.argumentArray[0].toLowerCase());
+                //If the user is already in the toke
+                }else{
+                    //Tell them to fuck off
+                    this.chatHandler.relayTokeWhisper(commandObj.socket, "You're already taking part in this toke!");
+                }
+
+            //Otherwise (there isn't a toke timer, but there is a cooldown timer. AKA: we're in cooldown)
+            }else{
+                //if the cooldownTimer exists (we're cooling down the toke)
+                this.chatHandler.relayTokeWhisper(commandObj.socket, `Please wait ${this.cooldownCounter} seconds before starting a new group toke.`);
+            }
+
+            //Toke command found, and there isn't any extra text, don't send as chat (re-create fore.st tokebot behaviour)
+            return (commandObj.command != `!${commandObj.argumentArray[0]}` && commandObj.command != '!r');
+        }else{
+            //No toke found, send it down the line, because shaming the user is funny
+            return true;
+        }
+    }
+
+    /**
+     * Called each second during the toke. Handles decrementing the timer variable, and countdown end logic.
+     */
+    countdown(){
+        //If we're in the last three seconds
+        if(this.tokeCounter <= 3 && this.tokeCounter > 0){
+            //Callout the last three seconds
+            this.chatHandler.relayTokeCallout(`${this.tokeCounter}...`);
+        //if the toke is over
+        }else if(this.tokeCounter < 0){
+            //if we had multiple tokers
+            if(this.tokers.size > 1){
+                //call out the toke
+                this.chatHandler.relayTokeCallout(`Take a toke ${Array.from(this.tokers.keys()).join(', ')}! ${this.tokers.size} tokers!`);
+            //if we only had one toker
+            }else{
+                //call out the solo toke
+                this.chatHandler.relayTokeCallout(`Take a toke ${Array.from(this.tokers.keys())[0]}.`);
+            }
+
+            //Asynchronously tattoo the toke into the users documents within the database so that tokebot doesn't have to wait or worry about DB transactions
+            userModel.tattooToke(this.tokers);
+            //Do the same for the global stat schema
+            statSchema.tattooToke(this.tokers);
+
+            //Set the toke cooldown
+            this.cooldownCounter  = this.cooldownTime;
+            this.cooldownTimer = setTimeout(this.cooldown.bind(this), 1000);
+
+            //Empty out the tokers array
+            this.tokers = new Map;
+
+            //Null out our timer
+            this.tokeTimer = null;
+
+            //return the function before it can continue
+            return;
+        }
+
+        //Decrement toke time
+        this.tokeCounter--;
+        //try again in another second
+        this.tokeTimer = setTimeout(this.countdown.bind(this), 1000)
+    }
+
+    /**
+     * This method seems to be a vestage from a bygone era. We should remove it after documenting shit.
+     * I would now, but I don't want to break shit in a comment-only commit.
+     */
+    async asyncFinisher(){
+        //Grab a copy of the tokers map before it gets cleared out
+        const tokers = this.tokers;
+
+        //we need to wait for this so we don't send used tokes pre-maturely
+        await userModel.tattooToke(tokers);
+    }
+
+    /**
+     * Runs every second for 60 seconds after a toke
+     */
+    cooldown(){
+        //If the cooldown timer isn't over
+        if(this.cooldownCounter > 0){
+            //Decrement toke time
+            this.cooldownCounter--;
+            //try again in another second
+            this.cooldownTimer = setTimeout(this.cooldown.bind(this), 1000);
+        //If the cooldown is over
+        }else{
+            //Null out the cooldown timer
+            this.cooldownTimer = null;
+        }
+    }
+
+    /**
+     * Resets toke cooldowns early upon authorized request
+     */
+    resetToke(){
+        //Set cooldown to 0
+        this.cooldownCounter = 0;
+
+        //Null out the timer
+        this.cooldownTimer = null;
+    }
+
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/chat.html b/www/doc/chat.html new file mode 100644 index 0000000..417f4d3 --- /dev/null +++ b/www/doc/chat.html @@ -0,0 +1,338 @@ + + + + + JSDoc: Class: chat + + + + + + + + + + +
+ +

Class: chat

+ + + + + + +
+ +
+ +

chat(user, flair, highLevel, msg, type, links)

+ +
Class representing a single chat message
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new chat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Instantiates a chat message object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +connectedUser + + + + User who sent the message
flair + + +String + + + + Flair ID String for the flair used to send the message
highLevel + + +Number + + + + Number representing current high level
msg + + +String + + + + Contents of the message, with links replaced with numbered file-seperator markers
type + + +String + + + + Message Type Identifier, used for client-side processing.
links + + +Array + + + + Array of URLs/Links included in the message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/chatBuffer.html b/www/doc/chatBuffer.html new file mode 100644 index 0000000..d5b0936 --- /dev/null +++ b/www/doc/chatBuffer.html @@ -0,0 +1,838 @@ + + + + + JSDoc: Class: chatBuffer + + + + + + + + + + +
+ +

Class: chatBuffer

+ + + + + + +
+ +
+ +

chatBuffer(server, chanDB, channel)

+ +
Class representing a stored chat buffer
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new chatBuffer(server, chanDB, channel)

+ + + + + + +
+ Instantiates a new chat buffer for a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent Server Object
chanDB + + +Mongoose.Document + + + + chanDB to rehydrate buffer from
channel + + +activeChannel + + + + Parent Channel Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

handleBusyRoom()

+ + + + + + +
+ Called after 5 minutes of solid activity +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleInactivity()

+ + + + + + +
+ Called after 10 seconds of chat room inactivity +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

push(chat)

+ + + + + + +
+ Adds a given chat to the chat buffer in RAM and sets any appropriate timers for DB transactions +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat object to commit to buffer
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) saveDB(reason, chanDB)

+ + + + + + +
+ Saves RAM-Based buffer to Channel Document in DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
reason + + +String + + + + Reason for DB save, formatted as 'x minutes/seconds of in/activity', used for logging purposes
chanDB + + +Mongoose.Document + + + + Channel Doc to work with, can be left empty for method to auto-find through channel name.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

shift()

+ + + + + + +
+ Removes the oldest item from the chat buffer + +Was originally created in-case we needed to trigger timing functions + +Left here since it seems like good form anywho, since this would be a private, or at least protected member in another language +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/commandProcessor.html b/www/doc/commandProcessor.html new file mode 100644 index 0000000..251dce7 --- /dev/null +++ b/www/doc/commandProcessor.html @@ -0,0 +1,1840 @@ + + + + + JSDoc: Class: commandProcessor + + + + + + + + + + +
+ +

Class: commandProcessor

+ + + + + + +
+ +
+ +

commandProcessor(server, chatHandler)

+ +
Class representing global server-side chat/command processing logic
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new commandProcessor(server, chatHandler)

+ + + + + + +
+ Instantiates a commandProcessor object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent Server Object
chatHandler + + +chatHandler + + + + Parent Chat Handler Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) announce(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!announce' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag on un-authorized call to shame the user +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

bold(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!bold' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) clear(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!clear' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag on un-authorized call to shame the user +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

italics(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!italics' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) kick(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!kick' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag on un-authorized call to shame the user +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) resettoke(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!resettoke' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag on un-authorized call to shame the user +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) serverannounce(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!serverannounce' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag on un-authorized call to shame the user +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

spoiler(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!spoiler' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

strikethrough(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!strikethrough' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

whisper(commandObj) → {Boolean}

+ + + + + + +
+ Command Processor method to handle the '!whisper' command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True to enable send flag +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/fonts/OpenSans-Bold-webfont.eot b/www/doc/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..5d20d91 Binary files /dev/null and b/www/doc/fonts/OpenSans-Bold-webfont.eot differ diff --git a/www/doc/fonts/OpenSans-Bold-webfont.svg b/www/doc/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/www/doc/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/doc/fonts/OpenSans-Bold-webfont.woff b/www/doc/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..1205787 Binary files /dev/null and b/www/doc/fonts/OpenSans-Bold-webfont.woff differ diff --git a/www/doc/fonts/OpenSans-BoldItalic-webfont.eot b/www/doc/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..1f639a1 Binary files /dev/null and b/www/doc/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/www/doc/fonts/OpenSans-BoldItalic-webfont.svg b/www/doc/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..6a2607b --- /dev/null +++ b/www/doc/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/doc/fonts/OpenSans-BoldItalic-webfont.woff b/www/doc/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..ed760c0 Binary files /dev/null and b/www/doc/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/www/doc/fonts/OpenSans-Italic-webfont.eot b/www/doc/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..0c8a0ae Binary files /dev/null and b/www/doc/fonts/OpenSans-Italic-webfont.eot differ diff --git a/www/doc/fonts/OpenSans-Italic-webfont.svg b/www/doc/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..e1075dc --- /dev/null +++ b/www/doc/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/doc/fonts/OpenSans-Italic-webfont.woff b/www/doc/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..ff652e6 Binary files /dev/null and b/www/doc/fonts/OpenSans-Italic-webfont.woff differ diff --git a/www/doc/fonts/OpenSans-Light-webfont.eot b/www/doc/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..1486840 Binary files /dev/null and b/www/doc/fonts/OpenSans-Light-webfont.eot differ diff --git a/www/doc/fonts/OpenSans-Light-webfont.svg b/www/doc/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/www/doc/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/doc/fonts/OpenSans-Light-webfont.woff b/www/doc/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..e786074 Binary files /dev/null and b/www/doc/fonts/OpenSans-Light-webfont.woff differ diff --git a/www/doc/fonts/OpenSans-LightItalic-webfont.eot b/www/doc/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..8f44592 Binary files /dev/null and b/www/doc/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/www/doc/fonts/OpenSans-LightItalic-webfont.svg b/www/doc/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/www/doc/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/doc/fonts/OpenSans-LightItalic-webfont.woff b/www/doc/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..43e8b9e Binary files /dev/null and b/www/doc/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/www/doc/fonts/OpenSans-Regular-webfont.eot b/www/doc/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..6bbc3cf Binary files /dev/null and b/www/doc/fonts/OpenSans-Regular-webfont.eot differ diff --git a/www/doc/fonts/OpenSans-Regular-webfont.svg b/www/doc/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..25a3952 --- /dev/null +++ b/www/doc/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/doc/fonts/OpenSans-Regular-webfont.woff b/www/doc/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..e231183 Binary files /dev/null and b/www/doc/fonts/OpenSans-Regular-webfont.woff differ diff --git a/www/doc/global.html b/www/doc/global.html new file mode 100644 index 0000000..038459c --- /dev/null +++ b/www/doc/global.html @@ -0,0 +1,7386 @@ + + + + + JSDoc: Global + + + + + + + + + + +
+ +

Global

+ + + + + + +
+ +
+ +

+ + +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

cache

+ + + + +
+ Basic RAM-Based cache of links, so we don't have to re-pull things after we get them +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) channelBanSchema

+ + + + +
+ DB Schema for Documents representing a user ban from a single channel +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) channelPermissionSchema

+ + + + +
+ DB Schema for Sub-Document representing permission structure for a single channel +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) channelSchema

+ + + + +
+ DB Schema for Documents containing de-hydrated representations of Canopy Stream/Chat Channels +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) chatSchema

+ + + + +
+ DB Schema for documents representing a single chat message +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) daysToExpire

+ + + + +
+ Email change token retention time +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) daysToExpire

+ + + + +
+ Password reset token retention time +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) emailChangeSchema

+ + + + +
+ DB Schema for Document representing a single email change request +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) emoteSchema

+ + + + +
+ DB Schema for documents represnting site-wide emotes +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) failedAttempts

+ + + + +
+ Create failed sign-in cache since it's easier and more preformant to implement it this way than adding extra burdon to the database +Server restarts are far and few between. It would take multiple during a single bruteforce attempt for this to become an issue. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) flairSchema

+ + + + +
+ DB Schema for documents representing chat flair +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) lifetime

+ + + + +
+ Captcha lifetime in minutes +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) maxAttempts

+ + + + +
+ How many attempts to lock user account out for the day +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) mediaSchema

+ + + + +
+ DB Schema representing a single piece of media +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) passwordResetSchema

+ + + + +
+ DB Schema for documents containing a single expiring password reset token +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) permissionSchema

+ + + + +
+ DB Schema for the singular site-wide permission document +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) playlistMediaProperties

+ + + + +
+ DB Schema for documents represnting a piece of media held in a playlist +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) playlistSchema

+ + + + +
+ DB Schema for Documents representing playlists full of media +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) queuedProperties

+ + + + +
+ DB Schema for documents representing a queued media object +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) rankEnum

+ + + + +
+ Rank Enum, lists all known permission ranks from lowest to highest. + +This originally belonged to the permissionSchema, but this avoids circular dependencies. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) spent

+ + + + +
+ Create empty array to hold cache of spent payloads to protect against replay attacks +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) statSchema

+ + + + +
+ DB Schema for single document for keeping track of server stats +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) throttleAttempts

+ + + + +
+ How many failed attempts required to throttle with altcha +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) tokeCommandSchema

+ + + + +
+ Mongoose Schema representing a toke command +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) transporter

+ + + + +
+ nodemailer transport object, generated from options specific in our config file +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) typeEnum

+ + + + +
+ "Enum" for emote type property +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) userBanSchema

+ + + + +
+ DB Schema for Documents representing a single user's ban +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

(constant) userSchema

+ + + + +
+ Mongoose Schema for a document representing a single canopy user +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

authenticateSession(user, pass, req)

+ + + + + + +
+ Sole and Singular Session Authentication method. +All logins should happen through here, all other site-wide authentication should happen by sessions authenticated by this model. +This is important, as reducing authentication endpoints reduces attack surface. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to login as
pass + + +String + + + + Password to authenticat session with
req + + +express.Request + + + + Express request object w/ session to authenticate
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Username of authticated user upon success +
+ + + + + + + + + + + + + + + +

comparePassword(pass, hash) → {Boolean}

+ + + + + + +
+ Sitewide password for authenticating/comparing passwords agianst hashes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
pass + + +String + + + + Plaintext Password
hash + + +String + + + + Salty Hash
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if authentication success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

consoleWarn(string)

+ + + + + + +
+ Prints warning text to server console +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
string + + +String + + + + String to print to console
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

errorHandler(res, msg, type, status) → {Express.Response}

+ + + + + + +
+ Main error handling function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
res + + +Express.Response + + + + Response being sent out to the client who caused the issue
msg + + +String + + + + Error message to send the client
type + + +String + + + + Error type to send back to the client
status + + +Number + + + + HTTP(s) Status Code to send back to the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ If we have a usable Express Response object, return it back after it's been cashed +
+ + + +
+
+ Type +
+
+ +Express.Response + + +
+
+ + + + + + + + + + + + + +

errorMiddleware(err, req, res, next)

+ + + + + + +
+ Basic error-handling middleware to ensure we're not dumping stack traces to the client, as that would be insecure +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
err + + +Error + + + + Error to handle
req + + +Express.Request + + + + Express Request
res + + +Express.Response + + + + Express Response
next + + +function + + + + Next function in the Express middleware chain (Not that it's getting called XP)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

escapeRegex(string) → {String}

+ + + + + + +
+ I won't lie this line was whole-sale ganked from stack overflow like a fucking skid +In my defense I only did it because js-runtime-devs are taking fucking eons to implement RegExp.escape() +This should be replaced once that function becomes available in mainline versions of node.js: +https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/escape +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
string + + +String + + + + Regex string to escape
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The Escaped String +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

exceptionHandler(res, err)

+ + + + + + +
+ Handles exceptions which where directly the fault of user action >:( +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
res + + +Express.Response + + + + Express Response object to bitch at
err + + +Error + + + + Error created by the jerk in question
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

exceptionSmith(msg, type) → {Error}

+ + + + + + +
+ Creates and returns a custom exception, tagged as a 'custom' exception, using the 'custom' boolean property. +This is used to denote that this error was generated on purpose, with a human readable message, that can be securely sent to the client. +Unexpected exceptions should only be logged internally, however, as they may contain sensitive data. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Error message to send the client
type + + +String + + + + Error type to send back to the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ The exception to smith +
+ + + +
+
+ Type +
+
+ +Error + + +
+
+ + + + + + + + + + + + + +

fetchMetadata(fullID, title) → {Array}

+ + + + + + +
+ Pulls metadate for a given archive.org item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fullID + + +String + + + + Full path of the requested upload
title + + +String + + + + Title to add to media object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Generated list of media objects from given upload path +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) fetchVideoMetadata(link, title, type) → {Array}

+ + + + + + +
+ Generic single video YTDLP function meant to be used by service-sepecific fetchers which will then be used to fetch video metadata +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
link + + +String + + + + Link to video in question
title + + +String + + + + Title to add to the given media objects
type + + +String + + + + Link type to attach to the resulting media object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of Media objects containing relevant metadata +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

fetchYoutubeMetadata(id, title) → {Media}

+ + + + + + +
+ Pulls metadata for a single youtube video via YT-DLP +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
id + + +String + + + + Youtube Video ID
title + + +String + + + + Title to add to the given media object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Media object containing relevant metadata +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

fetchYoutubePlaylistMetadata(id, title) → {Array}

+ + + + + + +
+ Pulls metadata for a playlist of youtube videos via YT-DLP +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
id + + +String + + + + Youtube Playlist ID
title + + +String + + + + Title to add to the given media objects
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of Media objects containing relevant metadata +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

genCaptcha(difficulty, uniqueSecret) → {String}

+ + + + + + +
+ Generates captcha challenges to send down to the browser +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
difficulty + + +Number + + + + Challange Difficulty (x100K internally)
uniqueSecret + + +String + + + + Secret to salt the challange hash with
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Altcha Challenge hash +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

getLoginAttempts(user) → {Number}

+ + + + + + +
+ Returns how many failed login attempts within the past day or so since the last login has occured for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User to check map against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ of failed login attempts +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

getMediaType(url) → {Object}

+ + + + + + +
+ Detects media type by URL + +I'd be lying if this didn't take at least some inspiration/regex patterns from extractQueryParam() in cytube/forest's browser-side 'util.js' +Still this has some improvements like url pre-checks and the fact that it's handled serverside, recuing possibility of bad requests. +Some of the regex expressions for certain services have also been improved, such as youtube, and the fore.st-unique archive.org +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
url + + +String + + + + URL to determine media type of
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ containing URL type and clipped ID string +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

hashIP(ip) → {String}

+ + + + + + +
+ Site-wide IP hashing/salting function + +Provides a basic level of privacy by only logging salted hashes of IP's +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
ip + + +String + + + + IP to hash
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Hashed/Salted IP Adress +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

hashPassword(pass) → {String}

+ + + + + + +
+ Sitewide function for hashing passwords +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
pass + + +String + + + + Password to hash
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Hashed/Salted password +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

kickoff()

+ + + + + + +
+ Kicks off first run of scheduled functions before scheduling functions for regular callback +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

killSession(session)

+ + + + + + +
+ Logs user out and destroys all server-side traces of a given session +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
session + + +express-session.session + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

localExceptionHandler(err)

+ + + + + + +
+ Handles local exceptions which where not directly created by user interaction +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
err + + +Error + + + + Exception to handle
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

mailem(to, subject, body, htmlBody) → {Object}

+ + + + + + +
+ Sends an email as tokebot to the requested user w/ the requested body and signature +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
to + + +String + + + + String containing the email address to send to
subject + + +String + + + + Subject line of the email to send
body + + +String + + + + Body contents, either HTML or Plaintext
htmlBody + + +Boolean + + + + Whether or not Body contents should be sent as HTML or Plaintext
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Sent mail info +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ Validates links and returns a marked link object that can be returned to the client to format/embed accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
link + + +String + + + + URL to Validate
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Marked link object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

processExpiredAttempts()

+ + + + + + +
+ Nightly Function Call which iterates through the failed login attempts map, removing any which haven't been attempted in over a da yeahy +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Refreshes raw links on relevant media objects + +Useful for sources like youtube, who only provide expiring raw links +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +ScheduledMedia + + + + Media Object to refresh
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Refreshed media object +
+ + + +
+
+ Type +
+
+ +ScheduledMedia + + +
+
+ + + + + + + + + + + + + +

schedule()

+ + + + + + +
+ Schedules all timed jobs accross the server +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

securityCheck()

+ + + + + + +
+ Basic security check which runs on startup. +Warns server admin against unsafe config options. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendAddressVerification(requestDB, userDB, newEmail)

+ + + + + + +
+ Sends address verification email +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
requestDB + + +Mongoose.Document + + + + DB Document Object for the current email change request token
userDB + + +Mongoose.Document + + + + DB Document Object for the user we're verifying email against
newEmail + + +String + + + + New email address to send to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCriticalExceptionHandler(socket, err) → {Boolean}

+ + + + + + +
+ Generates error messages and drops connection for critical errors caused by socket.io interaction +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket error originated from
err + + +Error + + + + Error created by the jerk in question
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Passthrough from socket.disconnect +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

socketErrorHandler(socket, msg, type) → {Boolean}

+ + + + + + +
+ Basic error-handling for socket.io so we don't just silently swallow errors. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket error originated from
msg + + +String + + + + Error message to send the client
type + + +String + + + + Error type to send back to the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Passthrough from socket.emit +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

socketExceptionHandler(socket, err) → {Boolean}

+ + + + + + +
+ Generates error messages for simple errors generated by socket.io interaction +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket error originated from
err + + +Error + + + + Error created by the jerk in question
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Passthrough from socket.emit +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

verify(payload, uniqueSecret) → {boolean}

+ + + + + + +
+ Verifies completed altcha challenges handed over from the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
payload + + +String + + + + Completed Altcha Payload
uniqueSecret + + +String + + + + Server-side Unique Secret to verify payload came from server-generated challenge
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if payload is a valid and unique altcha challenge which originated from this server +
+ + + +
+
+ Type +
+
+ +boolean + + +
+
+ + + + + + + + + + + + + +

yankMedia(url, title) → {Array}

+ + + + + + +
+ Checks a given URL and runs the proper metadata fetching function to create a media object from any supported URL +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
url + + +String + + + + URL to yank media against
title + + +String + + + + Title to apply to yanked media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Returns list of yanked media objects on success +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) ytdlpFetch(link, format) → {Object}

+ + + + + + +
+ Basic async YT-DLP Fetch wrapper, ensuring config +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
link + + +String + + + + + + Link to fetch using YT-DLP
format + + +String + + + + + + b + + Format string to hand YT-DLP, defaults to 'b'
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Metadata dump from YT-DLP +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/index.html b/www/doc/index.html new file mode 100644 index 0000000..4927765 --- /dev/null +++ b/www/doc/index.html @@ -0,0 +1,65 @@ + + + + + JSDoc: Home + + + + + + + + + + +
+ +

Home

+ + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/module.exports.html b/www/doc/module.exports.html new file mode 100644 index 0000000..128de4a --- /dev/null +++ b/www/doc/module.exports.html @@ -0,0 +1,202454 @@ + + + + + JSDoc: Class: exports + + + + + + + + + + +
+ +

Class: exports

+ + + + + + +
+ +
+ +

exports(server, chanDB)

+ +
Class representing a single active channel
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(server, chanDB)

+ + + + + + +
+ Instantiates an activeChannel object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent Server Object
chanDB + + +Mongoose.Document + + + + chanDB to rehydrate buffer from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(io)

+ +
Class containing global server-side channel connection management logic
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(io)

+ + + + + + +
+ Instantiates object containing global server-side channel conection management logic +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
io + + +Server + + + + Socket.io server instanced passed down from server.js
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(server)

+ +
Class containing global server-side chat relay logic
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(server)

+ + + + + + +
+ Instantiates a chatHandler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent Server Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(server, chatHandler)

+ +
Class containing global server-side chat/command pre-processing logic
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(server, chatHandler)

+ + + + + + +
+ Instantiates a commandPreprocessor object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent Server Object
chatHandler + + +chatHandler + + + + Parent Chat Handler Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(userDB, chanRank, channel, socket)

+ +
Class representing a single user connected to a channel
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(userDB, chanRank, channel, socket)

+ + + + + + +
+ Instantiates a connectedUser object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User document to re-hydrate user from
chanRank + + +PemissionModel.chanRank + + + + Enum representing user channel rank
channel + + +String + + + + Channel the user is connecting to
socket + + +Socket + + + + Socket associated with the users connection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(title, fileName, url, id, type, duration, rawLink)

+ +
Object representing a piece of media
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(title, fileName, url, id, type, duration, rawLink)

+ + + + + + +
+ Creates a new media object from scraped information +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
title + + +String + + + + Chosen title of media
fileName + + +String + + + + Original filename/title of media provided by source
url + + +String + + + + Original URL to file
id + + +String + + + + Video ID from source (IE: youtube watch code/archive.org file path)
type + + +String + + + + Original video source
duration + + +Number + + + + Length of media in seconds
rawLink + + +String + + + + URL to raw file copy of media, not applicable to all sources
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(server, channel)

+ +
Class containing playlist management logic for a single channel
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(server, channel)

+ + + + + + +
+ Instantiates a new object to handle playlist management for a single channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent server object
channel + + +activeChannel + + + + Parent Channel object for desired channel queue
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(server, chanDB, channel)

+ +
Object represneting a single channel's media queue
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(server, chanDB, channel)

+ + + + + + +
+ Instantiates a new media queue for a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent server object
chanDB + + +Document + + + + Related Channel Document from DB
channel + + +activeChannel + + + + Parent Channel object for desired channel queue
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(startTime, startTimeStamp, earlyEnd, uuid)

+ +
Class extending media which represents a queued piece of media
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(startTime, startTimeStamp, earlyEnd, uuid)

+ + + + + + +
+ Creates a new queued media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
startTime + + +Number + + + + + + JS Epoch representing start time
startTimeStamp + + +Number + + + + + + 0 + + Media start time stamp in seconds (relative to duration)
earlyEnd + + +Number + + + + + + Media end timestamp in seconds (relative to duration)
uuid + + +String + + + + + + Media object's unique identifier
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • media
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + + +
+ +
+ +

exports(server, chatHandler)

+ +
Class containing global server-side tokebot logic
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new exports(server, chatHandler)

+ + + + + + +
+ Instantiates a tokebot object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
server + + +channelManager + + + + Parent Server Object
chatHandler + + +chatHandler + + + + Parent Chat Handler Object
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(async) addPersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to add a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Adds media to channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) addToPlaylistValidator(socket, URL) → {Array}

+ + + + + + +
+ Validates client requests to add media to a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
URL + + +String + + + + URL String handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ List of media objects which where added +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

(async) addToUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Adds media to user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) asyncFinisher()

+ + + + + + +
+ This method seems to be a vestage from a bygone era. We should remove it after documenting shit. +I would now, but I don't want to break shit in a comment-only commit. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) authSocket(socket) → {Mongoose.Document}

+ + + + + + +
+ Global server-side authorization logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - Authorized User Document upon success +
+ + + +
+
+ Type +
+
+ +Mongoose.Document + + +
+
+ + + + + + + + + + + + + +

(async) broadcastChanEmotes(chanDB)

+ + + + + + +
+ Broadcasts channel emote list to connected users +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastQueue(chanDB)

+ + + + + + +
+ Broadcasts channel queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) broadcastSiteEmotes()

+ + + + + + +
+ Broadcast global emote list +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

broadcastUserList()

+ + + + + + +
+ Broadcasts user list to all users +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Changes default titles for a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) changeDefaultTitlesUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Changes default titles for a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

changeDefaultTitlesValidator(data) → {Array}

+ + + + + + +
+ Validates client requests to change default titles for a given playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of strings containing valid titles from the output +
+ + + +
+
+ Type +
+
+ +Array + + +
+
+ + + + + + + + + + + + + +

clearChat(user, chan)

+ + + + + + +
+ Clears chat for a given channel, targets specified user or entire channel if none found/specified. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + User chats to clear
chan + + +String + + + + Channel to broadcast message within
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

cooldown()

+ + + + + + +
+ Runs every second for 60 seconds after a toke +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

countdown()

+ + + + + + +
+ Called each second during the toke. Handles decrementing the timer variable, and countdown end logic. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

crawlConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) createChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Creates a new channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

createPlaylistValidator(socket, data) → {Object}

+ + + + + + +
+ Validates client requests to create a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated titles +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) createUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Creates a new user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Define Global Server-Side socket event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines global server-side chat relay event listeners +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

defineListeners(socket)

+ + + + + + +
+ Defines server-side socket.io listeners for newly connected sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylist(socket, data, userDB)

+ + + + + + +
+ Deletes a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteChannelPlaylistMedia(socket, data, chanDB)

+ + + + + + +
+ Deletes media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteMedia(socket, data)

+ + + + + + +
+ Processes client requests to delete queued media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deletePersonalEmote(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

deletePlaylistMediaValidator(socket, data)

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteRange(socket, data)

+ + + + + + +
+ Processes request to delete a range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylist(socket, data, chanDB)

+ + + + + + +
+ Deletes a Channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) deleteUserPlaylistMedia(socket, data, userDB)

+ + + + + + +
+ Deletes media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

disconnect(reason, type)

+ + + + + + +
+ Disconnects all sockets for a given user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
reason + + +String + + + + + + Reason for being disconnected
type + + +String + + + + + + Disconnected + + Disconnection Type
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

emit(eventName, data)

+ + + + + + +
+ Emits an event to all known sockets for a given user + +My brain keeps going back to using dynamic per-user namespaces for this +but everytime i look into it I come to the conclusion that it's a bad idea, then I toy with making chans namespaces +and using per-user channels for this, but what of gold or mod-only features? or games? +No matter what it'd probably end up hacky, as namespaces where meant for splitting app logic not user comms (like rooms). +at the end of the day there has to be some penance for decent multi-session handling on-top of a library that doesn't do it. +Having to crawl through these sockets is that. Because the other ways seem more gross somehow. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
eventName + + +String + + + + Event name to emit to client sockets
data + + +Object + + + + Data to emit to client sockets
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) end(quiet, noArchive, volatile, chanDB)

+ + + + + + +
+ End currently playing media +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
quiet + + +Boolean + + + + + + false + + Enable to prevent ending the media client-side
noArchive + + +Boolean + + + + + + false + + Enable to prevent ended media from being written to channel archive. Deletes media if Volatile is false
volatile + + +Boolean + + + + + + false + + Enable to prevent DB Transactions
chanDB + + +Mongoose.Document + + + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) endLivestream(wasPlaying, chanDB)

+ + + + + + +
+ Ends running Livestream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

fromMedia(media, startTime, startTimeStamp) → {queuedMedia}

+ + + + + + +
+ Creates a queuedMedia object from a media object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
media + + +media + + + + Media object to queue
startTime + + +Number + + + + Start time formatted as a JS Epoch
startTimeStamp + + +Number + + + + Start time stamp in seconds
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ queuedMedia object created from given media object +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

fromMediaArray(mediaList, start)

+ + + + + + +
+ Converts array of media objects into array of queuedMedia objects +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaList + + +Array + + + + Array of media objects to queue
start + + +Number + + + + Start time formatted as JS Epoch
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Array of converted queued media objects +
+ + + + + + + + + + + + + + + +

genUUID()

+ + + + + + +
+ Generates new unique identifier for queued media +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) getActiveChan(socket) → {Object}

+ + + + + + +
+ Gets active channel from a given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Object containing users active channel name and channel document object +
+ + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + + + + + + + + + +

(async) getChannelPlaylists(socket, chanDB)

+ + + + + + +
+ Sends channel playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getConnectedChannels(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getConnections(user, cb)

+ + + + + + +
+ Iterates through connections by a given username, and runs them through a given callback function/method +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to crawl connections against
cb + + +function + + + + Callback function to run active connections of a given user against
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

getEndTime(fullTime)

+ + + + + + +
+ return the end time of a given queuedMedia object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
fullTime + + +boolean + + + + + + false + + Overrides early ends
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ end time of given queuedMedia object +
+ + + + + + + + + + + + + + + +

getItemAtEpoch(epoch) → {queuedMedia}

+ + + + + + +
+ Gets a media item by epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found media item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemByUUID(uuid) → {queuedMedia}

+ + + + + + +
+ Get Scheduled Item by UUID +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ found item +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getItemsBetweenEpochs(start, end, noUnfinished) → {queuedMedia}

+ + + + + + +
+ Returns scheduled media between two given datetimes +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (Millis)
end + + +Number + + + + + + End date by JS Epoch (Millis)
noUnfinished + + +Boolean + + + + + + false + + Enable to include currently playing media
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Found Media Objects +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getLastItem(epoch)

+ + + + + + +
+ Gets last item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Last played item +
+ + + + + + + + + + + + + + + +

getNextItem(epoch) → {queuedMedia}

+ + + + + + +
+ Gets next item from a given epoch +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
epoch + + +Number + + + + Date to check by JS Epoch (Millis), defaults to now
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Next item on the schedule +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

getSocketInfo(socket)

+ + + + + + +
+ Pulls user information by socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns related user info +
+ + + + + + + + + + + + + + + +

getStart(start)

+ + + + + + +
+ Validates start times, and replaces bad ones with 5ms in the future +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
start + + +Number + + + + Start time to validate by JS Epoch (millis)
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Start time as JS Epoch (millis) +
+ + + + + + + + + + + + + + + +

(async) getUserPlaylists(socket, userDB)

+ + + + + + +
+ Sends user playlist data to a requesting socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
userDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) goLive(socket, data)

+ + + + + + +
+ Handle client request to start an HLS live stream +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleChat(socket, data)

+ + + + + + +
+ Handles incoming chat messages from client connections +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections to the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(socket)

+ + + + + + +
+ Handles global server-side initialization for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleConnection(userDB, chanDB, socket)

+ + + + + + +
+ Handles server-side initialization for new connections from a specific user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket)

+ + + + + + +
+ Handles server-side initialization for disconnecting from the channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

handleDisconnect(socket, reason)

+ + + + + + +
+ Global server-side logic for handling disconncted sockets +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket to check
reason + + +String + + + + Reason for disconnection
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) handleRawRefresh(mediaObj) → {queuedMedia}

+ + + + + + +
+ Refreshes expired raw links before media plays +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ passes through Media object with updated link upon success +
+ + + +
+
+ Type +
+
+ +queuedMedia + + +
+
+ + + + + + + + + + + + + +

kickConnections(user, reason)

+ + + + + + +
+ Kicks a user from all channels by username +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
user + + +String + + + + Username to kick from the server
reason + + +String + + + + Reason for kick
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamOverwriteSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Overwrites livestream over scheduled media content after it has ended +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) livestreamPushbackSchedule(wasPlaying, chanDB)

+ + + + + + +
+ Pushes back any missed content scheduled during Livestream after Livestream has ended. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
wasPlaying + + +queuedMedia + + + + Media object that was playing while we started the Livestream
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterates through links in message and marks them by link type for later use by client-side post-processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) moveMedia(socket, data)

+ + + + + + +
+ Processes request to move queued media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) preSwitch(mediaObj)

+ + + + + + +
+ Called 10 seconds before media begins to play +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
mediaObj + + +queuedMedia + + + + Media object that's about to play
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepMessage(commandObj)

+ + + + + + +
+ Re-creates message string from processed Command Array +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) prepQueue(chanDB)

+ + + + + + +
+ Prepares channel queue for network transmission +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ de-hydrated scehdule information +
+ + + + + + + + + + + + + + + +

(async) preprocess(socket, data)

+ + + + + + +
+ Ingests a command/chat request from Chat Handler and pre-processes and processes it accordingly +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) processServerCommand(commandObj)

+ + + + + + +
+ Uses the server's Command Processor object to process the chat/command request. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues an entire channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

queueFromChannelPlaylistValidator(socket, data) → {Number}

+ + + + + + +
+ Validates client requests to queue media from a playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns validated start time on success +
+ + + +
+
+ Type +
+
+ +Number + + +
+
+ + + + + + + + + + + + + +

(async) queueFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Queues random media from a given channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueRandomFromUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues random media from a given user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueURL(socket, data)

+ + + + + + +
+ Accepts new URL's to queue from the client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the URL from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) queueUserPlaylist(socket, data, userDB, chanDB)

+ + + + + + +
+ Queues an entire user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) refreshCommands()

+ + + + + + +
+ Reloads toke commands from DB into RAM-based toke command store +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

refreshNextTimer(volatile)

+ + + + + + +
+ Calculates next item to play, and sets timer to play it at it's scheduled start +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
volatile + + +Boolean + + + + + + false + + Disables DB Transactions if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rehydrateQueue(chanDB)

+ + + + + + +
+ Rehydrates media schedule from DB +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Pass through Channel Document to save on DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChannelAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to a given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChat(user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + + + Channel to broadcast message within
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayChatObject(chan, chat)

+ + + + + + +
+ Relays an existing chat object to a channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chan + + +String + + + + Channel to broadcast message within
chat + + +chat + + + + Chat Object representing the message to broadcast to the given channel
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChat(user, flair, highLevel, msg, type, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
user + + +String + + + + + + Originating user
flair + + +String + + + + + + Flair ID to mark chat with
highLevel + + +Number + + + + + + High Level to mark chat with
msg + + +String + + + + + + Message Text Content
type + + +String + + + + + + chat + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalChatObject(chat)

+ + + + + + +
+ Relays an existing chat object to the entire server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chat + + +chat + + + + Chat Object representing the message to broadcast throughout the server
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayGlobalTokeWhisper(msg, links)

+ + + + + + +
+ Broadcasts toke whisper to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChat(socket, user, flair, highLevel, msg, type, chan, links)

+ + + + + + +
+ Creates a new chatObject and relays the resulting message to the given socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending a message to (sounds menacing, huh?)
user + + +String + + + + Originating user
flair + + +String + + + + Flair ID to mark chat with
highLevel + + +Number + + + + High Level to mark chat with
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
chan + + +String + + + + Channel to broadcast message within
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayPrivateChatObject(socket, data)

+ + + + + + +
+ Handles incoming client request to delete a personal emote +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayServerAnnouncement(msg, links)

+ + + + + + +
+ Broadcasts announcement to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeCallout(msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayTokeWhisper(socket, msg, links)

+ + + + + + +
+ Broadcasts toke callout to the server +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're sending the whisper to
msg + + +String + + + + Message Text Content
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

relayUserChat(socket, msg, type, links)

+ + + + + + +
+ Relays a chat message from a user to the rest of the channel based on socket +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
msg + + +String + + + + Message Text Content
type + + +String + + + + Message Type, used for client-side chat post-processing.
links + + +Array + + + + Array of URLs/Links to hand to the client-side chat post-processor to inject into the final message.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) removeMedia(uuid, socket, chanDB, noScheduling) → {Media}

+ + + + + + +
+ Removes a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
uuid + + +String + + + + + + UUID of item to reschedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
noScheduling + + +Boolean + + + + + + false + + Disables schedule timer refresh if true
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ Deleted Media Item +
+ + + +
+
+ Type +
+
+ +Media + + +
+
+ + + + + + + + + + + + + +

(async) removeRange(start, end, socket, noUnfinished)

+ + + + + + +
+ Removes range of media items from the queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
start + + +Number + + + + + + Start date by JS Epoch (millis)
end + + +Number + + + + + + End date by JS Epoch (millis)
socket + + +Socket + + + + + + Requesting Socket
noUnfinished + + +Boolean + + + + + + false + + Set to true to include items that may be currently playing
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) renameChannelPlaylist(socket, data, chanDB)

+ + + + + + +
+ Renames a channel playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
chanDB + + +Mongoose.Document + + + + Channel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

renameChannelPlaylistValidator(socket, data) → {String}

+ + + + + + +
+ Validates client requests to rename the playlist validator +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Newly connected socket to define listeners against
data + + +Object + + + + Data handed over from the client
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns escaped/trimmed name upon success +
+ + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + + + + + + + + + +

(async) renameUserPlaylist(socket, data, userDB)

+ + + + + + +
+ Renames a user playlist +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
data + + +Object + + + + Data handed over from the client
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) rescheduleMedia(uuid, start, socket, chanDB)

+ + + + + + +
+ Reschedules a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
uuid + + +String + + + + UUID of item to reschedule
start + + +Number + + + + New start time by JS Epoch (Millis)
socket + + +Socket + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

resetToke()

+ + + + + + +
+ Resets toke cooldowns early upon authorized request +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sanatizeCommand(commandObj) → {Boolean}

+ + + + + + +
+ Sanatizes and Validates a single user chat message/command +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ false if Command/Message is too long to send +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

(async) scheduleMedia(media, socket, chanDB, force, volatile, startVolatile, saveLate, noSave)

+ + + + + + +
+ Schedules a Media Item + +This is a fun method and I think it deserves it's own little explination... +Since we're working with a time based schedule, using start epochs as keys for our iterable seemed the best option +I don't want to store everything in a sparse array because that *feels* icky, and would probably be a pain in the ass. +Maps seem like a good choice, if it wheren't for the issue of keeping them ordered... + +That's where this comes in. You see if we temporarily store it in a sparse array and convert into a map, +we can quickly and easily create a properly sorted schedule map that, out side of adding items, behaves normally. + +Also a note on preformance: +While .forEach ONLY runs through populated items in sparse arrays, many JS implementations run through them in the background, +simply skipping them before executing the provided function. Looping through object.keys(arr), however, avoids this entirely, +since it ONLY loops through defiened items within the array. No skipped empties for your runtime to worry about. +Even more preformance benefits can be had by using a real for loop on the arrays keys, skipping the overhead of forEach entirely. +This might seem gross but it completely avoids the computational workload of a sorting algo, especially when you consider +that, no matter what, re-ordering the schedule map would've required us to iterate through and rebuild the map anyways... + + +Also it looks like due to implementation limitations, epochs stored as MS are too large for array elements, so we store them there as seconds. +This also means that our current implementation will break exactly on unix epoch 4294967295 (Feb 7, 2106 6:28:15 AM UTC) +Hopefully javascript arrays will allow for larger lengths by then. If not blame the W3C :P + +If for some reason they haven't and we're not dead, we could probably implement an object that wraps a 2d array and set/gets it using modulo/devision/multiplication + +Further Reading: +https://stackoverflow.com/questions/59480871/foreach-vs-object-keys-foreach-performance-on-sparse-arrays +https://community.appsmith.com/content/blog/dark-side-foreach-why-you-should-think-twice-using-it +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
media + + +Media + + + + + + Media item to schedule
socket + + +Socket + + + + + + Requesting Socket
chanDB + + +Mongoose.Document + + + + + + Channnel Document Passthrough to save on DB Access
force + + +Boolean + + + + + + false + + Ignore certain conditions that would prevent scehduling and play the bitch anyways, used for internal function calls
volatile + + +Boolean + + + + + + false + + Prevent DB Writes, used for internal function calls
startVolatile + + +Boolean + + + + + + false + + Runs refreshNextTimer calls without DB writes, used for internal function calls
saveLate + + +Boolean + + + + + + false + + Saves items even if they're about to, or have already started. Used for internal function calls
noSave + + +Boolean + + + + + + false + + Allows function to edit Channel Document, but not save. Used for internal function calls in which the channel document is passed through, but will be saved immediatly after the scheduleMedia() call.
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendChanEmotes(chanDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendChat(commandObj)

+ + + + + + +
+ Relays chat to channel via parent Chat Handler object +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendClientMetadata(userDB, chanDB)

+ + + + + + +
+ Sends glut of required initial metadata to the client upon a new connection +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
chanDB + + +Mongoose.Document + + + + Channnel Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sendMedia(socket)

+ + + + + + +
+ Send media update to a specific socket or broadcast it to the entire channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendPersonalEmotes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendSiteEmotes()

+ + + + + + +
+ Send copy of site emotes to the user +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) sendUsedTokes(userDB)

+ + + + + + +
+ Send copy of channel emotes to the user +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
userDB + + +Mongoose.Document + + + + User Document Passthrough to save on DB Access
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setFlair(socket, data)

+ + + + + + +
+ Handles incoming client request to change flair +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) setHighLevel(socket, data)

+ + + + + + +
+ Handles incoming client request to change high level +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we're receiving the request from
data + + +Object + + + + Event payload
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

socketCrawl(cb)

+ + + + + + +
+ Iterates through all known connections for a given user, running them through a supplied callback function +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
cb + + +function + + + + Callback to call against found sockets for a given user
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

splitCommand(commandObj)

+ + + + + + +
+ Splits raw chat/command data into seperate arrays, one by word-borders and words surrounded by word-borders +These arrays are used to handle further command/chat processing +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) start(mediaObj, timestamp, volatile)

+ + + + + + +
+ Kicks off a media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
mediaObj + + +queuedMedia + + + + + + Media object that's about to play
timestamp + + +Number + + + + + + Media start timestamp in seconds
volatile + + +Boolean + + + + + + false + + Disables DB Transactions
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

stop(socket)

+ + + + + + +
+ Stops currently playing media item +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ returns false if there is nothing to stop +
+ + + + + + + + + + + + + + + +

(async) stopMedia(socket)

+ + + + + + +
+ Processes requests to stop currently playing media from client +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Socket we received the request from
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) stopScheduleTimers(noArchive)

+ + + + + + +
+ Clears and scheduling timers +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDefaultDescription
noArchive + + +Boolean + + + + + + true + + Disables Archiving
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

sync()

+ + + + + + +
+ Sends a syncronization ping out to client Sockets and increments the tracked timestamp by the Synchronization Delta +Called auto-magically by the Synchronization Timer +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) toggleLock(socket)

+ + + + + + +
+ Handle client request to (un)lock queue +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

tokeProcessor(commandObj) → {Boolean}

+ + + + + + +
+ Processes toke commands from Command Pre-Processor +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
commandObj + + +Object + + + + Object representing a single given command/chat request, passed down from the Command Pre-Processor
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ True if the toke is an invalid toke command (tells Command Pre-Processor to send command as chat) +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +

updateFlair(flair)

+ + + + + + +
+ Set flair for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
flair + + +String + + + + Flair string to update user's flair to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

updateHighLevel(highLevel)

+ + + + + + +
+ Set high level for a given user and broadcast update to clients +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
highLevel + + +Number + + + + Number to update user's high-level to
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) validateSocket(socket) → {Boolean}

+ + + + + + +
+ Global server-side validation logic for new connections to any channel +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
socket + + +Socket + + + + Requesting Socket
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ true on success +
+ + + +
+
+ Type +
+
+ +Boolean + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/www/doc/schemas_channel_channelBanSchema.js.html b/www/doc/schemas_channel_channelBanSchema.js.html new file mode 100644 index 0000000..4aaa763 --- /dev/null +++ b/www/doc/schemas_channel_channelBanSchema.js.html @@ -0,0 +1,110 @@ + + + + + JSDoc: Source: schemas/channel/channelBanSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/channelBanSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+/**
+ * DB Schema for Documents representing a user ban from a single channel
+ */
+const channelBanSchema = new mongoose.Schema({
+    user: {
+        type: mongoose.SchemaTypes.ObjectID,
+        required: true,
+        ref: "user"
+    },
+    banDate: {
+        type: mongoose.SchemaTypes.Date,
+        required: true,
+        default: new Date()
+    },
+    expirationDays: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+        default: 14
+    },
+    banAlts: {
+        type: mongoose.SchemaTypes.Boolean,
+        required: true,
+        default: false
+    }
+});
+
+//methods
+/**
+ * Calculates days until ban expiration
+ * @returns {Number} Days until the given ban expires
+ */
+channelBanSchema.methods.getDaysUntilExpiration = function(){
+        //Get ban date
+        const expirationDate = new Date(this.banDate);
+        //Get expiration days and calculate expiration date
+        expirationDate.setDate(expirationDate.getDate() + this.expirationDays);
+        //Calculate and return days until ban expiration
+        return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1);
+}
+
+module.exports = channelBanSchema;
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_channel_channelPermissionSchema.js.html b/www/doc/schemas_channel_channelPermissionSchema.js.html new file mode 100644 index 0000000..234d334 --- /dev/null +++ b/www/doc/schemas_channel_channelPermissionSchema.js.html @@ -0,0 +1,178 @@ + + + + + JSDoc: Source: schemas/channel/channelPermissionSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/channelPermissionSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+/**
+ * Rank Enum, lists all known permission ranks from lowest to highest.
+ * 
+ * This originally belonged to the permissionSchema, but this avoids circular dependencies.
+ */
+const rankEnum = ["anon", "user", "gold", "bot", "mod", "admin"];
+
+//Since this is intended to be used as a child schema for multiple parent schemas, we won't export it as a model
+/**
+ * DB Schema for Sub-Document representing permission structure for a single channel
+ */
+const channelPermissionSchema = new mongoose.Schema({
+    manageChannel: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    changeRank: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    changePerms: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    changeSettings: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    kickUser: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    banUser: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    announce: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    clearChat: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    editTokeCommands: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    editEmotes: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    scheduleMedia: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    clearSchedule:{
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    scheduleAdmin:{
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    editChannelPlaylists:{
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    deleteChannel: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    }
+});
+
+//Only putting the rank enum out, all other logic should be handled by channelSchema methods to avoid circular dependencies
+//Alternatively if things get to big we can make it it's own util.
+channelPermissionSchema.statics.rankEnum = rankEnum;
+
+module.exports = channelPermissionSchema;
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_channel_channelSchema.js.html b/www/doc/schemas_channel_channelSchema.js.html new file mode 100644 index 0000000..32ef99f --- /dev/null +++ b/www/doc/schemas_channel_channelSchema.js.html @@ -0,0 +1,943 @@ + + + + + JSDoc: Source: schemas/channel/channelSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/channelSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+const {validationResult, matchedData} = require('express-validator');
+
+//Local Imports
+//Server
+const server = require('../../server');
+//DB Models
+const statModel = require('../statSchema');
+const {userModel} = require('../user/userSchema');
+const permissionModel = require('../permissionSchema');
+const emoteModel = require('../emoteSchema');
+//DB Schemas
+const channelPermissionSchema = require('./channelPermissionSchema');
+const channelBanSchema = require('./channelBanSchema');
+const queuedMediaSchema = require('./media/queuedMediaSchema');
+const playlistSchema = require('./media/playlistSchema');
+const chatSchema = require('./chatSchema');
+//Utils
+const { exceptionHandler, errorHandler } = require('../../utils/loggerUtils');
+
+/**
+ * DB Schema for Documents containing de-hydrated representations of Canopy Stream/Chat Channels
+ */
+const channelSchema = new mongoose.Schema({
+    id: {
+        type: mongoose.SchemaTypes.Number,
+        required: true
+    },
+    name: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        //Calculate max length by the validator max length and the size of an escaped character
+        maxLength: 50 * 6,
+        default: 0
+    },
+    description: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        //Calculate max length by the validator max length and the size of an escaped character
+        maxLength: 1000 * 6,
+        default: 0
+    },
+    thumbnail: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        default: "/img/johnny.png"
+    },
+    settings: {
+        hidden: {
+            type: mongoose.SchemaTypes.Boolean,
+            required: true,
+            default: true
+        },
+        streamURL: {
+            type: mongoose.SchemaTypes.String,
+            default: ''
+        }
+    },
+    permissions: {
+        type: channelPermissionSchema,
+        default: () => ({})
+    },
+    rankList: [{
+        user: {
+            type: mongoose.SchemaTypes.ObjectID,
+            required: true,
+            ref: "user"
+        },
+        rank: {
+            type: mongoose.SchemaTypes.String,
+            required: true,
+            enum: permissionModel.rankEnum
+        }
+    }],
+    tokeCommands: [{
+            type: mongoose.SchemaTypes.String,
+            required: true
+    }],
+    //Not re-using the site-wide schema because post/pre save should call different functions
+    emotes: [{
+        name:{
+            type: mongoose.SchemaTypes.String,
+            required: true
+        },
+        link:{
+            type: mongoose.SchemaTypes.String,
+            required: true
+        },
+        type:{
+            type: mongoose.SchemaTypes.String,
+            required: true,
+            enum: emoteModel.typeEnum,
+            default: emoteModel.typeEnum[0]
+        }
+    }],
+    media: {
+        nowPlaying: queuedMediaSchema,
+        scheduled: [queuedMediaSchema],
+        //We should consider moving archived media and channel playlists to their own collections/models for preformances sake
+        archived: [queuedMediaSchema],
+        playlists: [playlistSchema],
+        liveRemainder: {
+            type: mongoose.SchemaTypes.UUID,
+            required: false
+        }
+    },
+    //Thankfully we don't have to keep track of alts, ips, or deleted users so this should be a lot easier than site-wide bans :P
+    banList: [channelBanSchema],
+    chatBuffer: [chatSchema]
+});
+
+
+/**
+ * Channel pre-save function. Ensures name requirements (for some reason, we should move that to the schema probably), kicks users after rank change, and handles housekeeping after adding tokes/emotes 
+ */
+channelSchema.pre('save', async function (next){
+    if(this.isModified("name")){
+        if(this.name.match(/^[a-z0-9_\-.]+$/i) == null){
+            throw loggerUtils.exceptionSmith("Username must only contain alpha-numerics and the following symbols: '-_.'", "validation");
+        }
+    }
+
+    //This entire block is just about finding users after rank-change and making sure they get kicked
+    //Getting the affected user would be a million times easier elsewhere
+    //But this ensures it happens every time channel rank gets changed no matter what
+    if(this.isModified('rankList') && this.rankList != null){
+        //Get the rank list before it was modified (gross but works, find a better way if you dont like it :P)
+        var chanDB = await module.exports.findOne({_id: this._id});
+        //Create empty variable for the found rank object
+        var foundRank = null;
+        if(chanDB != null){
+            //If we're removing one
+            if(chanDB.rankList.length > this.rankList.length){
+                //Child/Parent is *WAY* tooo atomic family for my tastes :P
+                var top = chanDB;
+                var bottom = this;
+            }else{
+                //otherwise reverse the loops
+                var top = this;
+                var bottom = chanDB;
+            }
+
+            //Populate the top doc
+            await top.populate('rankList.user');
+
+
+            //For each rank in the dommy-top copy of the rank list
+            top.rankList.forEach((topObj) => {
+                //Create empty variable for the matched rank
+                var matchedRank = null;
+                //For each rank in the subby-bottom copy of the rank list
+                bottom.rankList.forEach((bottomObj) => {
+                    //So long as both users exist (we're not working with deleted users)
+                    if(topObj.user != null && bottomObj.user != null){
+                        //If it's the same user
+                        if(topObj.user._id.toString() == bottomObj.user._id.toString()){
+                            //matched rank found
+                            matchedRank = bottomObj;
+                        }
+                    }
+                });
+
+
+                //If matched rank is null or isn't the topObject rank
+                if(matchedRank == null || matchedRank.rank != topObj.rank){
+                    //Set top object to found rank
+                    foundRank = topObj;
+                }
+
+            });
+
+            //get relevant active channel
+            const activeChan = server.channelManager.activeChannels.get(this.name);
+
+            //if the channel is online
+            if(activeChan != null){
+                //make sure we're not trying to kick a deleted user
+                if(foundRank.user != null){
+                    //Get the relevant user connection
+                    const userConn = activeChan.userList.get(foundRank.user.user);
+                    //if the user is online
+                    if(userConn != null){
+                        //kick the user
+                        userConn.disconnect("Your channel rank has changed!");
+                    }
+                }
+            }
+        }
+    }
+
+
+    //if the toke commands where changed
+    if(this.isModified("tokeCommands")){
+        //Get the active Channel object from the application side of the house
+        const activeChannel = server.channelManager.activeChannels.get(this.name);
+
+        //If the channel is active
+        if(activeChannel != null){
+            //Reload the toke command list
+            activeChannel.tokeCommands = this.tokeCommands;
+        }
+    }
+
+    //if emotes where modified
+    if(this.isModified('emotes')){
+        //Get the active Channel object from the application side of the house
+        const activeChannel = server.channelManager.activeChannels.get(this.name);
+
+        //If the channel is active
+        if(activeChannel != null){
+            //Broadcast the emote list
+            activeChannel.broadcastChanEmotes(this);
+        }
+    }
+
+    next();
+});
+
+//statics
+/**
+ * Registers a new channel to the DB
+ * @param {Object} channelObj - Channel Object from Browser to register
+ * @param {Mongoose.Document} ownerObj - DB Docuement representing user
+ */
+channelSchema.statics.register = async function(channelObj, ownerObj){
+    const {name, description, thumbnail} = channelObj;
+
+    const chanDB = await this.findOne({ name });
+
+    if(chanDB){
+        throw loggerUtils.exceptionSmith("Channel name already taken!", "validation");
+    }else{
+        const id = await statModel.incrementChannelCount();
+        const rankList = [{
+            user: ownerObj._id,
+            rank: "admin"
+        }];
+
+        const newChannelObj = {
+            id,
+            name,
+            description,
+            thumbnail,
+            rankList,
+            media: {
+                nowPlaying: null,
+                scheduledMedia: [],
+                archived: []
+            }
+        };
+
+        const newChannel = await this.create(newChannelObj);
+    }
+}
+
+/**
+ * Generates Network-Friendly Browser-Digestable list of channels
+ * @param {Boolean} includeHidden - Whether or not to include hidden channels within the list
+ * @returns {Array} List of Network-Friendly Browser-Digestable Objects representing channels on the server
+ */
+channelSchema.statics.getChannelList = async function(includeHidden = false){
+    const chanDB = await this.find({});
+    var chanGuide = [];
+
+    //crawl through channels
+    chanDB.forEach((channel) => {
+        //For each channel, push an object with only the information we need to the channel guide
+        if(!channel.settings.hidden || includeHidden){
+            chanGuide.push({
+                id: channel.id,
+                name: channel.name,
+                description: channel.description,
+                thumbnail: channel.thumbnail
+            });
+        }
+    });
+    
+    //return the channel guide
+    return chanGuide;
+}
+
+//Middleware for rank checks
+/**
+ * Configurable Express Middleware for Per-Channel Endpoint Authorization
+ * 
+ * Man, it would be really nice if express middleware actually supported async functions, you know, as if it where't still 2015 >:(
+ * Also holy shit, sharing a function between two middleware functions is a nightmare
+ * I'd rather just have this check chanField for '/c/' to handle channels in URL, fuck me this was obnoxious to write
+ * @param {String} - Permission to check against
+ * @param {String} - Name of channel to authorize against
+ * @returns {Function} Express middleware function with arguments injected into logic
+*/
+channelSchema.statics.reqPermCheck = function(perm, chanField = "chanName"){
+    return (req, res, next)=>{
+        try{
+            //Check validation result
+            const validResult = validationResult(req);
+
+            //if our chan field is set to '/c/', telling us to check the URL
+            if(chanField == '/c/'){
+                //Rip the chan name out of the URL
+                var chanName = (req.originalUrl.split('/c/')[1].replace('/settings',''));
+            }else if(validResult.isEmpty()){
+                //otherwise if our input is valid, use that
+                var chanName = matchedData(req)[chanField];
+            }else{
+                //We didn't get /c/ and we got a bad input, time for shit to hit the fan!
+                res.status(400);
+                return res.send({errors: validResult.array()})
+            }
+
+            //Find the related channel document, and handle it using a then() block
+            this.findOne({name: chanName}).then((chanDB) => {
+                //If we didnt find a channel
+                if(chanDB == null){
+                    //FUCK
+                    return errorHandler(res, "You cannot check permissions against a non-existant channel!", 'Unauthorized', 401);
+                }
+
+                //Run a perm check against the current user and permission
+                chanDB.permCheck(req.session.user, perm).then((permitted) => {
+                    if(permitted){
+                        //if we're permitted, go on to fulfill the request
+                        next();
+                    }else{
+                        //If not, prevent the request from going through and tell them why
+                        return errorHandler(res, "You do not have a high enough rank to access this resource.", 'Unauthorized', 401);
+                    }
+                });
+            });
+        }catch(err){
+            return exceptionHandler(res, err);
+        }
+    }
+}
+
+/**
+ * Schedulable Function for Processing and Deleting Expired Channel-level User Bans
+ */
+channelSchema.statics.processExpiredBans = async function(){
+    const chanDB = await this.find({});
+
+    for(let chanIndex in chanDB){
+        //Pull channel from channels by index
+        const channel = chanDB[chanIndex];
+
+        //channel.banList.forEach(async (ban, banIndex) => {
+        for(let banIndex in channel.banList){
+            //Pull ban from channel ban list
+            const ban = channel.banList[banIndex];
+
+            //ignore permanent and non-expired bans
+            if(ban.expirationDays >= 0 && ban.getDaysUntilExpiration() <= 0){
+                //Get the index of the ban
+                channel.banList.splice(banIndex,1);
+                await channel.save();
+            }
+        }
+    }
+}
+
+//methods
+/**
+ * Updates settings map for a given channel document
+ * @param {Map} settingsMap - Map of settings updates to apply against channel document
+ * @returns {Map} Map of all channel settings
+ */
+channelSchema.methods.updateSettings = async function(settingsMap){
+    settingsMap.forEach((value, key) => {
+        if(this.settings[key] == null){
+            throw loggerUtils.exceptionSmith("Invalid channel setting.", "validation");
+        }
+
+        this.settings[key] = value;
+    })
+
+    await this.save();
+    
+    return this.settings;
+}
+
+/**
+ * Crawls through channel rank and runs a callback against the requested user's rank sub-doc
+ * @param {Mongoose.Document} userDB - User DB Document to run the callback against
+ * @param {Function} cb - Callback Function to call against the given users rank sub-doc
+ */
+channelSchema.methods.rankCrawl = async function(userDB,cb){
+    //Crawl through channel rank list
+    //TODO: replace this with rank check function shared with setRank
+    this.rankList.forEach(async (rankObj, rankIndex) => {
+        //check against user ID to speed things up
+        if(rankObj.user != null && rankObj.user._id.toString() == userDB._id.toString()){
+            //If we found a match, call back
+            cb(rankObj, rankIndex);
+        }
+    });
+}
+
+/**
+ * Sets users rank by User Doc
+ * @param {Mongoose.Document} userDB - DB Document of user's channel rank to change
+ * @param {String} rank - Channel rank to set user to
+ * @returns {Array} Channel Rank List
+ */
+channelSchema.methods.setRank = async function(userDB,rank){
+    //Create variable to store found ranks
+    var foundRankIndex = null;
+
+    //Crawl through ranks to find matching index
+    this.rankCrawl(userDB,(rankObj, rankIndex)=>{foundRankIndex = rankIndex});
+
+    //If we found an existing rank object
+    if(foundRankIndex != null){
+        if(rank == "user"){
+            this.rankList.splice(foundRankIndex,1);
+        }else{
+            //otherwise, set the users rank
+            this.rankList[foundRankIndex].rank = rank;
+        }
+    }else if(rank != "user"){
+        //if the user rank object doesn't exist, and we're not setting to user
+        //Create rank object based on input
+        const rankObj = {
+            user: userDB._id,
+            rank: rank
+        }
+
+        //Add it to rank list
+        this.rankList.push(rankObj);
+    }
+
+
+    //Save our channel and return rankList
+    await this.save();
+    return this.rankList;
+}
+
+/**
+ * Generates Network-Friendly Browser-Digestable channel rank list
+ * @returns {Array} Network-Friendly Browser-Digestable channel rank list
+ */
+channelSchema.methods.getRankList = async function(){
+    //Create an empty array to hold the user list
+    const rankList = new Map()
+    //Create temp rank list to replace the current one in the advant we have busted users
+    let tempRankList = [];
+    //Flag that lets us know we gotta save
+    let reqSave = false;
+
+    //Populate the user objects in our ranklist based off of their DB ID's
+    await this.populate('rankList.user');
+
+    //For each rank object in the rank list
+    for(rankObjIndex in this.rankList){
+        const rankObj = this.rankList[rankObjIndex];
+        //If the use still exists
+        if(rankObj.user != null){
+            //Push current rank object to the temp rank list in the advant that it doesn't get saved
+            tempRankList.push(rankObj);
+
+            //Create a new user object from rank object data
+            const userObj = {
+                id: rankObj.user.id,
+                user: rankObj.user.user,
+                img: rankObj.user.img,
+                rank: rankObj.rank
+            }
+
+            //Add our user object to the list
+            rankList.set(rankObj.user.user, userObj);
+        //Otherwise if it's an invalid rank for a deleted user
+        }else{
+            //Ignore the rank object and throw the save flag to save the temporary rank list
+            reqSave = true;
+        }
+    }
+
+    //if we need to save the temp rank list
+    if(reqSave){
+        //set rank list
+        this.rankList = tempRankList;
+        //save
+        await this.save();
+    }
+
+    //return userList
+    return rankList;
+}
+
+/**
+ * Gets channel rank by user document
+ * @param {Mongoose.Document} userDB - DB Document of User to pull Channel Rank of
+ * @returns {String} Channel rank of requested user
+ */
+channelSchema.methods.getChannelRankByUserDoc = async function(userDB = null){
+    var foundRank = null;
+
+    //Check to make sure userDB exists before going forward
+    if(userDB == null){
+        //If so this user is probably not signed in
+        return "anon"
+    }
+
+    //Crawl through ranks to find matching rank
+    this.rankCrawl(userDB,(rankObj)=>{foundRank = rankObj});
+
+    //If we found an existing rank object
+    if(foundRank != null){
+        //return rank
+        return foundRank.rank;
+    }else{
+        //default to "user" for registered users, and "anon" for anonymous
+        if(userDB.rank == "anon"){
+            return "anon";
+        }else{
+            return "user";
+        }
+    }
+}
+
+/**
+ * Gets channel rank by username
+ * @param {String} user - Username of user to pull channel rank of
+ * @returns {String} Channel rank of requested user
+ */
+channelSchema.methods.getChannelRank = async function(user){
+    const userDB = await userModel.findOne({user: user.user});
+    return await this.getChannelRankByUserDoc(userDB);
+}
+
+/**
+ * Calculates a permission check against a specific channel permission for a given user by username
+ * @param {String} user - Username of user to check against
+ * @param {String} perm - Name of channel Permission to check against
+ * @returns {Boolean} Whether or not the given user passes the given channel perm check
+ */
+channelSchema.methods.permCheck = async function (user, perm){
+    //Set userDB to null if we wheren't passed a real user
+    if(user != null){
+        var userDB = await userModel.findOne({user: user.user});
+    }else{
+        var userDB = null;
+    }
+
+    return await this.permCheckByUserDoc(userDB, perm)
+}
+
+/**
+ * Calculates a permission check against a specific channel permission for a given user by DB Document
+ * @param {Mongoose.Document} userDB - DB Document of user to check against
+ * @param {String} perm - Name of channel Permission to check against
+ * @returns {Boolean} Whether or not the given user passes the given channel perm check
+ */
+channelSchema.methods.permCheckByUserDoc = async function(userDB, perm){
+    //Get site-wide rank as number, default to anon for anonymous users
+    const rank = userDB ? permissionModel.rankToNum(userDB.rank) : permissionModel.rankToNum("anon");
+    //Get channel rank as number
+    const chanRank = permissionModel.rankToNum(await this.getChannelRankByUserDoc(userDB));
+    //Get channel permission rank requirement as number
+    const permRank = permissionModel.rankToNum(this.permissions[perm]);
+    //Get site-wide rank requirement to override as number
+    const overrideRank = permissionModel.rankToNum((await permissionModel.getPerms()).channelOverrides[perm]);
+    //Get channel perm check result
+    const permCheck = (chanRank >= permRank);
+    //Get site-wide override perm check result
+    const overrideCheck = (rank >= overrideRank);
+
+    return (permCheck || overrideCheck);
+}
+
+/**
+ * Generates channel-wide permission map for a given user by user doc
+ * @param {Mongoose.Document} userDB - DB Document representing a single user account
+ * @returns {Object} Object containing two maps, one for channel perms, another for site-wide perms
+ */
+channelSchema.methods.getPermMapByUserDoc = async function(userDB){
+        //Grap site-wide permissions
+        const sitePerms = await permissionModel.getPerms();
+        const siteMap = sitePerms.getPermMapByUserDoc(userDB);
+        //Pull chan permissions keys
+        let permTree = channelPermissionSchema.tree;
+        let permMap = new Map();
+
+        //For each object in the temporary permissions object
+        for(let perm of Object.keys(permTree)){
+            //Check the current permission
+            permMap.set(perm, await this.permCheckByUserDoc(userDB, perm));
+        }
+
+        //return perm map
+        return {
+            site: siteMap.site,
+            chan: permMap
+        };
+}
+
+/**
+ * Checks if a specific user has been issued a channel-specific ban by DB doc
+ * @param {Mongoose.Document} userDB - DB Document representing a single user account
+ * @returns {Object} Found ban, if one exists
+ */
+channelSchema.methods.checkBanByUserDoc = async function(userDB){
+    var foundBan = null;
+
+    //this needs to be a for loop for async
+    //this.banList.forEach((ban) => {
+    for(banIndex in this.banList){
+
+        if(this.banList[banIndex].user != null){
+            if(this.banList[banIndex].user.toString() == userDB._id.toString()){
+                foundBan = this.banList[banIndex];
+            }
+            
+            //If this bans alts are banned
+            if(this.banList[banIndex].banAlts){
+                //Populate the user of the current ban being checked
+                await this.populate(`banList.${banIndex}.user`);
+
+                //If this is an alt of the banned user
+                if(await this.banList[banIndex].user.altCheck(userDB)){
+                    foundBan = this.banList[banIndex];
+                }
+            }
+        }
+    }
+
+    return foundBan;
+}
+
+/**
+ * Generates Network-Friendly Browser-Digestable list of channel emotes
+ * @returns {Array} Network-Friendly Browser-Digestable list of channel emotes
+ */
+channelSchema.methods.getEmotes = function(){
+    //Create an empty array to hold our emote list
+    const emoteList = [];
+
+    //For each channel emote
+    this.emotes.forEach((emote) => { 
+        //Push an object with select information from the emote to the emote list
+        emoteList.push({
+            name: emote.name,
+            link: emote.link,
+            type: emote.type
+        });
+    });
+
+    //return the emote list
+    return emoteList;
+}
+
+/**
+ * Generates Network-Friendly Browser-Digestable list of channel playlists
+ * @returns {Array} Network-Friendly Browser-Digestable list of channel playlists
+ */
+channelSchema.methods.getPlaylists = function(){
+    //Create an empty array to hold our emote list
+    const playlists = [];
+
+    //For each channel emote
+    for(let playlist of this.media.playlists){
+        //Push an object with select information from the emote to the emote list
+        playlists.push(playlist.dehydrate());
+    }
+
+    //return the emote list
+    return playlists;
+}
+
+/**
+ * Crawls through channel playlists, running a given callback function against each one
+ * @param {Function} cb - Callback function to run against channel playlists
+ */
+channelSchema.methods.playlistCrawl = function(cb){
+    for(let listIndex in this.media.playlists){
+        //Grab the associated playlist
+        playlist = this.media.playlists[listIndex];
+
+        //Call the callback with the playlist and list index as arguments
+        cb(playlist, listIndex);
+    }
+}
+
+/**
+ * Finds channel playlist by playlist name
+ * @param {String} name - name of given playlist to find
+ * @returns {Mongoose.Document} - Sub-Document representing a single playlist
+ */
+channelSchema.methods.getPlaylistByName = function(name){
+    //Create null value to hold our found playlist
+    let foundPlaylist = null;
+
+    //Crawl through active playlists
+    this.playlistCrawl((playlist, listIndex) => {
+        //If we found a match based on name
+        if(playlist.name == name){
+            //Keep it
+            foundPlaylist = playlist;
+            //Pass down the list index
+            foundPlaylist.listIndex = listIndex;
+        }
+    });
+
+    //return the given playlist
+    return foundPlaylist;
+}
+
+/**
+ * Deletes channel playlist by playlist name
+ * @param {String} name - name of given playlist to Delete
+ */
+channelSchema.methods.deletePlaylistByName = async function(name){
+    //Find the playlist
+    let playlist = this.getPlaylistByName(name);
+
+    //splice out the given playlist
+    this.media.playlists.splice(playlist.listIndex, 1);
+
+    //save the channel document
+    await this.save();
+}
+
+/**
+ * Generates Network-Friendly Browser-Digestable list of Channel-Wide user bans
+ * @returns {Array} Network-Friendly Browser-Digestable list of Channel-Wide user bans
+ */
+channelSchema.methods.getChanBans = async function(){
+    //Create an empty list to hold our found bans
+    var banList = [];
+    //Populate the users in the banList
+    await this.populate('banList.user');
+
+    //Crawl through known bans
+    this.banList.forEach((ban) => {
+        
+        var banObj = {
+            banDate: ban.banDate,
+            expirationDays: ban.expirationDays,
+            banAlts: ban.banAlts,
+        }
+
+        //Check if the ban was permanent (expiration set before ban date)
+        if(ban.expirationDays > 0){
+            //if not calculate expiration date
+            var expirationDate = new Date(ban.banDate);
+            expirationDate.setDate(expirationDate.getDate() + ban.expirationDays);
+
+            //Set calculated expiration date
+            banObj.expirationDate = expirationDate;
+            banObj.daysUntilExpiration = ban.getDaysUntilExpiration();
+        }
+
+        //Setup user object (Do this last to keep it at bottom for human-readibility of json :P)
+        banObj.user = {
+            id: ban.user.id,
+            user: ban.user.user,
+            img: ban.user.img,
+            date: ban.user.date
+        }
+
+        banList.push(banObj);
+    });
+
+    return banList;
+}
+
+/**
+ * Issues channel-wide ban to user based on user DB document
+ * @param {Mongoose.Document} userDB - DB Document representing a single user account to ban
+ * @param {Number} expirationDays - Days until ban expiration
+ * @param {Boolean} banAlts - Whether or not to ban alts
+ */
+channelSchema.methods.banByUserDoc = async function(userDB, expirationDays, banAlts){
+    //Throw a shitfit if the user doesn't exist
+    if(userDB == null){
+        throw loggerUtils.exceptionSmith("Cannot ban non-existant user!", "validation");
+    }
+
+    const foundBan = await this.checkBanByUserDoc(userDB);
+
+    if(foundBan != null){
+        throw loggerUtils.exceptionSmith("User already banned!", "validation");
+    }
+
+    //Create a new ban document based on input
+    const banDoc = {
+        user: userDB._id,
+        expirationDays,
+        banAlts
+    }
+
+    const activeChan = server.channelManager.activeChannels.get(this.name);
+    if(activeChan != null){
+        const userConn = activeChan.userList.get(userDB.user);
+        if(userConn != null){
+            if(expirationDays < 0){
+                userConn.disconnect("You have been permanently banned from this channel!");
+            }else{
+                userConn.disconnect(`You have been banned from this channel for ${expirationDays} day(s)!`);
+            }
+        }
+    }
+
+    //Push the ban to the list
+    this.banList.push(banDoc);
+
+    await this.save();
+}
+
+/**
+ * Syntatic sugar for banning users by username
+ * @param {String} user - Username of user to ban
+ * @param {Number} expirationDays - Days until ban expiration
+ * @param {Boolean} banAlts - Whether or not to ban alts
+ * @returns {Promise} promise from this.banByUserDoc
+ */
+channelSchema.methods.ban = async function(user, expirationDays, banAlts){
+    const userDB = await userModel.find({user});
+    return await this.banByUserDoc(userDB, expirationDays, banAlts);
+}
+
+/**
+ * Un-Bans user by DB Document
+ * @param {Mongoose.Document} userDB - DB Document representing a single user account to un-ban
+ * @returns {Mongoose.Document} Saved channel document
+ */
+channelSchema.methods.unbanByUserDoc = async function(userDB){
+    //Throw a shitfit if the user doesn't exist
+    if(userDB == null){
+        throw loggerUtils.exceptionSmith("Cannot ban non-existant user!", "validation");
+    }
+
+    const foundBan = await this.checkBanByUserDoc(userDB);
+
+    if(foundBan == null){
+        throw loggerUtils.exceptionSmith("User already unbanned!", "validation");
+    }
+
+    //You know I can't help but feel like an asshole for looking for the index of something I just pulled out of an array using forEach...
+    //Then again this is such an un-used function that the issue of code re-use overshadows performance 
+    //I mean how often are we REALLY going to be un-banning users from channels?
+    const banIndex = this.banList.indexOf(foundBan);
+    this.banList.splice(banIndex,1);
+    return await this.save();
+}
+
+/**
+ * Syntatic sugar for un-banning by username
+ * @param {String} user - Username of user to un-ban
+ * @returns {Mongoose.Document} Saved channel document
+ */
+channelSchema.methods.unban = async function(user){
+    const userDB = await userModel.find({user});
+    return await this.unbanByUserDoc(userDB);
+}
+
+/**
+ * Nukes channel upon channel-admin request
+ * @param {String} confirm - Channel name to confirm deletion of channel
+ */
+channelSchema.methods.nuke = async function(confirm){
+    if(confirm == "" || confirm == null){
+        throw loggerUtils.exceptionSmith("Empty Confirmation String!", "validation");
+    }else if(confirm != this.name){
+        throw loggerUtils.exceptionSmith("Bad Confirmation String!", "validation");
+    }
+
+    //Annoyingly there isnt a good way to do this from 'this'
+    var oldChan = await this.deleteOne();
+
+    if(oldChan.deletedCount == 0){
+        throw loggerUtils.exceptionSmith("Server Error: Unable to delete channel! Please report this error to your server administrator, and with timestamp.", "internal");
+    }
+}
+
+module.exports = mongoose.model("channel", channelSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_channel_chatSchema.js.html b/www/doc/schemas_channel_chatSchema.js.html new file mode 100644 index 0000000..218f637 --- /dev/null +++ b/www/doc/schemas_channel_chatSchema.js.html @@ -0,0 +1,105 @@ + + + + + JSDoc: Source: schemas/channel/chatSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/chatSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+const linkSchema = new mongoose.Schema({
+    link: mongoose.SchemaTypes.String,
+    type: mongoose.SchemaTypes.String
+});
+
+/**
+ * DB Schema for documents representing a single chat message
+ */
+const chatSchema = new mongoose.Schema({
+    user: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    flair: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },   
+    highLevel: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+    },
+    msg: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    type: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    links: {
+        type: [linkSchema],
+        required: true,
+    },
+});
+
+module.exports = chatSchema;
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_channel_media_mediaSchema.js.html b/www/doc/schemas_channel_media_mediaSchema.js.html new file mode 100644 index 0000000..8f31ede --- /dev/null +++ b/www/doc/schemas_channel_media_mediaSchema.js.html @@ -0,0 +1,105 @@ + + + + + JSDoc: Source: schemas/channel/media/mediaSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/media/mediaSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+/**
+ * DB Schema representing a single piece of media
+ */
+const mediaSchema = new mongoose.Schema({
+    title: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    fileName: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },   
+    url: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    id: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    type: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    duration: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+    },
+},
+{
+    discriminatorKey: 'status'
+}
+);
+
+
+module.exports = mediaSchema;
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_channel_media_playlistMediaSchema.js.html b/www/doc/schemas_channel_media_playlistMediaSchema.js.html new file mode 100644 index 0000000..9d43cd0 --- /dev/null +++ b/www/doc/schemas_channel_media_playlistMediaSchema.js.html @@ -0,0 +1,133 @@ + + + + + JSDoc: Source: schemas/channel/media/playlistMediaSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/media/playlistMediaSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const mediaSchema = require('./mediaSchema');
+const media = require('../../../app/channel/media/media');
+
+/**
+ * DB Schema for documents represnting a piece of media held in a playlist
+ */
+const playlistMediaProperties = new mongoose.Schema({
+    uuid: {
+        type: mongoose.SchemaTypes.UUID,
+        required:true,
+        default: crypto.randomUUID()
+    }
+},
+{
+    discriminatorKey: 'status'
+});
+
+//Schema Middleware
+/**
+ * Pre-save function for playlist meda, ensures unique UUID
+ */
+playlistMediaProperties.pre('save', async function (next){
+    //If the UUID was modified in anyway
+    if(this.isModified("uuid")){
+        //Throw that shit out and make a new one since it's probably either null or a leftover from some channel queue
+        this.uuid = crypto.randomUUID();
+    }
+
+    //Keep it moving
+    next();
+});
+
+//methods
+/**
+ * Rehydrate to a full phat media object
+ * @returns {media} A full phat media object, re-hydrated from the DB
+ */
+playlistMediaProperties.methods.rehydrate = function(){
+    //Return item as a full phat, standard media object
+    return new media(
+        this.title,
+        this.fileName,
+        this.url,
+        this.id,
+        this.type,
+        this.duration
+    );
+}
+
+/**
+ * Dehydrate to minified flat network-friendly object
+ * @returns {Object} Network-Friendly Browser-Digestable object representing media from a playlist
+ */
+playlistMediaProperties.methods.dehydrate = function(){
+    return {
+        title: this.title,
+        url: this.url,
+        duration: this.duration,
+        uuid: this.uuid.toString()
+    };
+}
+
+module.exports = mediaSchema.discriminator('saved', playlistMediaProperties);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_channel_media_playlistSchema.js.html b/www/doc/schemas_channel_media_playlistSchema.js.html new file mode 100644 index 0000000..1db3493 --- /dev/null +++ b/www/doc/schemas_channel_media_playlistSchema.js.html @@ -0,0 +1,183 @@ + + + + + JSDoc: Source: schemas/channel/media/playlistSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/media/playlistSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const playlistMediaSchema = require('./playlistMediaSchema');
+
+/**
+ * DB Schema for Documents representing playlists full of media
+ */
+const playlistSchema = new mongoose.Schema({
+    name: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+    },
+    media: [playlistMediaSchema],
+    defaultTitles:[{
+        type: mongoose.SchemaTypes.String,
+        required: false,
+        default: []
+    }]
+});
+
+//methods
+/**
+ * Dehydrate to minified flat network-friendly object
+ * @returns {Object} Network-Friendly Browser-Digestable object representing media from a playlist
+ */
+playlistSchema.methods.dehydrate = function(){
+    //Create empty array to hold media
+    const mediaArray = [];
+
+    //Fill media array
+    for(let media of this.media){
+        mediaArray.push(media.dehydrate());
+    }
+
+    //return dehydrated playlist
+    return {
+        name: this.name,
+        media: mediaArray,
+        defaultTitles: this.defaultTitles
+    }
+}
+
+/**
+ * Add media to the given playlist Document
+ * @param {Array} mediaList - Array of media Objects to add to playlist
+ */
+playlistSchema.methods.addMedia = function(mediaList){
+    //For every piece of media in the list
+    for(let media of mediaList){
+        //Set media status schema discriminator
+        media.status = 'saved';
+
+        //Add the media to the playlist
+        this.media.push(media);
+    }
+}
+
+/**
+ * Gets Media from a playlist by UUID
+ * @param {String} uuid - UUID of media to pull
+ * @returns {media} media with matching UUID 
+ */
+playlistSchema.methods.findMediaByUUID = function(uuid){
+    //For every piece of media in the current playlist
+    for(let media of this.media){
+        //If we found our match
+        if(media.uuid.toString() == uuid){
+            //return it
+            return media;
+        }
+    }
+}
+
+/**
+ * Deletes media from a given playlist
+ * @param {String} uuid - UUID of media to delete
+ */
+playlistSchema.methods.deleteMedia = function(uuid){
+    //Create new array to hold list of media to be kept
+    const keptMedia = [];
+
+    //For every piece of media in the current playlist
+    for(let media of this.media){
+        //It isn't the media to be deleted
+        if(media.uuid.toString() != uuid){
+            //Add it to the list to be kept
+            keptMedia.push(media);
+        }
+    }
+
+    //Set playlist media from keptMedia
+    this.media = keptMedia;
+}
+
+/**
+ * Pick title based on default title's list and media's given title
+ * @param {String} title - Title to use if there are no default titles.
+ * @returns {String} Chosen title based on result of function
+ */
+playlistSchema.methods.pickDefaultTitle = function(title){
+    //If we don't have default titles in this playlist
+    if(this.defaultTitles.length <= 0){
+        //If we wheren't handed an original title
+        if(title == null || title == ''){
+            return 'Unnamed Media'
+        }else{
+            return title;
+        }
+    }else{
+        //Grab a random default title and return it
+        return this.defaultTitles[Math.floor(Math.random() * this.defaultTitles.length)];
+    }
+}
+
+module.exports = playlistSchema;
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_channel_media_queuedMediaSchema.js.html b/www/doc/schemas_channel_media_queuedMediaSchema.js.html new file mode 100644 index 0000000..2395723 --- /dev/null +++ b/www/doc/schemas_channel_media_queuedMediaSchema.js.html @@ -0,0 +1,122 @@ + + + + + JSDoc: Source: schemas/channel/media/queuedMediaSchema.js + + + + + + + + + + +
+ +

Source: schemas/channel/media/queuedMediaSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const mediaSchema = require('./mediaSchema');
+const queuedMedia = require('../../../app/channel/media/queuedMedia');
+
+/**
+ * DB Schema for documents representing a queued media object
+ */
+const queuedProperties = new mongoose.Schema({
+    startTime: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+    },
+    startTimeStamp: {
+        type: mongoose.SchemaTypes.Number,
+        required: false,
+    },
+    earlyEnd: {
+        type: mongoose.SchemaTypes.Number,
+        required: false,
+    },
+    uuid: {
+        type: mongoose.SchemaTypes.UUID,
+        required: true,
+    }
+},
+{
+    discriminatorKey: 'status'
+});
+
+//Methods
+/**
+ * Rehydrate to a full phat queued media object
+ * @returns {queuedMedia} A full phat queued media object, re-hydrated from the DB
+ */
+queuedProperties.methods.rehydrate = function(){
+    return new queuedMedia(
+        this.title,
+        this.fileName,
+        this.url,
+        this.id,
+        this.type,
+        this.duration,
+        //We don't save raw links that are stored seperate from the standard URL as they tend to expire.
+        undefined,
+        this.startTime,
+        this.startTimeStamp,
+        this.earlyEnd,
+        this.uuid.toString()
+    );
+}
+
+//Export schema under the 'queued' discriminator of mediaSchema
+module.exports = mediaSchema.discriminator('queued', queuedProperties);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_emoteSchema.js.html b/www/doc/schemas_emoteSchema.js.html new file mode 100644 index 0000000..6860191 --- /dev/null +++ b/www/doc/schemas_emoteSchema.js.html @@ -0,0 +1,173 @@ + + + + + JSDoc: Source: schemas/emoteSchema.js + + + + + + + + + + +
+ +

Source: schemas/emoteSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const defaultEmote = require("../../defaultEmotes.json");
+const server = require('../server');
+
+/**
+ * "Enum" for emote type property
+ */
+const typeEnum = ["image", "video"];
+
+/**
+ * DB Schema for documents represnting site-wide emotes
+ */
+const emoteSchema = new mongoose.Schema({
+    name:{
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        maxLength: 14,
+    },
+    link:{
+        type: mongoose.SchemaTypes.String,
+        required: true
+    },
+    type:{
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        enum: typeEnum,
+        default: typeEnum[0]
+    }
+});
+
+/**
+ * Post-Save function, ensures all new emotes are broadcastes to actively connected clients
+ */
+emoteSchema.post('save', async function (next){
+    //broadcast updated emotes
+    server.channelManager.broadcastSiteEmotes();
+});
+
+/**
+ * Post-Delete function, ensures all deleted emotes are removed from actively connected clients
+ */
+emoteSchema.post('deleteOne', {document: true}, async function (next){
+    //broadcast updated emotes
+    server.channelManager.broadcastSiteEmotes();
+});
+
+//statics
+/**
+ * Loads un-loaded emotes from defaultEmotes.json
+ */
+emoteSchema.statics.loadDefaults = async function(){
+    //Make sure registerEmote function is happy
+    const _this = this;
+
+    //Ensure default comes first (.bind(this) doesn't seem to work here...)
+    await registerEmote(defaultEmote.default);
+    //For each entry in the defaultEmote.json file
+    defaultEmote.array.forEach(registerEmote);
+
+    async function registerEmote(emote){
+        try{
+            //Look for emote matching the one from our file
+            const foundEmote = await _this.findOne({name: emote.name});
+
+            //if the emote doesn't exist
+            if(!foundEmote){
+                const emoteDB = await _this.create(emote);
+                console.log(`Loading default emote [${emote.name}] into DB from defaultEmote.json`);
+            }
+
+        }catch(err){
+            if(emote != null){
+                console.log(`Error loading emote [${emote.name}]:`);
+            }else{
+                console.log("Error, null emote:");
+            }
+        }
+    }
+}
+
+/**
+ * Generates a network-friendly browser-digestable list of emotes
+ * @returns {Object} - network-friendly browser-digestable list of emotes
+ */
+emoteSchema.statics.getEmotes = async function(){
+    //Create an empty array to hold our emote list
+    const emoteList = [];
+    //Pull emotes from database
+    const emoteDB = await this.find({});
+
+    emoteDB.forEach((emote) => { 
+        emoteList.push({
+            name: emote.name,
+            link: emote.link,
+            type: emote.type
+        });
+    });
+
+    return emoteList;
+}
+
+emoteSchema.statics.typeEnum = typeEnum;
+
+module.exports = mongoose.model("emote", emoteSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_flairSchema.js.html b/www/doc/schemas_flairSchema.js.html new file mode 100644 index 0000000..4a4c8c3 --- /dev/null +++ b/www/doc/schemas_flairSchema.js.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Source: schemas/flairSchema.js + + + + + + + + + + +
+ +

Source: schemas/flairSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const permissionModel = require("./permissionSchema");
+const defaultFlair = require("../../defaultFlair.json");
+
+/**
+ * DB Schema for documents representing chat flair
+ */
+const flairSchema = new mongoose.Schema({
+    name:{
+        type: mongoose.SchemaTypes.String,
+        required: true
+    },
+    displayName:{
+        type: mongoose.SchemaTypes.String,
+        required: true
+    },
+    rank: {
+        type: mongoose.SchemaTypes.String,
+        enum: permissionModel.rankEnum,
+        default: "user",
+        required: true
+    }
+});
+
+/**
+ * Function which runs on server startup to load un-loaded flairs from defaultFlair.json into the DB
+ */
+flairSchema.statics.loadDefaults = async function(){
+    //Make sure registerFlair function is happy
+    const _this = this;
+
+    //Ensure default comes first (.bind(this) doesn't seem to work here...)
+    await registerFlair(defaultFlair.default);
+    //For each entry in the defaultFlair.json file
+    defaultFlair.array.forEach(registerFlair);
+
+    async function registerFlair(flair){
+        try{
+            //Look for flair matching the one from our file
+            const foundFlair = await _this.findOne({name: flair.name});
+
+            //if the flair doesn't exist
+            if(!foundFlair){
+                const flairDB = await _this.create(flair);
+                console.log(`Loading default flair '${flair.name} into DB from defaultFlair.json`);
+            }
+
+        }catch(err){
+            if(flair != null){
+                console.log(`Error loading flair '${flair.name}':`);
+            }else{
+                console.log("Error, null flair:");
+            }
+        }
+    }
+}
+
+module.exports = mongoose.model("flair", flairSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_permissionSchema.js.html b/www/doc/schemas_permissionSchema.js.html new file mode 100644 index 0000000..8d3f904 --- /dev/null +++ b/www/doc/schemas_permissionSchema.js.html @@ -0,0 +1,365 @@ + + + + + JSDoc: Source: schemas/permissionSchema.js + + + + + + + + + + +
+ +

Source: schemas/permissionSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const userModel = require('./user/userSchema');
+const channelPermissionSchema = require('./channel/channelPermissionSchema');
+const {errorHandler} = require('../utils/loggerUtils');
+
+//This originally belonged to the permissionSchema, but this avoids circular dependencies.
+//We could update all references but quite honestly I that would be uglier, this should have a copy too...
+const rankEnum = channelPermissionSchema.statics.rankEnum;
+
+/**
+ * DB Schema for the singular site-wide permission document
+ */
+const permissionSchema = new mongoose.Schema({
+    adminPanel: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    changeRank: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    changePerms: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    announce: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    resetToke: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    editTokeCommands: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    banUser: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    nukeUser: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    genPasswordReset: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    registerChannel: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    editEmotes: {
+        type: mongoose.SchemaTypes.String,
+        enum: rankEnum,
+        default: "admin",
+        required: true
+    },
+    channelOverrides: {
+        type: channelPermissionSchema,
+        default: () => ({})
+    },
+});
+
+//Statics
+permissionSchema.statics.rankEnum = rankEnum;
+
+/**
+ * Returns the server's singular permission document from the DB
+ * @returns {Mongoose.Document} - The server's singular permission document
+ */
+permissionSchema.statics.getPerms = async function(){
+    //Not sure why 'this' didn't work from here when calling this, I'm assuming it's because I'm doing it from middleware
+    //which is probably binding shit to this function, either way this works :P
+
+    //Get the first document we find
+    var perms = await module.exports.findOne({});
+    
+    if(perms){
+        //If we found something then the permissions document exist and this is it,
+        //So long as no one else has fucked with the database it should be the only one. (is this forshadowing for a future bug?)
+        return perms;
+    }else{
+        //Otherwise this is the first launch of the install, say hello
+        console.log("First launch detected! Initializing permissions document in Database!");
+
+        //create and save the permissions document
+        perms = await module.exports.create({});
+        await perms.save();
+
+        //live up to the name of the function
+        return perms;
+    }
+}
+
+/**
+ * Converts rank name to number
+ * @param {String} rank - rank to check
+ * @returns {Number} Rank level
+ */
+permissionSchema.statics.rankToNum = function(rank){
+    return rankEnum.indexOf(rank);
+}
+
+/**
+ * Check users rank against a given permission by username
+ * @param {String} user - Username of the user to check against a perm
+ * @param {String} perm - Permission to check user against
+ * @returns {Boolean} Whether or not the user is authorized for the permission in question
+ */
+permissionSchema.statics.permCheck = async function(user, perm){
+    //Check if the user is null
+    if(user != null){
+        //This specific call is why we export the userModel the way we do
+        //Someone will yell at me for circular dependencies but the fucking interpreter isn't :P
+        const userDB = await userModel.userModel.findOne({user: user.user});
+        return await this.permCheckByUserDoc(userDB, perm);
+    }else{
+        return await this.permCheckByUserDoc(null, perm);
+    }
+}
+
+/**
+ * Syntatic sugar for perms.CheckByUserDoc so we don't have to get the document ourselves
+ * @param {Mongoose.Document} user - User document to check perms against
+ * @param {String} perm - Permission to check user against
+ * @returns {Boolean} Whether or not the user is authorized for the permission in question
+ */
+permissionSchema.statics.permCheckByUserDoc = async function(user, perm){
+    //Get permission list
+    const perms = await this.getPerms();
+    //Call the perm check method
+    return perms.permCheckByUserDoc(user, perm);
+}
+
+/**
+ * Check users rank by a given permission by username
+ * @param {String} user - Username of the user to check against a perm
+ * @param {String} perm - Permission to check user against
+ * @returns {Boolean} Whether or not the user is authorized for the permission in question
+ */
+permissionSchema.statics.overrideCheck = async function(user, perm){
+    //Check if the user is null
+    if(user != null){
+        //This specific call is why we export the userModel the way we do
+        //Someone will yell at me for circular dependencies but the fucking interpreter isn't :P
+        const userDB = await userModel.userModel.findOne({user: user.user});
+        return await this.overrideCheckByUserDoc(userDB, perm);
+    }else{
+        return await this.overrideCheckByUserDoc(null, perm);
+    }
+}
+
+/**
+ * Syntatic sugar for perms.overrideCheckByUSerDoc so we don't have to seperately get the perm doc
+ * Checks channel perm override against a given user by username
+ * @param {String} user - Username of the user to check against a perm
+ * @param {String} perm - Permission to check user against
+ * @returns {Boolean} Whether or not the user is authorized for the permission in question
+ */
+permissionSchema.statics.overrideCheckByUserDoc = async function(user, perm){
+    //Get permission list
+    const perms = await this.getPerms();
+    //Call the perm check method
+    return perms.overrideCheckByUserDoc(user, perm);
+}
+
+//Middleware for rank checks
+/**
+ * Configurable express middleware which checks user's request against a given permission
+ * @param {String} perm - Permission to check
+ * @returns {Function} Express middlewhere function with given permission injected into it
+ */
+permissionSchema.statics.reqPermCheck = function(perm){
+    return (req, res, next)=>{
+        permissionSchema.statics.permCheck(req.session.user, perm).then((access) => {
+            if(access){
+                next();
+            }else{
+                return errorHandler(res, "You do not have a high enough rank to access this resource.", 'Unauthorized', 401);
+            }
+        });
+    }
+}
+
+//methods
+//these are good to have even for single-doc collections since we can loop through them without finding them in the database each time
+/**
+ * Checks permission against a single user by document
+ * @param {Mongoose.Document} userDB - User doc to rank check against
+ * @param {String} perm - Permission to check user doc against
+ * @returns {Boolean} True if authorized
+ */
+permissionSchema.methods.permCheckByUserDoc = function(userDB, perm){
+    //Set user to anon rank if no rank was found for the given user
+    if(userDB == null || userDB.rank == null){
+        userDB ={
+            rank: "anon"
+        };
+    }
+
+    //Check if this permission exists
+    if(this[perm] != null){
+        //if so get required rank as a number
+        requiredRank = this.model().rankToNum(this[perm])
+        //if so get user rank as a number
+        userRank = userDB ? this.model().rankToNum(userDB.rank) : 0;
+        //return whether or not the user is equal to or higher than the required rank for this permission
+        return (userRank >= requiredRank);
+    }else{
+        //if not scream and shout
+        throw loggerUtils.exceptionSmith(`Permission check '${perm}' not found!`, "Validation");
+    }
+}
+
+/**
+ * Checks channel override permission against a single user by document
+ * @param {Mongoose.Document} userDB - User doc to rank check against
+ * @param {String} perm - Channel Override Permission to check user doc against
+ * @returns {Boolean} True if authorized
+ */
+permissionSchema.methods.overrideCheckByUserDoc = function(userDB, perm){
+    //Set user to anon rank if no rank was found for the given user
+    if(userDB == null || userDB.rank == null){
+        userDB ={
+            rank: "anon"
+        };
+    }
+
+    //Check if this permission exists
+    if(this.channelOverrides[perm] != null){
+        //if so get required rank as a number
+        requiredRank = this.model().rankToNum(this.channelOverrides[perm])
+        //if so get user rank as a number
+        userRank = userDB ? this.model().rankToNum(userDB.rank) : 0;
+        //return whether or not the user is equal to or higher than the required rank for this permission
+        return (userRank >= requiredRank);
+    }else{
+        //if not scream and shout
+        throw loggerUtils.exceptionSmith(`Permission check '${perm}' not found!`, "validation");
+    }
+}
+
+/**
+ * Returns entire permission map marked with booleans
+ * @param {Mongoose.Document} userDB - User Doc to generate perm map against
+ * @returns {Map} Permission map containing booleans for each permission's authorization for a given user doc
+ */
+permissionSchema.methods.getPermMapByUserDoc = function(userDB){
+    //Pull permissions keys
+    let permTree = this.schema.tree;
+    let overrideTree = channelPermissionSchema.tree;
+    let permMap = new Map();
+    let overrideMap = new Map();
+
+    //For each object in the temporary permissions object
+    for(let perm of Object.keys(permTree)){
+        //Check the current permission
+        permMap.set(perm, this.permCheckByUserDoc(userDB, perm));
+    }
+
+    //For each object in the temporary permissions object
+    for(let perm of Object.keys(overrideTree)){
+        //Check the current permission
+        overrideMap.set(perm, this.overrideCheckByUserDoc(userDB, perm));
+    }
+
+    //return the auto-generated schema
+    return {
+        site: permMap,
+        channelOverrides: overrideMap
+    }
+}
+
+module.exports = mongoose.model("permissions", permissionSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_statSchema.js.html b/www/doc/schemas_statSchema.js.html new file mode 100644 index 0000000..010df6d --- /dev/null +++ b/www/doc/schemas_statSchema.js.html @@ -0,0 +1,249 @@ + + + + + JSDoc: Source: schemas/statSchema.js + + + + + + + + + + +
+ +

Source: schemas/statSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const config = require('./../../config.json');
+
+/**
+ * DB Schema for single document for keeping track of server stats
+ */
+const statSchema = new mongoose.Schema({
+    //This does NOT handle deleted accounts/channels. Use userModel.estimatedDocumentCount() for number of active users.
+    userCount: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+        default: 0
+    },
+    channelCount: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+        default: 0
+    },
+    launchCount: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+        default: 0
+    },
+    firstLaunch: {
+        type: mongoose.SchemaTypes.Date,
+        required: true,
+        default: new Date()
+    },
+    tokes: [{
+        toke: {
+            type: mongoose.SchemaTypes.Map,
+            required: true,
+            default: new Map()
+        },
+        date: {
+            type: mongoose.SchemaTypes.Date,
+            required: true,
+            default: new Date()
+        }
+    }]
+});
+
+//statics
+/**
+ * Get's servers sole stat document from the DB
+ * @returns {Mongoose.Document} Server's sole statistics document
+ */
+statSchema.statics.getStats = async function(){
+    //Get the first document we find
+    var stats = await this.findOne({});
+    
+    if(stats){
+        //If we found something then the statistics document exist and this is it,
+        //So long as no one else has fucked with the database it should be the only one. (is this forshadowing for a future bug?)
+        return stats;
+    }else{
+        //Otherwise this is the first launch of the install, say hello
+        console.log("First launch detected! Initializing statistics document in Database!");
+
+        //create and save the statistics document
+        stats = await this.create({});
+        await stats.save();
+
+        //live up to the name of the function
+        return stats;
+    }
+}
+
+/**
+ * Increments Lunach count upon server launch and prints out amount of launches since server initialization
+ */
+statSchema.statics.incrementLaunchCount = async function(){
+    //get our statistics document
+    const stats = await this.getStats();
+
+    //increment counter and save
+    stats.launchCount++;
+    stats.save();
+
+    //print bootup message to console.
+    console.log(`${config.instanceName}(Powered by Canopy) initialized. This server has booted ${stats.launchCount} time${stats.launchCount == 1 ? '' : 's'}.`)
+    console.log(`First booted on ${stats.firstLaunch}.`);
+}
+
+/**
+ * Increments user count upon new user registration
+ * @returns {Number} Number of users before count was incremented
+ */
+statSchema.statics.incrementUserCount = async function(){
+    //get our statistics document
+    const stats = await this.getStats();
+    //temporarily keep old count so we can return it for the users ID 
+    const oldCount = stats.userCount;
+
+    //increment counter and save
+    stats.userCount++;
+    stats.save();
+
+    //return the count from beggining of function for user ID
+    return oldCount;
+}
+
+/**
+ * Increments channel count upon new channel registration
+ * @returns {Number} Number of channels before count was incremented
+ */
+statSchema.statics.incrementChannelCount = async function(){
+    //get our statistics document
+    const stats = await this.getStats();
+    //temporarily keep old count so we can return it for the channel ID 
+    const oldCount = stats.channelCount;
+
+    //increment counter and save
+    stats.channelCount++;
+    stats.save();
+
+    //return the count from beggining of function for channel ID
+    return oldCount;
+}
+
+/**
+ * Tattoo's toke to the server statistics document
+ * @param {Map} toke - Tokemap handed down from Tokebot
+ */
+statSchema.statics.tattooToke = async function(toke){
+    //Get the statistics document
+    const stats = await this.getStats();
+
+    //Add the toke to the stat document
+    stats.tokes.push({toke});
+
+    //Save the stat document
+    await stats.save();
+}
+
+/**
+ * Gets toke count from statistics document
+ * @returns {Number} Number of tokes across the entire site
+ */
+statSchema.statics.getTokeCount = async function(){
+    //get stats doc
+    const stats = await this.getStats();
+
+    //return toke count
+    return stats.tokes.length;
+}
+
+/**
+ * Gets toke counts for each individual callout in a map
+ * @returns {Map} Map of toke counts for each individual callout registered to the server
+ */
+statSchema.statics.getTokeCommandCounts = async function(){
+    //get stats doc
+    const stats = await this.getStats()
+    //Create empty map to hold toke command counts
+    const count = new Map();
+
+    //for each toke
+    stats.tokes.forEach((toke) => {
+        //For each toke command called in the current toke
+        toke.toke.forEach((command) => {
+            //Get the current count for the current command
+            var curCount = count.get(command);
+
+            //if the current count is null
+            if(curCount == null){
+                //Set it to one
+                count.set(command, 1);
+            }else{
+                //Set it to ++curCount
+                count.set(command, ++curCount);
+            }
+        });
+    });
+
+    //return the toke command count
+    return count;
+}
+
+module.exports = mongoose.model("statistics", statSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_tokebot_tokeCommandSchema.js.html b/www/doc/schemas_tokebot_tokeCommandSchema.js.html new file mode 100644 index 0000000..fc81b54 --- /dev/null +++ b/www/doc/schemas_tokebot_tokeCommandSchema.js.html @@ -0,0 +1,169 @@ + + + + + JSDoc: Source: schemas/tokebot/tokeCommandSchema.js + + + + + + + + + + +
+ +

Source: schemas/tokebot/tokeCommandSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const defaultTokes = require("../../../defaultTokes.json");
+const server = require('../../server');
+
+/**
+ * Mongoose Schema representing a toke command
+ */
+const tokeCommandSchema = new mongoose.Schema({
+    command:{
+        type: mongoose.SchemaTypes.String,
+        required: true
+    }
+});
+
+/**
+ * Pre-Save middleware, ensures tokebot receives all new toke commands
+ */
+tokeCommandSchema.pre('save', async function (next){
+    //if the command was changed
+    if(this.isModified("command")){
+        //Get server tokebot object
+        const tokebot = server.channelManager.chatHandler.commandPreprocessor.tokebot;
+
+        //Pop the command on to the end
+        tokebot.tokeCommands.push(this.command);
+    }
+
+
+    //All is good, continue on saving.
+    next();
+});
+
+/**
+ * Pre-Delete middleware, ensures tokebot removes all old toke commands
+ */
+tokeCommandSchema.pre('deleteOne', {document: true}, async function (next){
+    //Get server tokebot object (isn't this a fun dot crawler? Why hasn't anyone asked me to stop writing software yet?)
+    const tokebot = server.channelManager.chatHandler.commandPreprocessor.tokebot;
+
+    //Get the index of the command within tokeCommand and splice it out
+    tokebot.tokeCommands.splice(tokebot.tokeCommands.indexOf(this.command),1);
+
+    //All is good, continue on deleting.
+    next();
+});
+
+/**
+ * Pulls command strings from DB and reports back
+ * @returns {Array} Array of toke commands pulled from the DB
+ */
+tokeCommandSchema.statics.getCommandStrings = async function(){
+    //Get all toke commands in the DB
+    const tokeDB = await this.find({});
+    //Create an empty array to hold the toke commands
+    var tokeArray = [];
+
+    //for all toke commands found in the database
+    tokeDB.forEach((toke)=>{
+        //Push the command string into the tokeArray
+        tokeArray.push(toke.command);
+    })
+
+    //return the toke command strings from the database
+    return tokeArray;
+}
+
+/**
+ * Loads default tokes into the DB from flat file upon launch
+ */
+tokeCommandSchema.statics.loadDefaults = async function(){
+    //Make sure registerToke function is happy
+    const _this = this;
+
+    //Ensure default comes first (.bind(this) doesn't seem to work here...)
+    await registerToke(defaultTokes.default);
+    //For each entry in the defaultTokes.json file
+    defaultTokes.array.forEach(registerToke);
+
+    async function registerToke(toke){
+        try{
+            //Look for toke matching the one from our file
+            const foundToke = await _this.findOne({command: toke});
+
+            //if the toke doesn't exist
+            if(!foundToke){
+                const tokeDB = await _this.create({command: toke});
+                console.log(`Loading default toke command '!${toke}' into DB from defaultTokes.json`);
+            }
+
+        }catch(err){
+            if(toke != null){
+                console.log(`Error loading toke command: '!${toke}'`);
+            }else{
+                console.log("Error, null toke!");
+            }
+        }
+    }
+}
+
+module.exports = mongoose.model("tokeCommand", tokeCommandSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_user_emailChangeSchema.js.html b/www/doc/schemas_user_emailChangeSchema.js.html new file mode 100644 index 0000000..0a1f2c8 --- /dev/null +++ b/www/doc/schemas_user_emailChangeSchema.js.html @@ -0,0 +1,231 @@ + + + + + JSDoc: Source: schemas/user/emailChangeSchema.js + + + + + + + + + + +
+ +

Source: schemas/user/emailChangeSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//You could make an argument for making this part of the userModel
+//However, this is so rarely used the preformance benefits aren't worth the extra clutter
+
+//Config
+const config = require('../../../config.json');
+
+//Node Imports
+const crypto = require("node:crypto");
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const hashUtil = require('../../utils/hashUtils');
+const mailUtils = require('../../utils/mailUtils');
+
+/**
+ * Email change token retention time 
+ */
+const daysToExpire = 7;
+
+/**
+ * DB Schema for Document representing a single email change request
+ */
+const emailChangeSchema = new mongoose.Schema({
+    user: {
+        type: mongoose.SchemaTypes.ObjectID,
+        ref: "user",
+        required: true
+    },
+    newEmail: {
+        type: mongoose.SchemaTypes.String,
+        required: true
+    },
+    token: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        //Use a cryptographically secure algorythm to create a random hex string from 16 bytes as our change/cancel token
+        default: ()=>{return crypto.randomBytes(16).toString('hex')}
+    },
+    ipHash: {
+        type: mongoose.SchemaTypes.String,
+        required: true
+    },
+    date: {
+        type: mongoose.SchemaTypes.Date,
+        required: true,
+        default: new Date()
+    }
+});
+
+
+/**
+ * Pre-Save function, ensures IP's are hashed and previous requests are deleted upon request creation
+ */
+emailChangeSchema.pre('save', async function (next){
+    //If we're saving an ip
+    if(this.isModified('ipHash')){
+        //Hash that sunnuvabitch
+        this.ipHash = hashUtil.hashIP(this.ipHash);
+    }
+
+    if(this.isModified('user')){
+        //Delete previous requests for the given user
+        const requests = await this.model().deleteMany({user: this.user._id});
+    }
+
+    next();
+});
+
+/**
+ * Schedulable function for processing expired email change requests
+ */
+emailChangeSchema.statics.processExpiredRequests = async function(){
+    //Pull all requests from the DB
+    //Tested finding request by date, but mongoose kept throwing casting errors.
+    //This seems to be an intermittent issue online. Maybe it will work in a future version?
+    const requestDB = await this.find({});
+
+    //Fire em all off at once without waiting for the last one to complete since we don't fuckin' need to
+    for(let requestIndex in requestDB){
+        //Pull request from requestDB by index
+        const request = requestDB[requestIndex];
+
+        //If the request hasn't been processed and it's been expired
+        if(request.getDaysUntilExpiration() <= 0){
+            //Delete the request
+            await this.deleteOne({_id: request._id});
+        }
+    }
+}
+
+/**
+ * Consumes email change token, changing email address on a given user
+ */
+emailChangeSchema.methods.consume = async function(){
+    //Populate the user reference
+    await this.populate('user');
+
+    const  oldMail = this.user.email;
+
+    //Set the new email
+    this.user.email = this.newEmail;
+    
+    //Save the user
+    await this.user.save();
+
+    //Delete the request token now that it has been consumed
+    await this.deleteOne();
+
+    //If we had a previous email address
+    if(oldMail != null && oldMail != ''){
+        //Notify it of the change
+        await mailUtils.mailem(
+            oldMail,
+            `Email Change Notification - ${this.user.user}`,
+            `<h1>Email Change Notification</h1>
+            <p>The ${config.instanceName} account '${this.user.user}' is no longer associated with this email address.<br>
+            <sup>If you received this email without request, you should <strong>immediately</strong> change your password and contact the server adminsitrator! -Tokebot</sup>`,
+            true
+        );
+    }
+
+    //Notify the new inbox of the change
+    await mailUtils.mailem(
+        this.newEmail,
+        `Email Change Notification - ${this.user.user}`,
+        `<h1>Email Change Notification</h1>
+        <p>The ${config.instanceName} account '${this.user.user}' is now associated with this email address.<br>
+        <sup>If you received this email without request, you should <strong>immediately</strong> check who's been inside your inbox! -Tokebot</sup>`,
+        true
+    );
+
+}
+
+/**
+ * Generates email change URL from a given token
+ * @returns {String} Email change URL generated from token
+ */
+emailChangeSchema.methods.getChangeURL = function(){
+    //Check for default port based on protocol
+    if((config.protocol == 'http' && config.port == 80) || (config.protocol == 'https' && config.port == 443  || config.proxied)){
+        //Return path
+        return `${config.protocol}://${config.domain}/emailChange?token=${this.token}`;
+    }else{
+        //Return path
+        return `${config.protocol}://${config.domain}:${config.port}/emailChange?token=${this.token}`;
+    }
+}
+
+/**
+ * Calculates days until token expiration
+ * @returns {Number} Days until token expiration
+ */
+emailChangeSchema.methods.getDaysUntilExpiration = function(){
+        //Get request date
+        const expirationDate = new Date(this.date);
+        //Get expiration days and calculate expiration date
+        expirationDate.setDate(expirationDate.getDate() + daysToExpire);
+        //Calculate and return days until request expiration
+        return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1);
+}
+
+module.exports = mongoose.model("emailChange", emailChangeSchema);
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_user_passwordResetSchema.js.html b/www/doc/schemas_user_passwordResetSchema.js.html new file mode 100644 index 0000000..1a3fff1 --- /dev/null +++ b/www/doc/schemas_user_passwordResetSchema.js.html @@ -0,0 +1,207 @@ + + + + + JSDoc: Source: schemas/user/passwordResetSchema.js + + + + + + + + + + +
+ +

Source: schemas/user/passwordResetSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//You could make an argument for making this part of the userModel
+//However, this is so rarely used the preformance benefits aren't worth the extra clutter
+
+//Config
+const config = require('../../../config.json');
+
+//Node Imports
+const crypto = require("node:crypto");
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const hashUtil = require('../../utils/hashUtils.js');
+const loggerUtils = require('../../utils/loggerUtils.js')
+
+/**
+ * Password reset token retention time
+ */
+const daysToExpire = 7;
+
+/**
+ * DB Schema for documents containing a single expiring password reset token
+ */
+const passwordResetSchema = new mongoose.Schema({
+    user: {
+        type: mongoose.SchemaTypes.ObjectID,
+        ref: "user",
+        required: true
+    },
+    token: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        //Use a cryptographically secure algorythm to create a random hex string from 16 bytes as our reset token
+        default: ()=>{return crypto.randomBytes(16).toString('hex')}
+    },
+    ipHash: {
+        type: mongoose.SchemaTypes.String,
+        required: true
+    },
+    date: {
+        type: mongoose.SchemaTypes.Date,
+        required: true,
+        default: new Date()
+    }
+});
+
+
+/**
+ * Pre-save function, ensures IP's are hashed before saving
+ */
+passwordResetSchema.pre('save', async function (next){
+    //If we're saving an ip
+    if(this.isModified('ipHash')){
+        //Hash that sunnuvabitch
+        this.ipHash = hashUtil.hashIP(this.ipHash);
+    }
+
+    next();
+});
+
+/**
+ * Schedulable function for processing expired reset requests
+ */
+passwordResetSchema.statics.processExpiredRequests = async function(){
+    //Pull all requests from the DB
+    //Tested finding request by date, but mongoose kept throwing casting errors.
+    //This seems to be an intermittent issue online. Maybe it will work in a future version?
+    const requestDB = await this.find({});
+
+    //Fire em all off at once without waiting for the last one to complete since we don't fuckin' need to
+    for(let requestIndex in requestDB){
+        //pull request from requestDB by index
+        const request = requestDB[requestIndex];
+
+        //If the request hasn't been processed and it's been expired
+        if(request.getDaysUntilExpiration() <= 0){
+            //Delete the request
+            await this.deleteOne({_id: request._id});
+        }
+    }
+}
+
+//methods
+/**
+ * Resets password and consumes token
+ * @param {String} pass - New password to set
+ * @param {String} confirmPass - Confirmation String to ensure new pass is correct
+ */
+passwordResetSchema.methods.consume = async function(pass, confirmPass){
+    //Check confirmation pass
+    if(pass != confirmPass){
+        throw loggerUtils.exceptionSmith("Confirmation password does not match!", "validation");
+    }
+
+    //Populate the user reference
+    await this.populate('user');
+
+    //Set the users password
+    this.user.pass = pass;
+    
+    //Save the user
+    await this.user.save();
+
+    //Kill all authed sessions for security purposes
+    await this.user.killAllSessions("Your password has been reset.");
+
+    //Delete the request token now that it has been consumed
+    await this.deleteOne();
+}
+
+/**
+ * Generates password reset URL off of the token object
+ * @returns {String} Reset URL
+ */
+passwordResetSchema.methods.getResetURL = function(){
+    //Check for default port based on protocol
+    if((config.protocol == 'http' && config.port == 80) || (config.protocol == 'https' && config.port == 443) || config.proxied){
+        //Return path
+        return `${config.protocol}://${config.domain}/passwordReset?token=${this.token}`;
+    }else{
+        //Return path
+        return `${config.protocol}://${config.domain}:${config.port}/passwordReset?token=${this.token}`;
+    }
+}
+
+/**
+ * Returns number of days until token expiration
+ * @returns {Number} Number of days until token expiration
+ */
+passwordResetSchema.methods.getDaysUntilExpiration = function(){
+        //Get request date
+        const expirationDate = new Date(this.date);
+        //Get expiration days and calculate expiration date
+        expirationDate.setDate(expirationDate.getDate() + daysToExpire);
+        //Calculate and return days until request expiration
+        return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1);
+}
+
+module.exports = mongoose.model("passwordReset", passwordResetSchema);
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_user_userBanSchema.js.html b/www/doc/schemas_user_userBanSchema.js.html new file mode 100644 index 0000000..3db347e --- /dev/null +++ b/www/doc/schemas_user_userBanSchema.js.html @@ -0,0 +1,530 @@ + + + + + JSDoc: Source: schemas/user/userBanSchema.js + + + + + + + + + + +
+ +

Source: schemas/user/userBanSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//Local Imports
+const hashUtil = require('../../utils/hashUtils.js');
+const {userModel} = require('./userSchema.js');
+const loggerUtils = require('../../utils/loggerUtils.js');
+
+/**
+ * DB Schema for Documents representing a single user's ban
+ */
+const userBanSchema = new mongoose.Schema({
+    user: {
+        type: mongoose.SchemaTypes.ObjectID,
+        ref: "user"
+    },
+    ips: {
+        plaintext: {
+            type: [mongoose.SchemaTypes.String],
+            required: false
+        },
+        hashed: {
+            type: [mongoose.SchemaTypes.String],
+            required: false
+        }
+    },
+    alts: [{
+        type: mongoose.SchemaTypes.ObjectID,
+        ref: "user"
+    }],
+    deletedNames: {
+        type: [mongoose.SchemaTypes.String],
+        required: false
+    },
+    banDate: {
+
+        type: mongoose.SchemaTypes.Date,
+        required: true,
+        default: new Date()
+    },
+    expirationDays: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+        default: 30
+    },
+    //If true, then expiration date deletes associated accounts instead of deleting the ban record
+    permanent: {
+        type: mongoose.SchemaTypes.Boolean,
+        required: true,
+        default: false
+    }
+});
+
+/**
+ * Checks ban by IP
+ * @param {String} ip - IP Address check for bans
+ * @returns {Mongoose.Document} Found ban Document if one exists.
+ */
+userBanSchema.statics.checkBanByIP = async function(ip){
+    //Get hash of ip
+    const ipHash = hashUtil.hashIP(ip);
+    //Get all bans
+    const banDB = await this.find({});
+    //Create null variable to hold any found ban
+    let foundBan = null;
+
+    //For every ban
+    for(ban of banDB){
+        //Create empty list to hold unmatched hashes in the advent that we match one
+        let tempHashes = [];
+        //Create flag to throw to save tempHashes in the advent that we have matches we dont want to save as hashes
+        let saveBan = false;
+
+
+        //For every plaintext IP in the ban
+        for(ipIndex in ban.ips.plaintext){
+            //Get the current ip
+            const curIP = ban.ips.plaintext[ipIndex];
+
+            //Check the current IP against the given ip
+            if(ip == curIP){
+                //If it matches we found the ban
+                foundBan = ban;
+            }
+        }
+
+        //For every hashed IP in the ban
+        for(ipIndex in ban.ips.hashed){
+            //Get the current ip hash
+            const curHash = ban.ips.hashed[ipIndex];
+
+            //Check the current hash against the given hash
+            if(ipHash == curHash){
+                //If it matches we found the ban
+                foundBan = ban;
+
+                //Push the match to plaintext IPs so we know who the fucker is
+                ban.ips.plaintext.push(ip);
+
+                //Throw the save ban flag to save the ban
+                saveBan = true;
+            //Otherwise
+            }else{
+                //Keep the hash since it hasn't been matched yet
+                tempHashes.push(curHash);
+            }
+        }
+
+        //If we matched a hashed ip and we need to save it as plaintext
+        if(saveBan){
+            //Keep unmatched hashes
+            ban.ips.hashed = tempHashes;
+
+            //Save the current ban
+            await ban.save();
+        }
+    }
+
+    return foundBan;
+}
+
+/**
+ * Checks for bans by user DB doc
+ * @param {Mongoose.Document} userDB - User Doc to check
+ * @returns {Mongoose.Document} Found ban document for given user doc
+ */
+userBanSchema.statics.checkBanByUserDoc = async function(userDB){
+    const banDB = await this.find({});
+    var foundBan = null;
+
+    banDB.forEach((ban) => {
+        if(ban.user != null){
+            //if we found a match
+            if(ban.user.toString() == userDB._id.toString()){
+                //Set found ban
+                foundBan = ban;
+            }
+
+            //For each banned alt
+            for(altIndex in ban.alts){
+                //get current alt
+                const alt = ban.alts[altIndex];
+
+                //if the alt matches our user
+                if(alt._id.toString() == userDB._id.toString()){
+                    //Set found ban
+                    foundBan = ban;
+                }
+            }
+        }
+    });
+
+    return foundBan;
+}
+
+/**
+ * Checks for ban by username
+ * @param {String} user - User to check for bans
+ * @returns {Mongoose.Document} Found User Ban DB Document
+ */
+userBanSchema.statics.checkBan = async function(user){
+    const userDB = await userModel.findOne({user: user.user});
+    return this.checkBanByUserDoc(userDB);
+}
+
+/**
+ * Looks through processed bans by user
+ * @param {String} user - user to check against for bans
+ * @returns {Mongoose.Document} Spent User Ban Document
+ */
+userBanSchema.statics.checkProcessedBans = async function(user){
+    //Pull banlist and create empty variable to hold any found ban
+    const banDB = await this.find({});
+    var foundBan = null;
+
+    //For each ban in list
+    banDB.forEach((ban)=>{
+        //For each deleted account associated with the ban
+        ban.deletedNames.forEach((name)=>{
+            //If the banned name equals the name we're checking against
+            if(name == user){
+                //We've found our ban
+                foundBan = ban;
+            }
+        })
+    });
+
+    //Return any found associated ban
+    return foundBan;
+}
+
+/**
+ * Bans a given user by their user Document
+ * @param {Mongoose.Document} userDB - DB Doc of the user to ban
+ * @param {Boolean} permanent - Whether or not it's permanant
+ * @param {Number} expirationDays - Days to expire
+ * @param {Boolean} ipBan - Whether or not we're banning by IP
+ * @returns {Mongoose.Document} A freshly created User Ban DB Document :)
+ */
+userBanSchema.statics.banByUserDoc = async function(userDB, permanent, expirationDays, ipBan = false){
+    //Prevent missing users
+    if(userDB == null){
+        throw loggerUtils.exceptionSmith("User not found", "validation");
+    }
+
+    //Ensure the user isn't already banned
+    if(await this.checkBanByUserDoc(userDB) != null){
+        throw loggerUtils.exceptionSmith("User already banned", "validation");
+    }
+
+    //Verify time to expire/delete depending on action
+    if(expirationDays < 0){
+        throw loggerUtils.exceptionSmith("Expiration Days must be a positive integer!", "validation");
+    }else if(expirationDays < 30 && permanent){
+        throw loggerUtils.exceptionSmith("Permanent bans must be given at least 30 days before automatic account deletion!", "validation");
+    }else if(expirationDays > 185){
+        throw loggerUtils.exceptionSmith("Expiration/Deletion date cannot be longer than half a year out from the original ban date.", "validation");
+    }
+
+    await banSessions(userDB);
+
+    //Add the ban to the database
+    const banDB = await this.create({user: userDB._id, permanent, expirationDays});
+
+    //If we're banning the users IP
+    if(ipBan){
+        //Scrape IP's from current user into the ban record
+        await scrapeUserIPs(userDB);
+
+        //Populate the users alts
+        await userDB.populate('alts');
+
+        //For each of the users alts
+        for(altIndex in userDB.alts){
+            //Add the current alt to the ban record
+            banDB.alts.push(userDB.alts[altIndex]._id);
+
+            //Scrape out the IPs from the current alt into the ban record
+            await scrapeUserIPs(userDB.alts[altIndex]);
+
+            //Kill all of alts sessions
+            await banSessions(userDB.alts[altIndex]);
+        }
+
+        //Save commited IP information to the ban record
+        await banDB.save();
+
+        async function scrapeUserIPs(curRecord){
+            //For each hashed ip on record for this user
+            for(hashIndex in curRecord.recentIPs){
+                //Look for any occurance of the current hash
+                const foundHash = banDB.ips.hashed.indexOf(curRecord.recentIPs[hashIndex].ipHash);
+
+                //If its not listed in the ban record
+                if(foundHash == -1){
+                    //Add it to the list of hashed IPs for this ban
+                    banDB.ips.hashed.push(curRecord.recentIPs[hashIndex].ipHash);
+                }
+            }
+        }
+    }
+
+    //return the ban record
+    return banDB;
+
+    async function banSessions(user){
+        //Log the user out
+        if(permanent){
+            await user.killAllSessions(`Your account has been permanently banned, and will be nuked from the database in ${expirationDays} day(s).`);
+        }else{
+            await user.killAllSessions(`Your account has been temporarily banned, and will be reinstated in: ${expirationDays} day(s).`);
+        }
+    }
+}
+
+/**
+ * Bans user by username
+ * @param {String} user - Username of user to ban
+ * @param {Boolean} permanent - Whether or not it's permanant
+ * @param {Number} expirationDays - Days to expire
+ * @param {Boolean} ipBan - Whether or not we're banning by IP
+ * @returns {Mongoose.Document} A freshly created User Ban DB Document :)
+ */
+userBanSchema.statics.ban = async function(user, permanent, expirationDays, ipBan){
+    const userDB = await userModel.findOne({user: user.user});
+    return this.banByUserDoc(userDB, permanent, expirationDays, ipBan);
+}
+
+/**
+ * Unbans users by user doc
+ * @param {Mongoose.Document} userDB - User DB Document to unban
+ * @returns {Mongoose.Document} Old, deleted ban document
+ */
+userBanSchema.statics.unbanByUserDoc = async function(userDB){
+
+    //Prevent missing users
+    if(userDB == null){
+        throw loggerUtils.exceptionSmith("User not found", "validation");
+    }
+
+    const banDB = await this.checkBanByUserDoc(userDB);
+
+    if(!banDB){
+        throw loggerUtils.exceptionSmith("User already un-banned", "validation");
+    }
+
+    //Use _id in-case mongoose wants to be a cunt
+    var oldBan = await this.deleteOne({_id: banDB._id});
+    return oldBan;
+}
+
+/**
+ * Unban deleted user
+ * Can't bring back accounts, but will re-allow re-use of old usernames, and new accounts/connections from banned IP's
+ * @param {String} user - Username of deleted account to unban
+ * @returns {Mongoose.Document} Old, deleted ban document
+ */
+userBanSchema.statics.unbanDeleted = async function(user){
+    const banDB = await this.checkProcessedBans(user);
+    
+    if(!banDB){
+        throw loggerUtils.exceptionSmith("User already un-banned", "validation");
+    }
+
+    const oldBan = await this.deleteOne({_id: banDB._id});
+    return oldBan;
+}
+
+/**
+ * Unbans user by username
+ * @param {String} user - Username of user to unban
+ * @returns Old, deleted ban document
+ */
+userBanSchema.statics.unban = async function(user){
+    //Find user in DB
+    const userDB = await userModel.findOne({user: user.user});
+
+    //If user was deleted
+    if(userDB == null){
+        //unban deleted user
+        return await this.unbanDeleted(user.user);
+    }else{
+        //unban by user doc
+        return await this.unbanByUserDoc(userDB);
+    }
+}
+
+/**
+ * Generates Network-Friendly Browser-Digestable list of bans for the admin panel
+ * @returns {Object} Network-Friendly Browser-Digestable list of bans for the admin panel
+ */
+userBanSchema.statics.getBans = async function(){
+    //Get the ban, populating users and alts
+    const banDB = await this.find({}).populate('user').populate('alts');
+    //Create an empty array to hold ban records
+    var bans = [];
+
+    banDB.forEach((ban) => {
+        //Create array to hold alts
+        var alts = [];
+        //Calculate expiration date
+        var expirationDate = new Date(ban.banDate);
+        expirationDate.setDate(expirationDate.getDate() + ban.expirationDays);
+
+        //Make sure we're not about to read the properties of a null object
+        if(ban.user != null){
+            var userObj = ban.user.getProfile();
+        }
+
+
+        //For each alt in the ban
+        for(alt of ban.alts){
+            //Get the profile and push it to the alt list
+            alts.push(alt.getProfile());
+        }
+
+        //Create ban object
+        const banObj = {
+            banDate: ban.banDate,
+            expirationDays: ban.expirationDays,
+            expirationDate: expirationDate,
+            daysUntilExpiration: ban.getDaysUntilExpiration(),
+            user: userObj,
+            ips: ban.ips,
+            alts,
+            deletedNames: ban.deletedNames,
+            permanent: ban.permanent
+        }
+
+        //Add it to the array
+        bans.push(banObj);
+    });
+
+    //Return the array
+    return bans;
+}
+
+/**
+ * Scheduable function for processing expired user bans
+ */
+userBanSchema.statics.processExpiredBans = async function(){
+    //Channel ban expirations may vary so there's no way to search for expired bans
+    const banDB = await this.find({});
+
+    //Firem all off all at once seperately without waiting for one another
+    for(let banIndex in banDB){
+        //Pull ban from banlist by index        
+        const ban = banDB[banIndex];
+
+        //This ban was already processed, and it's user has been deleted. There is no more to be done...
+        if(ban.user == null){
+            return;
+        }
+
+        //If the ban hasn't been processed and it's got 0 or less days to go
+        if(ban.getDaysUntilExpiration() <= 0){
+            //If the ban is permanent
+            if(ban.permanent){
+                //Populate the user and alt fields
+                await ban.populate('user');
+                await ban.populate('alts');
+                //Add the name to our deleted names list
+                ban.deletedNames.push(ban.user.user);
+                //Hey hey hey, goodbye!
+                await userModel.deleteOne({_id: ban.user._id});
+                //Empty out the reference
+                ban.user = null;
+
+                //For every alt
+                for(alt of ban.alts){
+                    //Add the alts name to the deleted names list
+                    ban.deletedNames.push(alt.user);
+                    //Motherfuckin' Kablewie!
+                    await userModel.deleteOne({_id: alt._id});
+                }
+
+                //Clear out the alts array
+                ban.alts = [];
+
+                //Save the ban
+                await ban.save();
+            }else{
+                //Otherwise, delete the ban and let our user back in :P
+                await this.deleteOne({_id: ban._id});
+            }
+        }
+    }
+}
+
+//methods
+/**
+ * Calculates days until ban expiration
+ * @returns {Number} Days until ban expiration
+ */
+userBanSchema.methods.getDaysUntilExpiration = function(){
+        //Get ban date
+        const expirationDate = new Date(this.banDate);
+        //Get expiration days and calculate expiration date
+        expirationDate.setDate(expirationDate.getDate() + this.expirationDays);
+        //Calculate and return days until ban expiration
+        return ((expirationDate - new Date()) / (1000 * 60 * 60 * 24)).toFixed(1);
+}
+
+module.exports = mongoose.model("userBan", userBanSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/schemas_user_userSchema.js.html b/www/doc/schemas_user_userSchema.js.html new file mode 100644 index 0000000..e5c04b0 --- /dev/null +++ b/www/doc/schemas_user_userSchema.js.html @@ -0,0 +1,897 @@ + + + + + JSDoc: Source: schemas/user/userSchema.js + + + + + + + + + + +
+ +

Source: schemas/user/userSchema.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const {mongoose} = require('mongoose');
+
+//local imports
+//server
+const server = require('../../server');
+//DB Models
+const statModel = require('../statSchema');
+const flairModel = require('../flairSchema');
+const permissionModel = require('../permissionSchema');
+const emoteModel = require('../emoteSchema');
+const emailChangeModel = require('./emailChangeSchema');
+const playlistSchema = require('../channel/media/playlistSchema');
+//Utils
+const hashUtil = require('../../utils/hashUtils');
+const mailUtil = require('../../utils/mailUtils');
+const loggerUtils = require('../../utils/loggerUtils')
+
+
+/**
+ * Mongoose Schema for a document representing a single canopy user
+ */
+const userSchema = new mongoose.Schema({
+    id: {
+        type: mongoose.SchemaTypes.Number,
+        required: true
+    },
+    user: {
+        type: mongoose.SchemaTypes.String,
+        maxLength: 22,
+        required: true,
+    },
+    pass: {
+        type: mongoose.SchemaTypes.String,
+        required: true
+    },
+    email: {
+        type: mongoose.SchemaTypes.String,
+        optional: true,
+        default: ""
+    },
+    date: {
+        type: mongoose.SchemaTypes.Date,
+        required: true,
+        default: new Date()
+    },
+    rank: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        enum: permissionModel.rankEnum,
+        default: "user"
+    },
+    tokes: {
+        type: mongoose.SchemaTypes.Map,
+        required: true,
+        default: new Map()
+    },
+    img: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        default: "/img/johnny.png"
+    },
+    bio: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        //Calculate max length by the validator max length and the size of an escaped character
+        maxLength: 1000 * 6,
+        default: "Bio not set!"
+    },
+    pronouns:{
+        type: mongoose.SchemaTypes.String,
+        optional: true,
+        //Calculate max length by the validator max length and the size of an escaped character
+        maxLength: 15 * 6,
+        default: ""
+    },
+    signature: {
+        type: mongoose.SchemaTypes.String,
+        required: true,
+        //Calculate max length by the validator max length and the size of an escaped character
+        maxLength: 25 * 6,
+        default: "Signature not set!"
+    },
+    highLevel: {
+        type: mongoose.SchemaTypes.Number,
+        required: true,
+        min: 0,
+        max: 10,
+        default: 0
+    },
+    flair: {
+        type: mongoose.SchemaTypes.ObjectID,
+        default: null,
+        ref: "flair"
+    },
+    //Not re-using the site-wide schema because post/pre save should call different functions
+    emotes: [{
+        name:{
+            type: mongoose.SchemaTypes.String,
+            required: true
+        },
+        link:{
+            type: mongoose.SchemaTypes.String,
+            required: true
+        },
+        type:{
+            type: mongoose.SchemaTypes.String,
+            required: true,
+            enum: emoteModel.typeEnum,
+            default: emoteModel.typeEnum[0]
+        }
+    }],
+    recentIPs: [{
+        ipHash: {
+            type: mongoose.SchemaTypes.String,
+            required: true
+        },
+        firstLog: {
+            type: mongoose.SchemaTypes.Date,
+            required: true,
+            default: new Date()
+        },
+        lastLog: {
+            type: mongoose.SchemaTypes.Date,
+            required: true,
+            default: new Date()
+        }
+    }],
+    alts:[{
+        type: mongoose.SchemaTypes.ObjectID,
+        ref: "user"
+    }],
+    playlists: [playlistSchema]
+});
+
+//This is one of those places where you really DON'T want to use an arrow function over an anonymous one!
+/**
+ * Pre-Save function for user document, handles password hashing, flair updates, emote refreshes, and kills sessions upon rank change
+ */
+userSchema.pre('save', async function (next){
+
+    //If the password was changed
+    if(this.isModified("pass")){
+        //Hash that sunnovabitch, no questions asked.
+        this.pass = hashUtil.hashPassword(this.pass);
+    }
+
+    //If the flair was changed
+    if(this.isModified("flair")){
+        //Get flair properties 
+        await this.populate('flair');
+
+        if(permissionModel.rankToNum(this.rank) < permissionModel.rankToNum(this.flair.rank)){
+            throw loggerUtils.exceptionSmith(`User '${this.user}' does not have a high enough rank for flair '${this.flair.displayName}'!`, "unauthorized");
+        }
+    }
+
+    //Ensure we don't have empty flair
+    if(this.flair == null){
+        const flairDB = await flairModel.findOne({});
+        this.flair = flairDB._id;
+    }
+
+    //If rank was changed
+    if(this.isModified("rank")){
+        //force a full log-out
+        await this.killAllSessions("Your site-wide rank has changed. Sign-in required.");
+    }
+
+    //if emotes where modified
+    if(this.isModified('emotes')){
+        //Get the active Channel object from the application side of the house
+        server.channelManager.crawlConnections(this.user, (conn)=>{
+            //Send out emotes to each one
+            conn.sendPersonalEmotes(this);
+        });
+    }
+
+    //All is good, continue on saving.
+    next();
+});
+
+/**
+ * Pre-Delete function for user accounts, drops connections and rips it self out from alt accounts
+ */
+userSchema.post('deleteOne', {document: true}, async function (){
+    //Kill any active sessions
+    await this.killAllSessions("If you're seeing this, your account has been deleted. So long, and thanks for all the fish! <3");
+
+    //Populate alts
+    await this.populate('alts');
+
+    //iterate through alts
+    for(alt in this.alts){
+        //Find the index of the alt entry for this user inside of the alt users array of alt users
+        const altIndex = this.alts[alt].alts.indexOf(this._id);
+
+        //splice the entry for this user out of the alt users array of alt users
+        this.alts[alt].alts.splice(altIndex,1);
+
+        //Save the alt user
+        await this.alts[alt].save();
+    }
+});
+
+//statics
+/**
+ * Registers a new user account with given information
+ * @param {Object} userObj - Object representing user to register, generated by the client
+ * @param {String} ip - IP Address of connection registering the account
+ */
+userSchema.statics.register = async function(userObj, ip){
+    //Pull values from user object
+    const {user, pass, passConfirm, email} = userObj;
+
+    //Check password confirmation matches
+    if(pass == passConfirm){
+        //Look for a user (case insensitive)
+        var userDB = await this.findOne({user: new RegExp(user, 'i')}); 
+
+        //If the user is found or someones trying to impersonate tokeboi
+        if(userDB || user.toLowerCase() == "tokebot"){
+            throw loggerUtils.exceptionSmith("User name/email already taken!", "validation");
+        }else{
+            //Increment the user count, pulling the id to tattoo to the user
+            const id = await statModel.incrementUserCount();
+
+            //Create user document in the database
+            const newUser = await this.create({id, user, pass});
+
+            //Tattoo the hashed IP used to register to the new user
+            await newUser.tattooIPRecord(ip);
+
+            //if we submitted an email
+            if(email != null){
+                const requestDB = await emailChangeModel.create({user: newUser._id, newEmail: email, ipHash: ip});
+
+                await mailUtil.sendAddressVerification(requestDB, newUser, email)
+            }
+        }
+    }else{
+        throw loggerUtils.exceptionSmith("Confirmation password doesn't match!", "validation");
+    }
+}
+
+/**
+ * Authenticates a username and password pair
+ * @param {String} user - Username of account to login as
+ * @param {String} pass - Password to authenticat account
+ * @param {String} failLine - Line to paste into custom error upon login failure
+ * @returns {Mongoose.Document} - User DB Document upon success
+ */
+userSchema.statics.authenticate = async function(user, pass, failLine = "Bad Username or Password."){
+    //check for missing pass
+    if(!user || !pass){
+        throw loggerUtils.exceptionSmith("Missing user/pass.", "validation");
+    }
+
+    //get the user if it exists
+    const userDB = await this.findOne({ user:  new RegExp(user, 'i')});
+
+    //if not scream and shout
+    if(!userDB){
+        badLogin();
+    }
+
+    //Check our password is correct
+    if(userDB.checkPass(pass)){
+        return userDB;
+    }else{
+        //if not scream and shout
+        badLogin();
+    }
+
+    //standardize bad login response so it's unknown which is bad for security reasons.
+    function badLogin(){
+        throw loggerUtils.exceptionSmith(failLine, "unauthorized");
+    }
+}
+
+/**
+ * Gets profile by username
+ * @param {String} user - name of user to find
+ * @param {Boolean} includeEmail - Whether or not to include email in the final result
+ * @returns {Object} A network-friendly browser-digestable Object representing a single user profile
+ */
+userSchema.statics.findProfile = async function(user, includeEmail = false){
+    //Catch null users
+    if(user == null || user.user == null){
+        return null;
+    //If someone's looking for tokebot
+    }else if(user.user.toLowerCase() == "tokebot"){
+        //fake a profile hashtable for tokebot
+        const profile = {
+            id: -420,
+            user: "Tokebot",
+            date: (await statModel.getStats()).firstLaunch,
+            tokes: await statModel.getTokeCommandCounts(),
+            tokeCount: await statModel.getTokeCount(),
+            img: "/img/johnny.png",
+            signature: "!TOKE",
+            bio: "!TOKE OR DIE!"
+        };
+
+        //return the faked profile
+        return profile;
+    }else{
+        //find user
+        const userDB = await this.findOne({user: user.user});
+        
+        //If we don't find a user just return a null profile
+        if(userDB == null){
+            return null
+        }
+
+        //return the profile
+        return userDB.getProfile(includeEmail);
+    }
+
+}
+
+/**
+ * Tattoos a single toke callout to all the users within it
+ * @param {Map} tokemap - Map containing list of users and the toke command they used to join the toke
+ */
+userSchema.statics.tattooToke = function(tokemap){
+    //For each toke, asynchronously:
+    tokemap.forEach(async (toke, user) => {
+        //get user
+        const userDB = await this.findOne({user});
+
+        //Check that the user exists (might come in handy for future treez.one integration?)
+        if(userDB != null){
+            var tokeCount = userDB.tokes.get(toke);
+
+            //if this is the first time using this toke command
+            if(tokeCount == null){
+                //set toke count to one
+                tokeCount = 1;
+            //otherwise
+            }else{
+                //increment tokecount
+                tokeCount++;
+            }
+
+            //Set the toke count for the specific command
+            userDB.tokes.set(toke, tokeCount);
+
+            //Save the user doc to the database
+            await userDB.save();
+
+            //Would rather do this inside of tokebot but then our boi would have to wait for DB or pass a nasty-looking callback function
+            //Crawl through active connections
+            server.channelManager.crawlConnections(userDB.user, (conn)=>{
+                    //Update used toke list
+                    conn.sendUsedTokes(userDB);
+            });
+        }
+    });
+}
+
+/**
+ * Acquires a list of the entire userbase
+ * @param {Boolean} fullList - Determines whether or not we're listing rank and email
+ * @returns {Array} Array of objects containing user metadata
+ */
+userSchema.statics.getUserList = async function(fullList = false){
+    var userList = [];
+    //Get all of our users
+    const users = await this.find({});
+
+    //Return empty if we don't find nuthin'
+    if(users == null){
+        return [];
+    }
+
+    //For each user
+    users.forEach((user)=>{
+        //create a user object with limited properties (safe for public consumption)
+        var userObj = {
+            id: user.id,
+            user: user.user,
+            img: user.img,
+            date: user.date
+        }
+
+        //Put together a spicier version for admins when told so (permission checks should happen before this is called)
+        if(fullList){
+            userObj.rank = user.rank,
+            userObj.email = user.email
+        }
+
+        //Add user object to list
+        userList.push(userObj);
+    });
+    
+    //return the userlist
+    return userList;
+}
+
+/**
+ * Process and Deletes Aged IP Records
+ */
+userSchema.statics.processAgedIPRecords = async function(){
+    //Pull full userlist
+    const users = await this.find({});
+
+    //Not a fan of iterating through the DB but there doesn't seem to be a way to search for a doc based on the properties of it's subdoc
+    for(let userIndex in users){
+        //Pull user record from users by index
+        const userDB = users[userIndex];
+        //For every recent ip within the user
+        for(let recordIndex in userDB.recentIPs){
+            //Pull record from recent IPs by index
+            const record = userDB.recentIPs[recordIndex];
+            //Check how long it's been since we've last seen the IP
+            const daysSinceLastUse = ((new Date() - record.lastLog) / (1000 * 60 * 60 * 24)).toFixed(1);
+
+            //If it's been more than a week
+            if(daysSinceLastUse >= 7){
+                //Splice out the IP record
+                userDB.recentIPs.splice(recordIndex, 1);
+                //No reason to wait on this since we're done with this user
+                await userDB.save();
+            }
+        }
+    }
+}
+
+
+
+//methods
+/**
+ * Checks password against a user document
+ * @param {String} pass - Password to authenticate
+ * @returns {Boolean} True if authenticated
+ */
+userSchema.methods.checkPass = function(pass){
+    return hashUtil.comparePassword(pass, this.pass)
+}
+
+/**
+ * Lists authenticated sessions for a given user document
+ * @returns {Promise} Promise containing an array of active user sessions for a given user
+ */
+userSchema.methods.getAuthenticatedSessions = async function(){
+    var returnArr = [];
+
+    //retrieve active sessions (they really need to implement this shit async already)
+    return new Promise((resolve) => {
+        server.store.all((err, sessions) => {
+            //You guys ever hear of a 'not my' problem? Fucking y33tskies lmao, better use a try/catch
+            if(err){
+                throw err;
+
+            }
+
+            //crawl through active sessions
+            sessions.forEach((session) => {
+                //Skip un-authed sessions
+                if(session.user != null){
+                    //if a session matches the current user
+                    if(session.user.id == this.id){
+                        //we return it
+                        returnArr.push(session);
+                    }
+                }
+            });
+
+            resolve(returnArr);
+        });
+    });
+
+}
+
+/**
+ * Generates a network-friendly browser-digestable profile object for a sepcific user document
+ * @param {Boolean} includeEmail - Whether or not to include the email address in the complete profile object
+ * @returns {Object} Network-Friendly Browser-Digestable object containing profile metadata
+ */
+userSchema.methods.getProfile = function(includeEmail = false){
+    //Create profile hashtable
+    const profile = {
+        id: this.id,
+        user: this.user,
+        date: this.date,
+        tokes: this.tokes,
+        tokeCount: this.getTokeCount(),
+        img: this.img,
+        signature: this.signature,
+        pronouns: this.pronouns,
+        bio: this.bio
+    };
+
+    //Include the email if we need to
+    if(includeEmail){
+        profile.email = this.email;
+    }
+
+    //return profile hashtable
+    return profile;
+}
+
+/**
+ * Gets list of profiles of alt accounts related to the given user document
+ * @returns {Array} List of alternate profiles
+ */
+userSchema.methods.getAltProfiles = async function(){
+    //Create an empty list to hold alt profiles
+    const profileList = [];
+
+    //populate the users alt list
+    await this.populate('alts');
+
+    //For every alt for the current user
+    for(let alt of this.alts){
+        //get the alts profile and push it to the profile list
+        profileList.push(alt.getProfile());
+    }
+
+    //return our generated profile list
+    return profileList;
+}
+
+/**
+ * Sets flair for current user documetn
+ * @param {String} flair - flair to set
+ * @returns {Mongoose.Document} returns found flair document from DB
+ */
+userSchema.methods.setFlair = async function(flair){
+    //Find flair by name
+    const flairDB = await flairModel.findOne({name: flair});
+    //Set the users flair ref to the found flairs _id
+    this.flair = flairDB._id;
+    //Save the user
+    await this.save();
+    //return the found flair
+    return flairDB;
+}
+
+/**
+ * Gets number of tokes for a given user document
+ * @returns {Number} Number of tokes recorded for the given user document
+ */
+userSchema.methods.getTokeCount = function(){
+    //Set tokeCount to 0
+    var tokeCount = 0;
+
+    //For each toke command the user has used
+    this.tokes.forEach((commandCount) => {
+        //Add the count for that specific command to the total
+        tokeCount += commandCount;
+    });
+
+    //Return the amount of tokes recorded
+    return tokeCount;
+}
+
+/**
+ * Gets number of emotes for a given user document
+ * @returns {Array} Array of objects representing emotes for the given user document
+ */
+userSchema.methods.getEmotes = function(){
+    //Create an empty array to hold our emote list
+    const emoteList = [];
+
+    //For each channel emote
+    this.emotes.forEach((emote) => { 
+        //Push an object with select information from the emote to the emote list
+        emoteList.push({
+            name: emote.name,
+            link: emote.link,
+            type: emote.type
+        });
+    });
+
+    //return the emote list
+    return emoteList;
+}
+
+/**
+ * Deletes an emote from the user Document
+ * @param {String} name - Name of emote to delete
+ */
+userSchema.methods.deleteEmote = async function(name){
+    //Get index by emote name
+    const emoteIndex = this.emotes.findIndex(checkName);
+
+    //Splice out found emote
+    this.emotes.splice(emoteIndex, 1);
+    
+    //Save the user doc
+    await this.save();
+
+    function checkName(emote){
+        //return emotes
+        return emote.name == name;
+    }
+}
+
+/**
+ * Gets list of user playlists
+ * @returns {Array} Array of objects represnting a playlist containing media objects
+ */
+userSchema.methods.getPlaylists = function(){
+    //Create an empty array to hold our emote list
+    const playlists = [];
+
+    //For each channel emote
+    for(let playlist of this.playlists){
+        //Push an object with select information from the emote to the emote list
+        playlists.push(playlist.dehydrate());
+    }
+
+    //return the emote list
+    return playlists;
+}
+
+/**
+ * Iterates through user playlists and calls a given callback function against them
+ * @param {Function} cb - Callback function to call against user playlists
+ */
+userSchema.methods.playlistCrawl = function(cb){
+    for(let listIndex in this.playlists){
+        //Grab the associated playlist
+        playlist = this.playlists[listIndex];
+
+        //Call the callback with the playlist and list index as arguments
+        cb(playlist, listIndex);
+    }
+}
+
+/**
+ * Returns playlist by name
+ * @param {String} name -  Playlist to get by name
+ * @returns {Object} Object representing the requested playlist
+ */
+userSchema.methods.getPlaylistByName = function(name){
+    //Create null value to hold our found playlist
+    let foundPlaylist = null;
+
+    //Crawl through active playlists
+    this.playlistCrawl((playlist, listIndex) => {
+        //If we found a match based on name
+        if(playlist.name == name){
+            //Keep it
+            foundPlaylist = playlist;
+            //Pass down the list index
+            foundPlaylist.listIndex = listIndex;
+        }
+    });
+
+    //return the given playlist
+    return foundPlaylist;
+}
+
+/**
+ * Deletes a playlist from the user document by name
+ * @param {String} name - Name of playlist to delete
+ */
+userSchema.methods.deletePlaylistByName = async function(name){
+    //Find the playlist
+    const playlist = this.getPlaylistByName(name);
+
+    //splice out the given playlist
+    this.playlists.splice(playlist.listIndex, 1);
+
+    //save the channel document
+    await this.save();
+}
+
+/**
+ * Salts, Hashes and Tattoo's IP address to user document in a privacy respecting manner
+ * @param {String} ip - Plaintext IP Address to Salt, Hash and Tattoo
+ */
+userSchema.methods.tattooIPRecord = async function(ip){
+    //Hash the users ip
+    const ipHash = hashUtil.hashIP(ip);
+   
+    //Look for a pre-existing entry for this ipHash
+    const foundIndex = this.recentIPs.findIndex(checkHash);
+
+    //If there is no entry
+    if(foundIndex == -1){
+        //Pull the entire userlist
+        //TODO: update query to only pull users with recentIPs, so we aren't looping through inactive users
+        const users = await this.model().find({});
+
+        //create record object
+        const record = {
+            ipHash: ipHash,
+            firstLog: new Date(),
+            lastLog: new Date()
+        };
+
+        //We should really start using for loops and stop acting like its 2008
+        //Though to be quite honest this bit would be particularly brutal without them
+        //For every user in the userlist
+        for(let curUser of users){
+            //Ensure we're not checking the user against itself
+            if(curUser._id != this._id){
+                //For every IP record in the current user
+                for(let curRecord of curUser.recentIPs){
+                    //If it matches the current ipHash
+                    if(curRecord.ipHash == ipHash){
+                        //Check if we've already marked the user as an alt
+                        const foundAlt = this.alts.indexOf(curUser._id);
+
+                        //If these accounts aren't already marked as alts
+                        if(foundAlt == -1){
+                            //Add found user to this users alt list
+                            this.alts.push(curUser._id);
+
+                            //add this user to found users alt list
+                            curUser.alts.push(this._id);
+
+                            //Save changes to the found user, this user will save at the end of the function
+                            await curUser.save();
+                        }
+                    }
+                }
+            }
+        }
+
+        //Pop it into place
+        this.recentIPs.push(record);
+
+        //Save the user doc
+        await this.save();
+    //Otherwise, if we already have a record for this IP
+    }else{
+        //Update the last logged date for the found record
+        this.recentIPs[foundIndex].lastLog = new Date();
+        
+        //Save the user doc
+        await this.save();
+    }
+
+    //Look for matching ip record
+    function checkHash(ipRecord){
+        //return matching records
+        return ipRecord.ipHash == ipHash;
+    }
+}
+
+//note: if you gotta call this from a request authenticated by it's user, make sure to kill that session first!
+/**
+ * Kills all sessions for a given user
+ * @param {String} reason - Reason to kill user sessions
+ */
+userSchema.methods.killAllSessions = async function(reason = "A full log-out from all devices was requested for your account."){
+    //get authenticated sessions
+    var sessions = await this.getAuthenticatedSessions();
+
+    //crawl through and kill all sessions
+    sessions.forEach((session) => {
+        server.store.destroy(session.seshid);
+    });
+
+    //Tell the application side of the house to kick the user out as well
+    server.channelManager.kickConnections(this.user, reason);
+}
+
+/**
+ * Changes password for a given user document 
+ * @param {Object} passChange - passChange object handed down from Browser
+ */
+userSchema.methods.changePassword = async function(passChange){
+    if(this.checkPass(passChange.oldPass)){
+        if(passChange.newPass == passChange.confirmPass){
+            //Note: We don't have to worry about hashing here because the schema is written to do it auto-magically
+            this.pass = passChange.newPass;
+            
+            //Save our password
+            await this.save();
+
+            //Kill all authed sessions for security purposes
+            await this.killAllSessions("Your password has been reset.");
+        }else{
+            //confirmation pass doesn't match
+            throw loggerUtils.exceptionSmith("Mismatched confirmation password!", "validation");
+        }
+    }else{
+        //Old password wrong
+        throw loggerUtils.exceptionSmith("Incorrect Password!", "validation");
+    }
+
+}
+
+/**
+ * Checks another user document against this one to see if they're alts
+ * @param {Mongoose.Document} userDB - User document to check for alts against
+ * @returns {Boolean} True if alt
+ */
+userSchema.methods.altCheck = async function(userDB){
+    //Found alt flag
+    let foundAlt = false;
+
+    for(alt in this.alts){
+        //If we found a match
+        if(this.alts[alt]._id.toString() == userDB._id.toString()){
+            foundAlt = true;
+        }
+    }
+
+    //return the results
+    return foundAlt;
+}
+
+/**
+ * Nukes user account from the face of the planet upon said user's request
+ * @param {String} pass - Password to authenticate against before deleting
+ */
+userSchema.methods.nuke = async function(pass){
+    //Check we have a confirmation password
+    if(pass == "" || pass == null){
+        //scream and shout
+        throw loggerUtils.exceptionSmith("No confirmation password!", "validation");
+    }
+
+    //Check that the password is correct
+    if(this.checkPass(pass)){
+        //delete the user
+        var oldUser = await this.deleteOne();
+    }else{
+        //complain about a bad pass
+        throw loggerUtils.exceptionSmith("Bad pass.", "unauthorized");
+    }
+}
+
+module.exports.userModel = mongoose.model("user", userSchema);
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/www/doc/scripts/linenumber.js b/www/doc/scripts/linenumber.js new file mode 100644 index 0000000..4354785 --- /dev/null +++ b/www/doc/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(() => { + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/www/doc/scripts/prettify/Apache-License-2.0.txt b/www/doc/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/www/doc/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/www/doc/scripts/prettify/lang-css.js b/www/doc/scripts/prettify/lang-css.js new file mode 100644 index 0000000..041e1f5 --- /dev/null +++ b/www/doc/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/www/doc/scripts/prettify/prettify.js b/www/doc/scripts/prettify/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/www/doc/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p th:last-child { border-right: 1px solid #ddd; } + +.ancestors, .attribs { color: #999; } +.ancestors a, .attribs a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { margin-top: 14px; border-left: 2px solid #DDD; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D4E53; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/www/doc/styles/prettify-jsdoc.css b/www/doc/styles/prettify-jsdoc.css new file mode 100644 index 0000000..5a2526e --- /dev/null +++ b/www/doc/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/www/doc/styles/prettify-tomorrow.css b/www/doc/styles/prettify-tomorrow.css new file mode 100644 index 0000000..b6f92a7 --- /dev/null +++ b/www/doc/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/www/doc/utils_altchaUtils.js.html b/www/doc/utils_altchaUtils.js.html new file mode 100644 index 0000000..827d344 --- /dev/null +++ b/www/doc/utils_altchaUtils.js.html @@ -0,0 +1,127 @@ + + + + + JSDoc: Source: utils/altchaUtils.js + + + + + + + + + + +
+ +

Source: utils/altchaUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Config
+const config = require('../../config.json');
+
+//NPM imports
+const { createChallenge, verifySolution } = require('altcha-lib');
+
+/**
+ * Create empty array to hold cache of spent payloads to protect against replay attacks
+ */
+const spent = [];
+/**
+ * Captcha lifetime in minutes
+ */
+const lifetime = 2;
+
+/**
+ * Generates captcha challenges to send down to the browser
+ * @param {Number} difficulty - Challange Difficulty (x100K internally)
+ * @param {String} uniqueSecret - Secret to salt the challange hash with
+ * @returns {String} Altcha Challenge hash
+ */
+module.exports.genCaptcha = async function(difficulty = 2, uniqueSecret = ''){
+    //Set altcha expiration date
+    const expiration = new Date();
+
+    //Add four minutes
+    expiration.setMinutes(expiration.getMinutes() + lifetime);
+
+    //Generate Altcha Challenge
+    return await createChallenge({
+        hmacKey: [config.altchaSecret, uniqueSecret].join(''),
+        maxNumber: 100000 * difficulty,
+        expires: expiration
+    });
+}
+
+/**
+ * Verifies completed altcha challenges handed over from the user
+ * @param {String} payload - Completed Altcha Payload
+ * @param {String} uniqueSecret - Server-side Unique Secret to verify payload came from server-generated challenge
+ * @returns {boolean} True if payload is a valid and unique altcha challenge which originated from this server
+ */
+module.exports.verify = async function(payload, uniqueSecret = ''){
+    //If this payload is already spent
+    if(spent.indexOf(payload) != -1){
+        //Fuck off and die
+        return false;
+    }
+
+    //Get length before pushing payload to get index of next item
+    const payloadIndex = spent.length;
+
+    //Add payload to cache of spent payloades
+    spent.push(payload);
+
+    //Set timeout to splice out the used payload after its expired so we're not filling RAM with expired payloads that aren't going to resolve true anyways
+    setTimeout(() => {spent.splice(payloadIndex,1);}, lifetime * 60 * 1000);
+
+    //Return verification results
+    return await verifySolution(payload, [config.altchaSecret, uniqueSecret].join(''));
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_configCheck.js.html b/www/doc/utils_configCheck.js.html new file mode 100644 index 0000000..93fea81 --- /dev/null +++ b/www/doc/utils_configCheck.js.html @@ -0,0 +1,117 @@ + + + + + JSDoc: Source: utils/configCheck.js + + + + + + + + + + +
+ +

Source: utils/configCheck.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Config
+const config = require('../../config.json');
+
+//Local
+const loggerUtil = require('./loggerUtils');
+
+//NPM Imports
+const validator = require('validator');//We need validators for express-less code too!
+
+/**
+ * Basic security check which runs on startup.
+ * Warns server admin against unsafe config options.
+ */
+module.exports.securityCheck = function(){
+    //Check Protocol
+    if(config.protocol.toLowerCase() != 'https'){
+        //If it's insecure then warn the admin
+        loggerUtil.consoleWarn("Starting in HTTP mode. This server should be used for development purposes only!");
+    }
+
+    //Check mail protocol
+    if(!config.mail.secure){
+        //If it's insecure then warn the admin
+        loggerUtil.consoleWarn("Mail transport security disabled! This server should be used for development purposes only!");
+    }
+
+    //check session secret
+    if(!validator.isStrongPassword(config.sessionSecret) || config.sessionSecret == "CHANGE_ME"){
+        loggerUtil.consoleWarn("Insecure Session Secret! Change Session Secret!");
+    }
+
+    //check altcha secret
+    if(!validator.isStrongPassword(config.altchaSecret) || config.altchaSecret == "CHANGE_ME"){
+        loggerUtil.consoleWarn("Insecure Altcha Secret! Change Altcha Secret!");
+    }
+
+    //check ipHash secret
+    if(!validator.isStrongPassword(config.ipSecret) || config.ipSecret == "CHANGE_ME"){
+        loggerUtil.consoleWarn("Insecure IP Hashing Secret! Change IP Hashing Secret!");
+    }
+
+    //check DB pass
+    if(!validator.isStrongPassword(config.db.pass) || config.db.pass == "CHANGE_ME" || config.db.pass == config.db.user){
+        loggerUtil.consoleWarn("Insecure Database Password! Change Database password!");
+    }
+
+    //check email pass
+    if(!validator.isStrongPassword(config.mail.pass) || config.mail.pass == "CHANGE_ME"){
+        loggerUtil.consoleWarn("Insecure Email Password! Change Email password!");
+    }
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_hashUtils.js.html b/www/doc/utils_hashUtils.js.html new file mode 100644 index 0000000..21dcb02 --- /dev/null +++ b/www/doc/utils_hashUtils.js.html @@ -0,0 +1,112 @@ + + + + + JSDoc: Source: utils/hashUtils.js + + + + + + + + + + +
+ +

Source: utils/hashUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Config
+const config = require('../../config.json');
+
+//Node Imports
+const crypto = require('node:crypto');
+
+//NPM Imports
+const bcrypt = require('bcrypt');
+
+/**
+ * Sitewide function for hashing passwords
+ * @param {String} pass - Password to hash
+ * @returns {String} Hashed/Salted password
+ */
+module.exports.hashPassword = function(pass){
+    const salt = bcrypt.genSaltSync();
+    return bcrypt.hashSync(pass, salt);
+}
+
+/**
+ * Sitewide password for authenticating/comparing passwords agianst hashes
+ * @param {String} pass - Plaintext Password
+ * @param {String} hash - Salty Hash
+ * @returns {Boolean} True if authentication success
+ */
+module.exports.comparePassword = function(pass, hash){
+    return bcrypt.compareSync(pass, hash);
+}
+
+/**
+ * Site-wide IP hashing/salting function
+ * 
+ * Provides a basic level of privacy by only logging salted hashes of IP's
+ * @param {String} ip - IP to hash
+ * @returns {String} Hashed/Salted IP Adress
+ */
+module.exports.hashIP = function(ip){
+    //Create hash object
+    const hashObj = crypto.createHash('md5');
+
+    //add IP and salt to the hash
+    hashObj.update(`${ip}${config.ipSecret}`);
+
+    //return the IP hash as a string
+    return hashObj.digest('hex');
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_linkUtils.js.html b/www/doc/utils_linkUtils.js.html new file mode 100644 index 0000000..baff084 --- /dev/null +++ b/www/doc/utils_linkUtils.js.html @@ -0,0 +1,155 @@ + + + + + JSDoc: Source: utils/linkUtils.js + + + + + + + + + + +
+ +

Source: utils/linkUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const validator = require('validator');//No express here, so regular validator it is!
+
+//Create link cache
+/**
+ * Basic RAM-Based cache of links, so we don't have to re-pull things after we get them
+ */
+module.exports.cache = new Map();
+
+/**
+ * Validates links and returns a marked link object that can be returned to the client to format/embed accordingly
+ * @param {String} link - URL to Validate
+ * @returns {Object} Marked link object
+ */
+module.exports.markLink = async function(link){
+    //Check link cache for the requested link
+    const cachedLink = module.exports.cache.get(link);
+
+    //If we have a cached result
+    if(cachedLink){
+        //return the cached link
+        return cachedLink;
+    }
+
+    //Set max file size to 4MB
+    const maxSize = 4000000;
+    //Assume links are guilty until proven innocent
+    var type = "malformedLink"    
+
+    //Make sure we have an actual, factual URL
+    if(validator.isURL(link)){
+        //The URL is valid, so this is at least a dead link
+        type = 'deadLink';
+
+        //Don't try this at home, we're what you call "Experts"
+        //TODO: Handle this shit simultaneously and send the chat before its done, then send updated types for each link as they're pulled individually
+        try{
+            //Pull content type
+            var response = await fetch(link,{
+                method: "HEAD",
+            });
+
+            //If we made it this far then the link is, at the very least, not dead.
+            type = 'link'
+
+            //Get file type from header
+            const fileType = response.headers.get('content-type');
+            const fileSize = response.headers.get('content-length');
+
+            //If they're reporting file types
+            if(fileType != null){
+                //If we have an image
+                if(fileType.match('image/')){
+                    //If the file size is unreported OR it's smaller than 4MB (not all servers report this and images that big are pretty rare)
+                    if(fileSize == null || fileSize <= maxSize){
+                        //Mark link as an image
+                        type = 'image';
+                    }
+                //If it's a video
+                }else if(fileType.match('video/mp4' || 'video/webm')){
+                    //If the server is reporting file-size and it's reporting under 4MB (Reject unreported sizes to be on the safe side is video is huge)
+                    if(fileSize != null && fileSize <= maxSize){
+                        //mark link as a video
+                        type = 'video';
+                    }
+                }
+            }
+        //Probably bad form but if something happens in here I'm blaming whoever hosted the link
+        //maybe don't host a fucked up server and I wouldn't handle with an empty catch
+        }catch{};
+    }
+
+    //Create the link object from processed information
+    const linkObj = {
+        link,
+        type
+    }
+
+    //Cache the result
+    module.exports.cache.set(link, linkObj);
+
+    //Set timer to remove cache entry in five minutes
+    setTimeout(()=>{
+        module.exports.cache.delete(link);
+    }, 300000)
+
+    //return the link
+    return linkObj;
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_loggerUtils.js.html b/www/doc/utils_loggerUtils.js.html new file mode 100644 index 0000000..9c85192 --- /dev/null +++ b/www/doc/utils_loggerUtils.js.html @@ -0,0 +1,216 @@ + + + + + JSDoc: Source: utils/loggerUtils.js + + + + + + + + + + +
+ +

Source: utils/loggerUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Config
+const config = require('../../config.json');
+
+/**
+ * Creates and returns a custom exception, tagged as a 'custom' exception, using the 'custom' boolean property.
+ * This is used to denote that this error was generated on purpose, with a human readable message, that can be securely sent to the client.
+ * Unexpected exceptions should only be logged internally, however, as they may contain sensitive data.
+ * 
+ * @param {String} msg - Error message to send the client
+ * @param {String} type - Error type to send back to the client
+ * @returns {Error} The exception to smith
+ */
+module.exports.exceptionSmith = function(msg, type){
+        //Create the new error with the given message
+        const exception = new Error(msg);
+
+        //Set the error type
+        exception.type = type;
+        
+        //Mark the error as a custom error
+        exception.custom = true;
+
+        //Return the error
+        return exception;
+}
+
+/**
+ * Main error handling function
+ * @param {Express.Response} res - Response being sent out to the client who caused the issue
+ * @param {String} msg - Error message to send the client
+ * @param {String} type - Error type to send back to the client
+ * @param {Number} status - HTTP(s) Status Code to send back to the client
+ * @returns {Express.Response} If we have a usable Express Response object, return it back after it's been cashed
+ */
+module.exports.errorHandler = function(res, msg, type = "Generic", status = 400){
+        //Some controllers do things after sending headers, for those, we should remain silent
+        if(!res.headersSent){
+                res.status(status);
+                return res.send({errors: [{type, msg, date: new Date()}]});
+        }
+}
+
+/**
+ * Handles local exceptions which where not directly created by user interaction
+ * @param {Error} err - Exception to handle
+ */
+module.exports.localExceptionHandler = function(err){
+        //If we're being verbose
+        if(config.verbose){
+                //Log the error
+                console.log(err)
+        }
+}
+
+/**
+ * Handles exceptions which where directly the fault of user action >:(
+ * @param {Express.Response} res - Express Response object to bitch at
+ * @param {Error} err - Error created by the jerk in question
+ */
+module.exports.exceptionHandler = function(res, err){
+        //If this is a self-made problem
+        if(err.custom){
+                module.exports.errorHandler(res, err.message, err.type);
+        }else{
+                //Locally handle the exception
+                module.exports.localExceptionHandler(err);
+
+                //if not yell at the browser for fucking up, and tell it what it did wrong.
+                module.exports.errorHandler(res, "An unexpected server crash was just prevented. You should probably report this to an admin.", "Caught Exception");
+        }
+}
+
+/**
+ * Basic error-handling for socket.io so we don't just silently swallow errors.
+ * @param {Socket} socket - Socket error originated from
+ * @param {String} msg - Error message to send the client
+ * @param {String} type - Error type to send back to the client
+ * @returns {Boolean} - Passthrough from socket.emit
+ */
+module.exports.socketErrorHandler = function(socket, msg, type = "Generic"){
+        return socket.emit("error", {errors: [{type, msg, date: new Date()}]});
+}
+
+/**
+ * Generates error messages for simple errors generated by socket.io interaction
+ * @param {Socket} socket - Socket error originated from
+ * @param {Error} err - Error created by the jerk in question
+ * @returns {Boolean} - Passthrough from socket.emit
+ */
+module.exports.socketExceptionHandler = function(socket, err){
+        //If this is a self made problem
+        if(err.custom){
+                //yell at the browser for fucking up, and tell it what it did wrong.
+                return module.exports.socketErrorHandler(socket, err.message, err.type);
+        }else{
+                //Locally handle the exception
+                module.exports.localExceptionHandler(err);
+
+                //if not yell at the browser for fucking up
+                return module.exports.socketErrorHandler(socket, "An unexpected server crash was just prevented. You should probably report this to an admin.", "Server");
+        }
+}
+
+/**
+ * Generates error messages and drops connection for critical errors caused by socket.io interaction
+ * @param {Socket} socket - Socket error originated from
+ * @param {Error} err - Error created by the jerk in question
+ * @returns {Boolean} - Passthrough from socket.disconnect
+ */
+module.exports.socketCriticalExceptionHandler = function(socket, err){
+        //If this is a self made problem
+        if(err.custom){
+                //yell at the browser for fucking up, and tell it what it did wrong.
+                socket.emit("kick", {type: "Disconnected", reason: `Server Error: ${err.message}`});
+        }else{
+                //Locally handle the exception
+                module.exports.localExceptionHandler(err);
+
+                //yell at the browser for fucking up
+                socket.emit("kick", {type: "Disconnected", reason: "An unexpected server crash was just prevented. You should probably report this to an admin."});
+        }
+        return socket.disconnect();
+}
+
+/**
+ * Prints warning text to server console
+ * @param {String} string - String to print to console
+ */
+module.exports.consoleWarn = function(string){
+        console.warn('\x1b[31m\x1b[4m%s\x1b[0m',string);
+}
+
+/**
+ * Basic error-handling middleware to ensure we're not dumping stack traces to the client, as that would be insecure
+ * @param {Error} err - Error to handle
+ * @param {Express.Request} req - Express Request
+ * @param {Express.Response} res - Express Response
+ * @param {Function} next - Next function in the Express middleware chain (Not that it's getting called XP)
+ */
+module.exports.errorMiddleware = function(err, req, res, next){
+        //Set generic error
+        var reason = "Server Error";
+
+        //If it's un-authorized
+        if(err.status == 403){
+                reason = "Unauthorized"
+        }
+
+        module.exports.errorHandler(res, err.message, reason, err.status);
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_mailUtils.js.html b/www/doc/utils_mailUtils.js.html new file mode 100644 index 0000000..38d831e --- /dev/null +++ b/www/doc/utils_mailUtils.js.html @@ -0,0 +1,149 @@ + + + + + JSDoc: Source: utils/mailUtils.js + + + + + + + + + + +
+ +

Source: utils/mailUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Config
+const config = require('../../config.json');
+
+//NPM imports
+const nodeMailer = require("nodemailer");
+
+//Setup mail transport
+/**
+ * nodemailer transport object, generated from options specific in our config file
+ */
+const transporter = nodeMailer.createTransport({
+    host: config.mail.host,
+    port: config.mail.port,
+    secure: config.mail.secure,
+    auth: {
+        user: config.mail.address,
+        pass: config.mail.pass
+    }
+});
+
+/**
+ * Sends an email as tokebot to the requested user w/ the requested body and signature
+ * @param {String} to - String containing the email address to send to
+ * @param {String} subject - Subject line of the email to send
+ * @param {String} body - Body contents, either HTML or Plaintext
+ * @param {Boolean} htmlBody - Whether or not Body contents should be sent as HTML or Plaintext
+ * @returns {Object} Sent mail info
+ */
+module.exports.mailem = async function(to, subject, body, htmlBody = false){
+    //Create mail object
+    const mailObj = {
+        from: `"Tokebot🤖💨"<${config.mail.address}>`,
+        to,
+        subject
+    };
+
+    //If we're sending HTML
+    if(htmlBody){
+        //set body as html
+        mailObj.html = body;
+    //If we're sending plaintext
+    }else{
+        //Set body as plaintext
+        mailObj.text = body
+    }
+
+    //Send mail based on mail object
+    const sentMail = await transporter.sendMail(mailObj);
+
+    //return the mail info
+    return sentMail;
+}
+
+/**
+ * Sends address verification email
+ * @param {Mongoose.Document} requestDB - DB Document Object for the current email change request token
+ * @param {Mongoose.Document} userDB - DB Document Object for the user we're verifying email against
+ * @param {String} newEmail - New email address to send to
+ */
+module.exports.sendAddressVerification = async function(requestDB, userDB, newEmail){
+    //Send the reset url via email
+    await module.exports.mailem(
+        newEmail,
+        `Email Change Request - ${userDB.user}`,
+        `<h1>Email Change Request</h1>
+        <p>A request to change the email associated with the ${config.instanceName} account '${userDB.user}' to this address has been requested.<br>
+        <a href="${requestDB.getChangeURL()}">Click here</a> to confirm this change.</p>
+        <sup>If you received this email without request, feel free to ignore and delete it! -Tokebot</sup>`,
+        true
+    );
+
+    //If the user has a pre-existing email address
+    if(userDB.email != null && userDB.email != ""){
+        await module.exports.mailem(
+            userDB.email,
+            `Email Change Request - ${userDB.user}`,
+            `<h1>Email Change Request Notification</h1>
+            <p>A request to change the email associated with the ${config.instanceName} account '${userDB.user}' to another address has been requested.<br>
+            <sup>If you received this email without request, you should <strong>immediately</strong> change your password and contact the server adminsitrator! -Tokebot</sup>`,
+            true
+        );
+    }
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_media_internetArchiveUtils.js.html b/www/doc/utils_media_internetArchiveUtils.js.html new file mode 100644 index 0000000..be4210f --- /dev/null +++ b/www/doc/utils_media_internetArchiveUtils.js.html @@ -0,0 +1,163 @@ + + + + + JSDoc: Source: utils/media/internetArchiveUtils.js + + + + + + + + + + +
+ +

Source: utils/media/internetArchiveUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Node Imports
+const validator = require('validator');
+
+//Local Imports
+const media = require('../../app/channel/media/media.js');
+const regexUtils = require('../regexUtils.js');
+const loggerUtils = require('../loggerUtils.js')
+
+/**
+ * Pulls metadate for a given archive.org item
+ * @param {String} fullID - Full path of the requested upload
+ * @param {String} title - Title to add to media object
+ * @returns {Array} Generated list of media objects from given upload path
+ */
+module.exports.fetchMetadata = async function(fullID, title){
+    //Split fullID by first slash
+    const [itemID, requestedPath] = decodeURIComponent(fullID).split(/\/(.*)/);
+    //Create empty list to hold media objects
+    const mediaList = [];
+    //Create empty variable to hold return data object
+    let data;
+
+    //Create metadata link from itemID
+    const metadataLink = `https://archive.org/metadata/${itemID}`;
+
+    //Fetch item metadata from the internet archive
+    const response = await fetch(metadataLink,
+        {
+            method: "GET"
+        }
+    );
+
+    //If we hit a snag
+    if(!response.ok){
+        //Scream and shout
+        const errorBody = await response.text();
+        throw loggerUtils.exceptionSmith(`Internet Archive Error '${response.status}': ${errorBody}`, "queue");
+    }
+
+    //Collect our metadata
+    const rawMetadata = await response.json();
+
+    //Filter out any in-compatible files
+    const compatibleFiles = rawMetadata.files.filter(compatibilityFilter);
+
+
+    //If we're requesting an empty path
+    if(requestedPath == '' || requestedPath == null){
+        //Return item metadata and compatible files
+        data = {
+                files: compatibleFiles,
+                metadata: rawMetadata.metadata
+        }
+    //Other wise
+    }else{
+        //Return item metadata and matching compatible files
+        data = {
+            //Filter files out that don't match requested path and return remaining list
+            files: compatibleFiles.filter(pathFilter),
+            metadata: rawMetadata.metadata
+        }
+    }
+
+    //for every compatible and relevant file returned from IA
+    for(let file of data.files){
+        //Split file path by directories
+        const path = file.name.split('/');
+
+        //pull filename from path and escape in-case someone put something nasty in there
+        const name = validator.escape(validator.trim(path[path.length - 1]));
+
+        //Construct link from pulled info
+        const link = `https://archive.org/download/${data.metadata.identifier}/${file.name}`;
+
+        //if we where handed a null title
+        if(title == null || title == ''){
+            //Create new media object from file info substituting filename for title
+            mediaList.push(new media(name, name, link, link, 'ia', Number(file.length)));
+        }else{
+            //Create new media object from file info
+            mediaList.push(new media(title, name, link, link, 'ia', Number(file.length)));
+        }
+    }
+
+    //return media object list
+    return mediaList;
+
+    function compatibilityFilter(file){
+        //return true for all files that match for web-safe formats
+        return file.format == "h.264 IA" || file.format == "h.264" || file.format == "Ogg Video" || file.format.match("MPEG4");
+    }
+
+    function pathFilter(file){
+        //return true for all file names which match the given requested file path
+        return file.name.match(`^${regexUtils.escapeRegex(requestedPath)}`);
+    }
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_media_yanker.js.html b/www/doc/utils_media_yanker.js.html new file mode 100644 index 0000000..e070b5d --- /dev/null +++ b/www/doc/utils_media_yanker.js.html @@ -0,0 +1,202 @@ + + + + + JSDoc: Source: utils/media/yanker.js + + + + + + + + + + +
+ +

Source: utils/media/yanker.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+//const url = require("node:url");
+const validator = require('validator');//No express here, so regular validator it is!
+
+//local import
+const iaUtil = require('./internetArchiveUtils');
+const ytdlpUtil = require('./ytdlpUtils');
+
+/**
+ * Checks a given URL and runs the proper metadata fetching function to create a media object from any supported URL
+ * @param {String} url - URL to yank media against
+ * @param {String} title - Title to apply to yanked media
+ * @returns {Array} Returns list of yanked media objects on success
+ */
+module.exports.yankMedia = async function(url, title){
+    //Get pull type
+    const pullType = await this.getMediaType(url);
+
+    //Check pull type
+    switch(pullType.type){
+        case "ia":
+            //return media object list from IA module
+            return await iaUtil.fetchMetadata(pullType.id, title); 
+        case "yt":
+            //return media object list from the YT-DLP module's youtube function
+            return await ytdlpUtil.fetchYoutubeMetadata(pullType.id, title);
+        case "ytp":
+            //return media object list from YT-DLP module's youtube playlist function
+            //return await ytdlpUtil.fetchYoutubePlaylistMetadata(pullType.id, title);
+            //Holding off on this since YT-DLP takes 10 years to do a playlist as it needs to pull each and every video one-by-one
+            //Maybe in the future a piped alternative might be in order, however this would most likely require us to host our own local instance.
+            //Though it could give us added resistance against youtube/google's rolling IP bans
+            return null;
+        case "dm":
+            //return mediao object list from the YT-DLP module's dailymotion function
+            return await ytdlpUtil.fetchDailymotionMetadata(pullType.id, title);
+        default:
+            //return null to signify a bad url
+            return null;
+    }
+}
+
+/**
+ * Refreshes raw links on relevant media objects
+ * 
+ * Useful for sources like youtube, who only provide expiring raw links
+ * @param {ScheduledMedia} mediaObj - Media Object to refresh
+ * @returns {ScheduledMedia} Refreshed media object
+ */
+module.exports.refreshRawLink = async function(mediaObj){
+    switch(mediaObj.type){
+        case 'yt':
+            //Scrape expiration from query strings
+            const expires = mediaObj.rawLink.match(/expire=([0-9]+)/); 
+            //Went with regex for speed, but I figure I'd keep this around in case we want the accuracy of a battle-tested implementation
+            //const expires = new URL(mediaObj.rawLink).searchParams.get("expire");
+
+            //If we have a valid raw file link that will be good by the end of the video
+            if(expires != null && (expires * 1000) > mediaObj.getEndTime()){
+                //Return null to tell the calling function there is no refresh required for this video at this time
+                return null;
+            }
+
+            //Re-fetch media metadata
+            metadata = await ytdlpUtil.fetchYoutubeMetadata(mediaObj.id);
+            //Refresh media rawlink from metadata
+            mediaObj.rawLink = metadata[0].rawLink;
+
+            //return media object
+            return mediaObj;
+    }
+
+    //Return null to tell the calling function there is no refresh required for this media type
+    return null;
+}
+/**
+ * Detects media type by URL
+ * 
+ * I'd be lying if this didn't take at least some inspiration/regex patterns from extractQueryParam() in cytube/forest's browser-side 'util.js'
+ * Still this has some improvements like url pre-checks and the fact that it's handled serverside, recuing possibility of bad requests.
+ * Some of the regex expressions for certain services have also been improved, such as youtube, and the fore.st-unique archive.org
+ * 
+ * @param {String} url - URL to determine media type of
+ * @returns {Object} containing URL type and clipped ID string
+ */
+module.exports.getMediaType = async function(url){
+    //Check if we have a valid url, encode it on the fly in case it's too humie-friendly
+    if(!validator.isURL(encodeURI(url))){
+        //If not toss the fucker out
+        return {
+            type: null,
+            id: null
+        }
+    }
+    
+    //If we have link to a resource from archive.org
+    if(match = url.match(/archive\.org\/(?:details|download)\/([a-zA-Z0-9\/._-\s\%]+)/)){
+        //return internet archive upload id and filepath
+        return {
+            type: "ia",
+            id: match[1]
+        }
+    }
+
+    //If we have a match to a youtube video
+    if((match = url.match(/youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})/)) || (match = url.match(/youtu\.be\/([a-zA-Z0-9_-]{11})/))){
+        //return youtube video id
+        return {
+            type: "yt",
+            id: match[1]
+        }
+    }
+
+    //If we have a match to a youtube playlist
+    if((match = url.match(/youtube\.com\/playlist\?list=([a-zA-Z0-9_-]{34})/)) || (match = url.match(/youtu\.be\/playlist\?list=([a-zA-Z0-9_-]{34})/))){
+        //return youtube playlist id
+        return {
+            type: "ytp",
+            id: match[1]
+        }
+    }
+
+    //If we have a match to a dailymotion video
+    if(match = url.match(/dailymotion\.com\/video\/([a-zA-Z0-9]+)/)){
+        return {
+            type: "dm",
+            id: match[1]
+        }
+    }
+
+    //If we fell through all of our media types without a match
+    return{
+        type: null,
+        id: null
+    }
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_media_ytdlpUtils.js.html b/www/doc/utils_media_ytdlpUtils.js.html new file mode 100644 index 0000000..460ede2 --- /dev/null +++ b/www/doc/utils_media_ytdlpUtils.js.html @@ -0,0 +1,195 @@ + + + + + JSDoc: Source: utils/media/ytdlpUtils.js + + + + + + + + + + +
+ +

Source: utils/media/ytdlpUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Config
+const config = require('../../../config.json');
+
+//Node Imports
+const { create: ytdlpMaker } = require('youtube-dl-exec');
+//Import ytdlp w/ custom path from config so we can force the newest build of yt-dlp from pip
+const ytdlp = ytdlpMaker(config.ytdlpPath);
+const url = require("node:url");
+const validator = require('validator');
+
+//Local Imports
+const media = require('../../app/channel/media/media.js');
+const regexUtils = require('../regexUtils.js');
+const loggerUtils = require('../loggerUtils.js')
+
+/**
+ * Pulls metadata for a single youtube video via YT-DLP
+ * @param {String} id - Youtube Video ID
+ * @param {String} title - Title to add to the given media object
+ * @returns {Media} Media object containing relevant metadata
+ */
+module.exports.fetchYoutubeMetadata = async function(id, title){
+    try{
+        //Try to pull media from youtube id
+        const media = await fetchVideoMetadata(`https://youtu.be/${id}`, title, 'yt');
+
+        //Return found media
+        return media;
+    //If something went wrong
+    }catch(err){
+        //If our IP was banned by youtube
+        if(err.message.match("Sign in to confirm you’re not a bot.")){
+            //Make our own error with blackjack and hookers
+            throw loggerUtils.exceptionSmith("The server's IP address has been banned by youtube. Please contact your server's administrator.", "queue");
+        //Otherwise if we don't have a good way to handle it
+        }else{
+            //toss it back up
+            throw err;
+        }
+    }
+}
+
+/**
+ * Pulls metadata for a playlist of youtube videos via YT-DLP
+ * @param {String} id - Youtube Playlist ID
+ * @param {String} title - Title to add to the given media objects
+ * @returns {Array} Array of  Media objects containing relevant metadata
+ */
+module.exports.fetchYoutubePlaylistMetadata = async function(id, title){
+    try{
+        //Try to pull media from youtube id
+        const media = await fetchPlaylistMetadata(`https://youtu.be/playlist?list=${id}`, title, 'yt');
+
+        //Return found media
+        return media;
+    //If something went wrong
+    }catch(err){
+        //If our IP was banned by youtube
+        if(err.message.match("Sign in to confirm you’re not a bot.")){
+            //Make our own error with blackjack and hookers
+            throw loggerUtils.exceptionSmith("The server's IP address has been banned by youtube. Please contact your server's administrator.", "queue");
+        //Otherwise if we don't have a good way to handle it
+        }else{
+            //toss it back up
+            throw err;
+        }
+    }
+}
+
+/* This requires HLS embeds which, in-turn, require daily motion to add us to their CORS exception list
+ * Not gonna happen, so we need to use their API for this, or proxy the video
+module.exports.fetchDailymotionMetadata = async function(id, title){
+    //Pull media from dailymotion link
+    const media = await fetchVideoMetadata(`https://dailymotion.com/video/${id}`, title, 'dm');
+
+    //Return found media;
+    return media;
+}*/
+
+/**
+ * Generic single video YTDLP function meant to be used by service-sepecific fetchers which will then be used to fetch video metadata
+ * @param {String} link - Link to video in question
+ * @param {String} title - Title to add to the given media objects
+ * @param {String} type - Link type to attach to the resulting media object
+ * @returns {Array} Array of  Media objects containing relevant metadata
+ */
+async function fetchVideoMetadata(link, title, type, format = 'b'){
+    //Create media list
+    const mediaList = [];    
+
+    //Pull raw metadata from YT-DLP
+    const rawMetadata = await ytdlpFetch(link, format);
+
+    //Pull data from rawMetadata, sanatizing title to prevent XSS
+    const name = validator.escape(validator.trim(rawMetadata.title));
+    const rawLink = rawMetadata.requested_downloads[0].url;
+    const id = rawMetadata.id;
+
+    //if we where handed a null title
+    if(title == null || title == ''){
+        //Create new media object from file info substituting filename for title
+        mediaList.push(new media(name, name, link, id, type, Number(rawMetadata.duration), rawLink));
+    }else{
+        //Create new media object from file info
+        mediaList.push(new media(title, name, link, id, type, Number(rawMetadata.duration), rawLink));
+    }
+
+    //Return list of media
+    return mediaList;
+}
+
+//YT-DLP takes forever to handle playlists, we'll handle this via piped in the future perhaps
+/*async function fetchPlaylistMetadata(link, title, type, format = 'b'){
+}*/
+
+//Wrapper function for YT-DLP NPM package with pre-set cli-flags
+/**
+ * Basic async YT-DLP Fetch wrapper, ensuring config
+ * @param {String} link - Link to fetch using YT-DLP
+ * @param {String} format - Format string to hand YT-DLP, defaults to 'b'
+ * @returns {Object} Metadata dump from YT-DLP
+ */
+async function ytdlpFetch(link, format = 'b'){
+    //return promise from ytdlp
+    return ytdlp(link, {
+        dumpSingleJson: true,
+        format
+    });
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_regexUtils.js.html b/www/doc/utils_regexUtils.js.html new file mode 100644 index 0000000..53407f9 --- /dev/null +++ b/www/doc/utils_regexUtils.js.html @@ -0,0 +1,78 @@ + + + + + JSDoc: Source: utils/regexUtils.js + + + + + + + + + + +
+ +

Source: utils/regexUtils.js

+ + + + + + +
+
+
 /*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/   
+
+/**
+ * I won't lie this line was whole-sale ganked from stack overflow like a fucking skid
+ * In my defense I only did it because js-runtime-devs are taking fucking eons to implement RegExp.escape()
+ * This should be replaced once that function becomes available in mainline versions of node.js:
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/escape
+ * 
+ * @param {String} string - Regex string to escape
+ * @returns {String} The Escaped String
+ */
+module.exports.escapeRegex = function(string){
+    return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_scheduler.js.html b/www/doc/utils_scheduler.js.html new file mode 100644 index 0000000..ad2f750 --- /dev/null +++ b/www/doc/utils_scheduler.js.html @@ -0,0 +1,114 @@ + + + + + JSDoc: Source: utils/scheduler.js + + + + + + + + + + +
+ +

Source: utils/scheduler.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//NPM Imports
+const cron = require('node-cron');
+
+//Local Imports
+const {userModel} = require('../schemas/user/userSchema');
+const userBanModel = require('../schemas/user/userBanSchema');
+const passwordResetModel = require('../schemas/user/passwordResetSchema');
+const emailChangeModel = require('../schemas/user/emailChangeSchema');
+const channelModel = require('../schemas/channel/channelSchema');
+const sessionUtils = require('./sessionUtils');
+const { email } = require('../validators/accountValidator');
+
+/**
+ * Schedules all timed jobs accross the server
+ */
+module.exports.schedule = function(){
+    //Process hashed IP Records that haven't been recorded in a week or more
+    cron.schedule('0 0 * * *', ()=>{userModel.processAgedIPRecords()},{scheduled: true, timezone: "UTC"});
+    //Process expired global bans every night at midnight
+    cron.schedule('0 0 * * *', ()=>{userBanModel.processExpiredBans()},{scheduled: true, timezone: "UTC"});
+    //Process expired channel bans every night at midnight
+    cron.schedule('0 0 * * *', ()=>{channelModel.processExpiredBans()},{scheduled: true, timezone: "UTC"});
+    //Process expired failed login attempts every night at midnight
+    cron.schedule('0 0 * * *', ()=>{sessionUtils.processExpiredAttempts()},{scheduled: true, timezone: "UTC"});
+    //Process expired password reset requests every night at midnight
+    cron.schedule('0 0 * * *', ()=>{passwordResetModel.processExpiredRequests()},{scheduled: true, timezone: "UTC"});
+    //Process expired email change requests every night at midnight
+    cron.schedule('0 0 * * *', ()=>{emailChangeModel.processExpiredRequests()},{scheduled: true, timezone: "UTC"});
+}
+
+/**
+ * Kicks off first run of scheduled functions before scheduling functions for regular callback
+ */
+module.exports.kickoff = function(){
+    //Process Hashed IP Records that haven't been recorded in a week or more
+    userModel.processAgedIPRecords();
+    //Process expired global bans that may have expired since last restart
+    userBanModel.processExpiredBans();
+    //Process expired channel bans that may have expired since last restart
+    channelModel.processExpiredBans();
+    //Process expired password reset requests that may have expired since last restart
+    passwordResetModel.processExpiredRequests();
+    //Process expired email change requests that may have expired since last restart
+    emailChangeModel.processExpiredRequests();
+
+    //Schedule jobs
+    module.exports.schedule();
+}
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + + diff --git a/www/doc/utils_sessionUtils.js.html b/www/doc/utils_sessionUtils.js.html new file mode 100644 index 0000000..3b73c64 --- /dev/null +++ b/www/doc/utils_sessionUtils.js.html @@ -0,0 +1,245 @@ + + + + + JSDoc: Source: utils/sessionUtils.js + + + + + + + + + + +
+ +

Source: utils/sessionUtils.js

+ + + + + + +
+
+
/*Canopy - The next generation of stoner streaming software
+Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.*/
+
+//Local Imports
+const config = require('../../config.json');
+const {userModel} = require('../schemas/user/userSchema.js');
+const userBanModel = require('../schemas/user/userBanSchema.js')
+const altchaUtils = require('../utils/altchaUtils.js');
+const loggerUtils = require('../utils/loggerUtils.js');
+
+/**
+ * Create failed sign-in cache since it's easier and more preformant to implement it this way than adding extra burdon to the database
+ * Server restarts are far and few between. It would take multiple during a single bruteforce attempt for this to become an issue.
+ */
+const failedAttempts = new Map();
+
+/**
+ * How many failed attempts required to throttle with altcha
+ */
+const throttleAttempts = 5;
+
+/**
+ * How many attempts to lock user account out for the day
+ */
+const maxAttempts = 200;
+
+/**
+ * Sole and Singular Session Authentication method.
+ * All logins should happen through here, all other site-wide authentication should happen by sessions authenticated by this model.
+ * This is important, as reducing authentication endpoints reduces attack surface.
+ * @param {String} user - Username to login as
+ * @param {String} pass - Password to authenticat session with
+ * @param {express.Request} req - Express request object w/ session to authenticate
+ * @returns Username of authticated user upon success
+ */
+module.exports.authenticateSession = async function(user, pass, req){
+    //Fuck you yoda
+    try{
+        //Grab previous attempts
+        const attempt = failedAttempts.get(user);
+
+        //If we're proxied use passthrough IP
+        const ip = config.proxied ? req.headers['x-forwarded-for'] : req.ip;
+
+        //Look for ban by IP
+        const ipBanDB = await userBanModel.checkBanByIP(ip);
+
+        //If this ip is randy bobandy
+        if(ipBanDB != null){
+            //Make the number a little prettier despite the lack of precision since we're not doing calculations here :P
+            const expiration = ipBanDB.getDaysUntilExpiration() < 1 ? 0 : ipBanDB.getDaysUntilExpiration();
+
+            //If the ban is permanent
+            if(ipBanDB.permanent){
+                //tell it to fuck off
+                throw loggerUtils.exceptionSmith(`The IP address you are trying to login from has been permanently banned. Your cleartext IP has been saved to the database. Any associated accounts will be nuked in ${expiration} day(s).`, "unauthorized");
+            }else{
+                //tell it to fuck off
+                throw loggerUtils.exceptionSmith(`The IP address you are trying to login from has been temporarily banned. Your cleartext IP has been saved to the database until the ban expires in ${expiration} day(s).`, "unauthorized");
+            }
+        }
+
+        //If we have failed attempts
+        if(attempt != null){
+            //If we have more failed attempts than allowed
+            if(attempt.count > maxAttempts){
+                throw loggerUtils.exceptionSmith("This account has been locked for at 24 hours due to a large amount of failed log-in attempts", "unauthorized");
+            }
+
+            //If we're throttling logins
+            if(attempt.count > throttleAttempts){
+                //Verification doesnt get sanatized or checked since that would most likely break the cryptography
+                //Since we've already got access to the request and dont need to import anything, why bother getting it from a parameter?
+                if(req.body.verification == null){
+                    throw loggerUtils.exceptionSmith("Verification failed!", "unauthorized");
+                }else if(!altchaUtils.verify(req.body.verification, user)){
+                    throw loggerUtils.exceptionSmith("Verification failed!", "");
+                }
+            }
+        }
+
+        //Authenticate the session
+        const userDB = await userModel.authenticate(user, pass);
+
+        //Check for user ban
+        const userBanDB = await userBanModel.checkBanByUserDoc(userDB);
+
+        //If the user is banned
+        if(userBanDB){
+            //Make the number a little prettier despite the lack of precision since we're not doing calculations here :P
+            const expiration = userBanDB.getDaysUntilExpiration() < 1 ? 0 : userBanDB.getDaysUntilExpiration();
+            if(userBanDB.permanent){
+                throw loggerUtils.exceptionSmith(`Your account has been permanently banned, and will be nuked from the database in: ${expiration} day(s)`, "unauthorized");
+            }else{
+                throw loggerUtils.exceptionSmith(`Your account has been temporarily banned, and will be reinstated in: ${expiration} day(s)`, "unauthorized");
+            }
+        }
+
+        //Tattoo the session with user and metadata
+        //unfortunately store.all() does not return sessions w/ their ID so we had to improvise...
+        //Not sure if this is just how connect-mongo is implemented or if it's an express issue, but connect-mongodb-session seems to not implement the all() function what so ever...
+        req.session.seshid = req.session.id;
+        req.session.authdate = new Date();
+        req.session.user = {
+            user: userDB.user,
+            id: userDB.id,
+            rank: userDB.rank
+        }
+
+        //Tattoo hashed IP address to user account for seven days
+        userDB.tattooIPRecord(ip);
+
+        //If we got to here then the log-in was successful. We should clear-out any failed attempts.
+        failedAttempts.delete(user);
+
+        //return user
+        return userDB.user;
+    }catch(err){
+        //Look for previous failed attempts
+        var attempt = failedAttempts.get(user);
+
+        //If this is the first attempt
+        if(attempt == null){
+            //Create new attempt object
+            attempt = {
+                count: 1,
+                lastAttempt: new Date()
+            }
+        }else{
+            //Create updated attempt object
+            attempt = {
+                count: attempt.count + 1,
+                lastAttempt: new Date()
+            }
+        }
+
+        //Commit the failed attempt to the failed sign-in cache
+        failedAttempts.set(user, attempt);
+
+        //y33t
+        throw err;
+    }
+}
+
+/**
+ * Logs user out and destroys all server-side traces of a given session
+ * @param {express-session.session} session 
+ */
+module.exports.killSession = async function(session){
+    session.destroy();
+}
+
+/**
+ * Returns how many failed login attempts within the past day or so since the last login has occured for a given user
+ * @param {String} user - User to check map against
+ * @returns {Number} of failed login attempts
+ */
+module.exports.getLoginAttempts = function(user){
+    //Read the code, i'm not explaining this
+    return failedAttempts.get(user);
+}
+
+/**
+ * Nightly Function Call which iterates through the failed login attempts map, removing any which haven't been attempted in over a da yeahy
+ */
+module.exports.processExpiredAttempts = function(){
+    for(user of failedAttempts.keys()){
+        //Get attempt by user
+        const attempt = failedAttempts.get(user);
+        //Check how long its been
+        const daysSinceLastAttempt = ((new Date() - attempt.lastAttempt) / (1000 * 60 * 60 * 24)).toFixed(1);
+
+        //If it's been more than a day since anyones tried to log in as this user
+        if(daysSinceLastAttempt >= 1){
+            //Clear out the attempts so that they don't need to fuck with a captcha anymore
+            failedAttempts.delete(user);
+        }
+    }
+}
+
+module.exports.throttleAttempts = throttleAttempts;
+module.exports.maxAttempts = maxAttempts;
+
+
+ + + + +
+ + + +
+ +
+ Documentation generated by JSDoc 4.0.4 on Tue Sep 02 2025 07:08:41 GMT-0400 (Eastern Daylight Time) +
+ + + + +