183 lines
5.9 KiB
JavaScript
183 lines
5.9 KiB
JavaScript
/*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 commandPreprocessor{
|
||
constructor(client){
|
||
this.client = client;
|
||
this.commandProcessor = new commandProcessor(client);
|
||
this.emotes = {
|
||
site: [],
|
||
chan: [],
|
||
personal: []
|
||
}
|
||
|
||
//define listeners
|
||
this.defineListeners();
|
||
}
|
||
|
||
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));
|
||
}
|
||
|
||
preprocess(command){
|
||
//Set command and sendFlag
|
||
this.command = command;
|
||
this.sendFlag = true;
|
||
|
||
this.processLocalCommand();
|
||
|
||
if(this.sendFlag){
|
||
this.message = command;
|
||
this.processEmotes();
|
||
this.processLinks();
|
||
this.sendRemoteCommand();
|
||
}
|
||
}
|
||
|
||
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 && 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);
|
||
}
|
||
}
|
||
}
|
||
|
||
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
|
||
this.message = this.message.replaceAll(`[${emote.name}]`, emote.link);
|
||
});
|
||
});
|
||
}
|
||
|
||
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('');
|
||
}
|
||
|
||
sendRemoteCommand(){
|
||
this.client.socket.emit("chatMessage",{msg: this.message, links: this.links});
|
||
}
|
||
|
||
setSiteEmotes(data){
|
||
this.emotes.site = data;
|
||
}
|
||
|
||
setChanEmotes(data){
|
||
this.emotes.chan = data;
|
||
}
|
||
|
||
setPersonalEmotes(data){
|
||
this.emotes.personal = data;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
buildAutocompleteDictionary(){
|
||
//This isn't complete, just a placeholder for now
|
||
let dictionary = {
|
||
tokes: [
|
||
"toke"
|
||
],
|
||
serverCMD: [
|
||
"whisper",
|
||
"announce",
|
||
"serverannounce",
|
||
"clear",
|
||
"kick"
|
||
],
|
||
localCMD:[
|
||
"high"
|
||
]
|
||
};
|
||
|
||
return dictionary;
|
||
}
|
||
|
||
}
|
||
|
||
class commandProcessor{
|
||
constructor(client){
|
||
this.client = client
|
||
}
|
||
|
||
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]});
|
||
}
|
||
}
|
||
} |