canopy/www/doc/client/commandPreprocessor.js.html

381 lines
13 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: commandPreprocessor.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: commandPreprocessor.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/*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 &lt;https://www.gnu.org/licenses/>.*/
/**
* Class containing chat and command pre-processing logic
*/
class commandPreprocessor{
/**
* Instantiates a new commandPreprocessor object
* @param {channel} client - Parent client Management Object
*/
constructor(client){
/**
* Parent Client Management object
*/
this.client = client;
/**
* Child Command Processor object
*/
this.commandProcessor = new commandProcessor(client);
/**
* Set of arrays containing site-wide, channel-wide, and user-specific emotes
*/
this.emotes = {
site: [],
chan: [],
personal: []
}
//define listeners
this.defineListeners();
}
/**
* Defines Network-Related Listeners
*/
defineListeners(){
//When we receive site-wide emote list
this.client.socket.on("siteEmotes", this.setSiteEmotes.bind(this));
this.client.socket.on("chanEmotes", this.setChanEmotes.bind(this));
this.client.socket.on("personalEmotes", this.setPersonalEmotes.bind(this));
this.client.socket.on("usedTokes", this.setUsedTokes.bind(this));
}
/**
* Pre-Processes a single chat/command before sending it off to the server
* @param {String} command - Chat/Command to pre-process
*/
preprocess(command){
//Set command and sendFlag
this.command = command;
this.sendFlag = true;
//Attempt to process as local command
this.processLocalCommand();
//If we made it through the local command processor
if(this.sendFlag){
//Set the message to the command
this.message = command;
//Process message emotes into links
this.processEmotes();
//Process unmarked links into marked links
this.processLinks();
//Send command off to server
this.sendRemoteCommand();
}
}
/**
* Processes local commands, starting with '/'
*/
processLocalCommand(){
//Create an empty array to hold the command
this.commandArray = [];
//Split string by words
this.commandArray = this.command.split(/\b/g);//Split by word-borders
this.argumentArray = this.command.match(/\b\w+\b/g);//Match by words surrounded by borders
//If this is a local command
if(this.commandArray[0] == '/'){
//If the command exists
if(this.argumentArray != null &amp;&amp; this.commandProcessor[this.argumentArray[0].toLowerCase()] != null){
//Don't send it to the server
this.sendFlag = false;
//Call the command with the argument array
this.commandProcessor[this.argumentArray[0].toLowerCase()](this.argumentArray, this.commandArray);
}
}
}
/**
* Processes emotes refrences in loaded message into links to be further processed by processLinks()
*/
processEmotes(){
//inject invisible whitespace in-between emotes to prevent from mushing links together
this.message = this.message.replaceAll('][','][');
//For each list of emotes
Object.keys(this.emotes).forEach((key) => {
//For each emote in the current list
this.emotes[key].forEach((emote) => {
//Inject emote links into the message, pad with invisible whitespace to keep link from getting mushed
this.message = this.message.replaceAll(`[${emote.name}]`, `${emote.link}`);
});
});
}
/**
* Processes links into numbered file seperators, putting links into a dedicated array.
*/
processLinks(){
//Strip out file seperators in-case the user is being a smart-ass
this.message = this.message.replaceAll('␜','');
//Split message by links
var splitMessage = this.message.split(/(https?:\/\/[^\s]+)/g);
//Create an empty array to hold links
this.links = [];
splitMessage.forEach((chunk, chunkIndex) => {
//For each chunk that is a link
if(chunk.match(/(https?:\/\/[^\s]+)/g)){
//I looked online for obscure characters that no one would use to prevent people from chatting embed placeholders
//Then I found this fucker, turns out it's literally made for the job lmao (even if it was originally intended for paper/magnetic tape)
//Replace link with indexed placeholder
splitMessage[chunkIndex] = `␜${this.links.length}`
//push current chunk as link
this.links.push(chunk);
}
});
//Join the message back together
this.message = splitMessage.join('');
}
/**
* Transmits message/command off to server
*/
sendRemoteCommand(){
this.client.socket.emit("chatMessage",{msg: this.message, links: this.links});
}
/**
* Sets site emotes
* @param {Object} data - Emote data from server
*/
setSiteEmotes(data){
this.emotes.site = data;
}
/**
* Sets channel emotes
* @param {Object} data - Emote data from server
*/
setChanEmotes(data){
this.emotes.chan = data;
}
/**
* Sets personal emotes
* @param {Object} data - Emote data from server
*/
setPersonalEmotes(data){
this.emotes.personal = data;
}
/**
* Sets used tokes
* @param {Object} data - Used toke data from server
*/
setUsedTokes(data){
this.usedTokes = data.tokes;
}
/**
* Fetches emote by link
* @param {String} link - Link to fetch emote with
* @returns {Object} found emote
*/
getEmoteByLink(link){
//Create an empty variable to hold the found emote
var foundEmote = null;
//For each list of emotes
Object.keys(this.emotes).forEach((key) => {
//For each emote in the current list
this.emotes[key].forEach((emote) => {
//if we found a match
if(emote.link == link){
//return the match
foundEmote = emote;
}
});
});
return foundEmote;
}
/**
* Generates flat list of emote names
* @returns {Array} List of strings containing emote names
*/
getEmoteNames(){
//Create an empty array to hold names
let names = [];
//For every set of emotes
for(let set of Object.keys(this.emotes)){
//for every emote in the current set of emotes
for(let emote of this.emotes[set]){
//push the name of the emote to the name list
names.push(emote.name);
}
}
//return our list of names
return names;
}
/**
* Generates auto-complete dictionary from pre-written commands, emotes, and used tokes from servers for use with autocomplete
* @returns {Object} Generated Dictionary object
*/
buildAutocompleteDictionary(){
let dictionary = {
tokes: {
prefix: '!',
postfix: '',
cmds: [
['toke', true]
].concat(injectPerms(this.usedTokes))
},
//Make sure to add spaces at the end for commands that take arguments
//Not necissary but definitely nice to have
serverCMD: {
prefix: '!',
postfix: '',
cmds: [
["whisper ", true],
["announce ", client.user.permMap.chan.get('announce')],
["serverannounce ", client.user.permMap.site.get('announce')],
["clear ", client.user.permMap.chan.get('clearChat')],
["kick ", client.user.permMap.chan.get('kickUser')],
]
},
localCMD:{
prefix: '/',
postfix: '',
cmds: [
["high ", true]
]
},
usernames:{
prefix: '',
postfix: '',
cmds: injectPerms(Array.from(client.userList.colorMap.keys()))
},
emotes:{
prefix:'[',
postfix:']',
cmds: injectPerms(this.getEmoteNames())
}
};
//return our dictionary object
return dictionary;
function injectPerms(cmds, perm = true){
//Create empty array to hold cmds
let cmdSet = [];
//For each cmd
for(let cmd of cmds){
//Add the cmd with its perm to the cmdset
cmdSet.push([cmd, perm]);
}
//return the cmd set
return cmdSet;
}
}
}
/**
* Class which contains logic for client-side commands
*/
class commandProcessor{
/**
* Instantiates a new Command Processor object
* @param {channel} client - Parent client mgmt object
*/
constructor(client){
/**
* Parent Client Management object
*/
this.client = client
}
/**
* Method handling /high client command
* @param {Array} argumentArray - Array of arguments passed down from Command Pre-Processor
*/
high(argumentArray){
//If we have an argument
if(argumentArray[1]){
//Use it to set our high level
//Technically this is less of a local command than it would be if it where telling the select to do this
//but TTN used to treat this as a local command so fuck it
this.client.socket.emit("setHighLevel", {highLevel: argumentArray[1]});
}
}
}</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="addURLPopup.html">addURLPopup</a></li><li><a href="cPanel.html">cPanel</a></li><li><a href="channel.html">channel</a></li><li><a href="chatBox.html">chatBox</a></li><li><a href="chatPostprocessor.html">chatPostprocessor</a></li><li><a href="clearPopup.html">clearPopup</a></li><li><a href="commandPreprocessor.html">commandPreprocessor</a></li><li><a href="commandProcessor.html">commandProcessor</a></li><li><a href="defaultTitlesPopup.html">defaultTitlesPopup</a></li><li><a href="emotePanel.html">emotePanel</a></li><li><a href="hlsBase.html">hlsBase</a></li><li><a href="hlsLiveStreamHandler.html">hlsLiveStreamHandler</a></li><li><a href="mediaHandler.html">mediaHandler</a></li><li><a href="newPlaylistPopup.html">newPlaylistPopup</a></li><li><a href="nullHandler.html">nullHandler</a></li><li><a href="panelObj.html">panelObj</a></li><li><a href="player.html">player</a></li><li><a href="playlistManager.html">playlistManager</a></li><li><a href="poppedPanel.html">poppedPanel</a></li><li><a href="queuePanel.html">queuePanel</a></li><li><a href="rawFileBase.html">rawFileBase</a></li><li><a href="rawFileHandler.html">rawFileHandler</a></li><li><a href="renamePopup.html">renamePopup</a></li><li><a href="reschedulePopup.html">reschedulePopup</a></li><li><a href="schedulePopup.html">schedulePopup</a></li><li><a href="settingsPanel.html">settingsPanel</a></li><li><a href="userList.html">userList</a></li><li><a href="youtubeEmbedHandler.html">youtubeEmbedHandler</a></li></ul><h3>Global</h3><ul><li><a href="global.html#onYouTubeIframeAPIReady">onYouTubeIframeAPIReady</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Sat Sep 06 2025 00:47:15 GMT-0400 (Eastern Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>