//META{"name":"ChatFilter","website":"https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ChatFilter","source":"https://raw.githubusercontent.com/mwittrien/BetterDiscordAddons/master/Plugins/ChatFilter/ChatFilter.plugin.js"}*//
class ChatFilter {
getName () {return "ChatFilter";}
getVersion () {return "3.3.5";}
getAuthor () {return "DevilBro";}
getDescription () {return "Allows the user to censor words or block complete messages based on words in the chatwindow.";}
constructor () {
this.changelog = {
"fixed":[["Light Theme Update","Fixed bugs for the Light Theme Update, which broke 99% of my plugins"]]
};
this.patchModules = {
"Message":["componentDidMount","componentDidUpdate"],
"StandardSidebarView":"componentWillUnmount"
};
}
initConstructor () {
this.css = `
${BDFDB.dotCNS.messagegroup + BDFDB.dotCN.messageaccessory}.blocked:not(.revealed),
${BDFDB.dotCNS.messagegroup + BDFDB.dotCN.messagemarkup}.blocked:not(.revealed) {
font-weight: bold;
font-style: italic;
}`;
this.defaults = {
configs: {
empty: {value:false, description:"Allows the replacevalue to be empty (ignoring the default)"},
case: {value:false, description:"Handle the wordvalue case sensitive"},
exact: {value:true, description:"Handle the wordvalue as an exact word and not as part of a word"}
},
replaces: {
blocked: {value:"~~BLOCKED~~", title:"Block:", description:"Default Replace Word for blocked Messages:"},
censored: {value:"$!%&%!&", title:"Censor:", description:"Default Replace Word for censored Messages:"}
},
settings: {
addContextMenu: {value:true, inner:false, description:"Add a ContextMenu entry to faster add new blocked/censored Words:"},
showMessageOnClick: {value:{blocked:true, censored:true}, enabled:{blocked:true, censored:true}, inner:true, description:"Show original Message on Click:"},
hideMessage: {value:{blocked:false, censored:false}, enabled:{blocked:true, censored:false}, inner:true, description:"Completely hide targeted Messages:"}
}
};
this.chatfilterAddModalMarkup =
`
`;
}
getSettingsPanel () {
if (!global.BDFDB || typeof BDFDB != "object" || !BDFDB.loaded || !this.started) return;
var replaces = BDFDB.getAllData(this, "replaces");
var settings = BDFDB.getAllData(this, "settings");
var settingshtml = `
${this.name}
`;
for (let key in settings) {
if (!this.defaults.settings[key].inner) settingshtml += `
`;
}
for (let rtype in replaces) {
settingshtml += `
`;
for (let key in settings) {
if (this.defaults.settings[key].inner && this.defaults.settings[key].enabled[rtype]) settingshtml += `
`;
}
settingshtml += `
${this.defaults.replaces[rtype].description} `;
settingshtml += `
List of ${rtype} Words: `;
for (let config in this.defaults.configs) {
settingshtml += ``;
}
settingshtml += `
`;
for (let word in this.words[rtype]) {
settingshtml += `
${BDFDB.encodeToHTML(word)} (${BDFDB.encodeToHTML(this.words[rtype][word].replace)})
`
for (let config in this.defaults.configs) {
settingshtml += `
`;
}
settingshtml += `
`;
}
settingshtml += `
`
settingshtml += `
Remove all added words. Reset
`;
settingshtml += `
`;
}
var infoHidden = BDFDB.loadData("hideInfo", this, "hideInfo");
settingshtml += `
`;
settingshtml += `
Case: Will block/censor words while comparing lowercase/uppercase. apple => apple, not APPLE or AppLe
Not Case: Will block/censor words while ignoring lowercase/uppercase. apple => apple, APPLE and AppLe
Exact: Will block/censor words that are exactly the selected word. apple => apple, not applepie or pineapple
Not Exact: Will block/censor all words containing the selected word. apple => apple, applepie and pineapple
Empty: Ignores the default and set replace word and removes the word/message instead.
`;
settingshtml += `
`;
let settingspanel = BDFDB.htmlToElement(settingshtml);
BDFDB.initElements(settingspanel, this);
BDFDB.addEventListener(this, settingspanel, "keypress", ".wordInputs", e => {if (e.which == 13) this.updateContainer(settingspanel, e.currentTarget);});
BDFDB.addEventListener(this, settingspanel, "keyup", ".defaultInputs", e => {this.saveReplace(e.currentTarget);});
BDFDB.addEventListener(this, settingspanel, "click", ".btn-addword, .remove-word, .remove-all", e => {this.updateContainer(settingspanel, e.currentTarget);});
BDFDB.addEventListener(this, settingspanel, "click", BDFDB.dotCN.checkboxinput, e => {this.updateConfig(e.currentTarget);});
BDFDB.addEventListener(this, settingspanel, "click", ".toggle-info", e => {this.toggleInfo(e.currentTarget);});
return settingspanel;
}
//legacy
load () {}
start () {
if (!global.BDFDB) global.BDFDB = {myPlugins:{}};
if (global.BDFDB && global.BDFDB.myPlugins && typeof global.BDFDB.myPlugins == "object") global.BDFDB.myPlugins[this.getName()] = this;
var libraryScript = document.querySelector('head script#BDFDBLibraryScript');
if (!libraryScript || (performance.now() - libraryScript.getAttribute("date")) > 600000) {
if (libraryScript) libraryScript.remove();
libraryScript = document.createElement("script");
libraryScript.setAttribute("id", "BDFDBLibraryScript");
libraryScript.setAttribute("type", "text/javascript");
libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.min.js");
libraryScript.setAttribute("date", performance.now());
libraryScript.addEventListener("load", () => {this.initialize();});
document.head.appendChild(libraryScript);
}
else if (global.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) this.initialize();
this.startTimeout = setTimeout(() => {this.initialize();}, 30000);
}
initialize () {
if (global.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) {
if (this.started) return;
BDFDB.loadMessage(this);
this.words = BDFDB.loadAllData(this, "words");
for (let rtype in this.defaults.replaces) if (!BDFDB.isObject(this.words[rtype])) this.words[rtype] = {};
BDFDB.WebModules.forceAllUpdates(this);
}
else {
console.error(`%c[${this.getName()}]%c`, 'color: #3a71c1; font-weight: 700;', '', 'Fatal Error: Could not load BD functions!');
}
}
stop () {
if (global.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) {
document.querySelectorAll(`${BDFDB.dotCN.messagemarkup}.blocked, ${BDFDB.dotCN.messageaccessory}.censored, ${BDFDB.dotCN.messagemarkup}.blocked, ${BDFDB.dotCN.messageaccessory}.censored`).forEach(message => {this.resetMessage(message);});
BDFDB.unloadMessage(this);
}
}
// begin of own functions
updateContainer (settingspanel, ele) {
var wordvalue = null, replacevalue = null, action = ele.getAttribute("action"), rtype = ele.getAttribute("rtype"), update = () => {
BDFDB.saveAllData(this.words, this, "words");
var containerhtml = ``;
for (let word in this.words[rtype]) {
containerhtml += `
${BDFDB.encodeToHTML(word)} (${BDFDB.encodeToHTML(this.words[rtype][word].replace)})
`
for (let config in this.defaults.configs) {
containerhtml += `
`;
}
containerhtml += `
`;
}
containerhtml += `
`;
settingspanel.querySelector("." + rtype + "-list").innerHTML = containerhtml;
BDFDB.initElements(settingspanel, this);
this.SettingsUpdated = true;
};
if (action == "add") {
var wordinput = settingspanel.querySelector("#input-" + rtype + "-wordvalue");
var replaceinput = settingspanel.querySelector("#input-" + rtype + "-replacevalue");
if (wordinput.value && wordinput.value.trim().length > 0) {
this.saveWord(wordinput.value.trim(), replaceinput.value.trim(), rtype);
wordinput.value = null;
replaceinput.value = null;
update();
}
}
else if (action == "remove") {
var wordvalue = ele.getAttribute("word");
if (wordvalue) {
delete this.words[rtype][wordvalue];
update();
}
}
else if (action == "removeall") {
BDFDB.openConfirmModal(this, "Are you sure you want to remove all added Words from your list?", () => {
this.words[rtype] = {};
update();
});
}
}
saveWord (wordvalue, replacevalue, rtype, configs = BDFDB.getAllData(this, "configs")) {
if (!wordvalue || !replacevalue) return;
wordvalue = wordvalue.trim();
replacevalue = replacevalue.trim();
this.words[rtype][wordvalue] = {
replace: replacevalue,
empty: configs.empty,
case: configs.case,
exact: wordvalue.indexOf(" ") > -1 ? false : configs.exact,
regex: false
};
}
saveReplace (input) {
var rtype = input.getAttribute("rtype");
var wordvalue = input.value;
if (rtype) {
var replaces = BDFDB.getData(rtype, this, "replaces");
BDFDB.saveData(rtype, wordvalue.trim(), this, "replaces");
}
}
updateConfig (ele) {
var wordvalue = ele.getAttribute("word");
var config = ele.getAttribute("config");
var rtype = ele.getAttribute("rtype");
if (wordvalue && this.words[rtype][wordvalue] && config) {
this.words[rtype][wordvalue][config] = ele.checked;
BDFDB.saveAllData(this.words, this, "words");
}
}
toggleInfo (ele) {
BDFDB.toggleClass(ele.querySelector("svg"), BDFDB.disCN.directionright);
BDFDB.toggleEles(ele.nextElementSibling);
BDFDB.saveData("hideInfo", BDFDB.isEleHidden(ele.nextElementSibling), this, "hideInfo");
}
onNativeContextMenu (instance, menu, returnvalue) {
if (instance.props && instance.props.value && instance.props.value.trim() && !menu.querySelector(`${this.name}-contextMenuItem`)) {
if ((instance.props.type == "NATIVE_TEXT" || instance.props.type == "CHANNEL_TEXT_AREA") && BDFDB.getData("addContextMenu", this, "settings")) this.appendItem(menu, returnvalue, instance.props.value.trim());
}
}
onMessageContextMenu (instance, menu, returnvalue) {
if (instance.props && instance.props.message && instance.props.channel && instance.props.target && !menu.querySelector(`${this.name}-contextMenuItem`)) {
let text = document.getSelection().toString().trim();
if (text && BDFDB.getData("addContextMenu", this, "settings")) this.appendItem(menu, returnvalue, text);
}
}
appendItem (menu, returnvalue, text) {
let [children, index] = BDFDB.getContextMenuGroupAndIndex(returnvalue, ["FluxContainer(MessageDeveloperModeGroup)", "DeveloperModeGroup"]);
const itemgroup = BDFDB.React.createElement(BDFDB.LibraryComponents.ContextMenuItemGroup, {
className: `BDFDB-contextMenuItemGroup ${this.name}-contextMenuItemGroup`,
children: [
BDFDB.React.createElement(BDFDB.LibraryComponents.ContextMenuItem, {
label: "Add to ChatFilter",
className: `BDFDB-contextMenuItem ${this.name}-contextMenuItem ${this.name}-addalias-contextMenuItem`,
action: e => {
BDFDB.closeContextMenu(menu);
this.openAddModal(text);
}
})
]
});
if (index > -1) children.splice(index, 0, itemgroup);
else children.push(itemgroup);
}
processMessage (instance, wrapper, returnvalue) {
wrapper.querySelectorAll(`${BDFDB.dotCNC.messagemarkup + BDFDB.dotCN.messageaccessory}`).forEach(message => {this.hideMessage(message);});
}
processStandardSidebarView (instance, wrapper, returnvalue) {
if (this.SettingsUpdated) {
delete this.SettingsUpdated;
document.querySelectorAll(`${BDFDB.dotCN.messagemarkup}.blocked, ${BDFDB.dotCN.messageaccessory}.censored, ${BDFDB.dotCN.messagemarkup}.blocked, ${BDFDB.dotCN.messageaccessory}.censored`).forEach(message => {this.resetMessage(message);});
BDFDB.WebModules.forceAllUpdates(this);
}
}
hideMessage (message) {
if (message.tagName && !BDFDB.containsClass(message, "blocked", "censored", false)) {
var orightml = message.innerHTML;
var newhtml = "";
if (orightml) {
var blocked = null;
var strings = [];
var count = 0;
orightml.split("").forEach((chara) => {
if (chara == "<") {
if (strings[count]) count++;
}
strings[count] = strings[count] ? strings[count] + chara : chara;
if (chara == ">") {
count++;
}
});
var settings = BDFDB.getAllData(this, "settings");
var replaces = BDFDB.getAllData(this, "replaces");
var blocked = false;
for (let bWord in this.words.blocked) {
var blockedReplace = this.words.blocked[bWord].empty ? "" : (this.words.blocked[bWord].replace || replaces.blocked);
var reg = this.createReg(bWord, this.words.blocked[bWord]);
strings.forEach(string => {
if (this.testForEmoji(string, reg)) blocked = true;
else if (string.indexOf(' 0 ? string.split('src="')[1] : null;
url = url ? url.split('"')[0] : null;
if (reg.test(url)) blocked = true;
}
else if (string.indexOf("<") != 0) {
string.replace(/\n/g, " \n ").split(" ").forEach((word) => {
let wordWithoutSpecial = word.replace(/[\?\¿\!\¡\.\"]/g, "");
if (word && reg.test(word) || wordWithoutSpecial && reg.test(wordWithoutSpecial)) blocked = true;
});
}
});
if (blocked) break;
}
if (blocked) {
if (settings.hideMessage.blocked) BDFDB.toggleEles(message, false);
newhtml = BDFDB.encodeToHTML(blockedReplace);
message.innerHTML = newhtml;
BDFDB.addClass(message, "blocked");
message.ChatFilterOriginalHTML = orightml;
message.ChatFilterNewHTML = newhtml;
this.addClickListener(message, settings.showMessageOnClick.blocked);
}
else {
var censored = false;
for (let cWord in this.words.censored) {
var censoredReplace = this.words.censored[cWord].empty ? "" : (this.words.censored[cWord].replace || replaces.censored);
var reg = this.createReg(cWord, this.words.censored[cWord]);
strings.forEach((string,i) => {
if (this.testForEmoji(string, reg)) {
censored = true;
strings[i] = BDFDB.encodeToHTML(censoredReplace);
if (strings[i+1] && strings[i+1].indexOf(" 0 ? string.split('src="')[1] : null;
url = url ? url.split('"')[0] : null;
if (reg.test(url)) {
censored = true;
strings = [BDFDB.encodeToHTML(censoredReplace)];
}
}
else if (string.indexOf("<") != 0) {
var newstring = [];
string.replace(/\n/g, " \n ").split(" ").forEach((word) => {
let wordWithoutSpecial = word.replace(/[\?\¿\!\¡\.\"]/g, "");
if (word && reg.test(word) || wordWithoutSpecial && reg.test(wordWithoutSpecial)) {
censored = true;
newstring.push(BDFDB.encodeToHTML(censoredReplace));
}
else {
newstring.push(word);
}
});
strings[i] = newstring.join(" ").replace(/ \n /g, "\n");
}
});
}
if (censored) {
newhtml = strings.join("");
message.innerHTML = newhtml;
BDFDB.addClass(message, "censored");
message.ChatFilterOriginalHTML = orightml;
message.ChatFilterNewHTML = newhtml;
this.addClickListener(message, settings.showMessageOnClick.censored);
}
}
}
}
}
createReg (word, config) {
return new RegExp(BDFDB.encodeToHTML(config.exact ? "^" + BDFDB.regEscape(word) + "$" : BDFDB.regEscape(word)), config.case ? "" : "i");
}
testForEmoji (string, reg) {
if (string.indexOf(" -1 || string.indexOf('class="emoji') > -1)) {
var emojiname = string.split('alt="').length > 0 ? string.split('alt="')[1].split('"')[0] : null;
return emojiname = !emojiname ? false : (reg.test(emojiname) || reg.test(emojiname.replace(/:/g, "")));
}
return false;
}
resetMessage (message) {
message.innerHTML = message.ChatFilterOriginalHTML;
BDFDB.removeClass(message, "blocked", "censored", "revealed");
BDFDB.toggleEles(message, true);
delete message.ChatFilterOriginalHTML;
delete message.ChatFilterNewHTML;
message.removeEventListener("click", message.clickChatFilterListener);
}
addClickListener (message, addListener) {
message.removeEventListener("click", message.clickChatFilterListener);
if (addListener) {
message.clickChatFilterListener = () => {
if (BDFDB.containsClass(message, "revealed")) {
BDFDB.removeClass(message, "revealed");
message.innerHTML = message.ChatFilterNewHTML;
}
else {
BDFDB.addClass(message, "revealed");
message.innerHTML = message.ChatFilterOriginalHTML;
}
};
message.addEventListener("click", message.clickChatFilterListener);
}
}
openAddModal (wordvalue) {
let chatfilterAddModal = BDFDB.htmlToElement(this.chatfilterAddModalMarkup);
let wordvalueinput = chatfilterAddModal.querySelector("#input-wordvalue");
let replacevalueinput = chatfilterAddModal.querySelector("#input-replacevalue");
let addbutton = chatfilterAddModal.querySelector(".btn-add");
wordvalueinput.value = wordvalue || "";
BDFDB.appendModal(chatfilterAddModal);
wordvalueinput.addEventListener("input", () => {
if (!wordvalueinput.value.trim()) {
addbutton.disabled = true;
BDFDB.addClass(wordvalueinput, "invalid");
addbutton.style.setProperty("pointer-events", "none", "important");
BDFDB.createTooltip("Choose a Wordvalue", {type: "right", color: "red", selector: "chatfilter-disabled-tooltip"});
}
else {
addbutton.disabled = false;
BDFDB.removeClass(wordvalueinput, "invalid");
addbutton.style.removeProperty("pointer-events");
BDFDB.removeEles(".chatfilter-disabled-tooltip");
}
});
BDFDB.addChildEventListener(chatfilterAddModal, "click", BDFDB.dotCNC.backdrop + BDFDB.dotCNC.modalclose + ".btn-add", () => {
BDFDB.removeEles(".chatfilter-disabled-tooltip");
});
addbutton.addEventListener("click", e => {
let configs = {};
for (let key in this.defaults.configs) {
let configinput = chatfilterAddModal.querySelector("#input-config" + key);
if (configinput) configs[key] = configinput.checked;
}
let rtype = chatfilterAddModal.querySelector("#input-choiceblockcensor").checked ? "censored" : "blocked";
this.saveWord(wordvalueinput.value.trim(), replacevalueinput.value.trim(), rtype, configs);
BDFDB.saveAllData(this.words, this, "words");
document.querySelectorAll(`${BDFDB.dotCN.messagemarkup}.blocked, ${BDFDB.dotCN.messageaccessory}.censored, ${BDFDB.dotCN.messagemarkup}.blocked, ${BDFDB.dotCN.messageaccessory}.censored`).forEach(message => {this.resetMessage(message);});
BDFDB.WebModules.forceAllUpdates(this);
});
wordvalueinput.focus();
}
}