//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.4";} getAuthor () {return "DevilBro";} getDescription () {return "Allows the user to censor words or block complete messages based on words in the chatwindow.";} initConstructor () { this.changelog = { "added":[["ContextMenu","Added an contextmenu entry when right clicking a highlighted/selected word to allow you to faster add new aliases"]] }; this.patchModules = { "Message":["componentDidMount","componentDidUpdate"], "StandardSidebarView":"componentWillUnmount" }; 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.chatfilterContextEntryMarkup = `
Add to ChatFilter
`; this.chatfilterAddModalMarkup = `

Add to ChatFilter

Block/Censor:

With:

Translator:

Use as Blockword

Use as Censorword

${Object.keys(this.defaults.configs).map((key, i) => `

${this.defaults.configs[key].description}

`).join('')}
`; } 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 += `

${this.defaults.settings[key].description}

`; } for (let rtype in replaces) { settingshtml += `

${this.defaults.replaces[rtype].title}

With:

`; for (let key in settings) { if (this.defaults.settings[key].inner && this.defaults.settings[key].enabled[rtype]) settingshtml += `

${this.defaults.settings[key].description}

`; } settingshtml += `

${this.defaults.replaces[rtype].description}

`; settingshtml += `

List of ${rtype} Words:

`; for (let config in this.defaults.configs) { settingshtml += `
${config.toUpperCase()}
`; } 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.

`; settingshtml += `
`; } var infoHidden = BDFDB.loadData("hideInfo", this, "hideInfo"); settingshtml += `
Information
`; 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[src="https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.js"]'); if (!libraryScript || performance.now() - libraryScript.getAttribute("date") > 600000) { if (libraryScript) libraryScript.remove(); libraryScript = document.createElement("script"); libraryScript.setAttribute("type", "text/javascript"); libraryScript.setAttribute("src", "https://mwittrien.github.io/BetterDiscordAddons/Plugins/BDFDB.js"); libraryScript.setAttribute("date", performance.now()); libraryScript.addEventListener("load", () => {if (global.BDFDB && typeof BDFDB === "object" && BDFDB.loaded) 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, BDFDB.disCN.categorywrappercollapsed); BDFDB.toggleClass(ele, BDFDB.disCN.categorywrapperdefault); var svg = ele.querySelector(BDFDB.dotCN.categoryicontransition); BDFDB.toggleClass(svg, BDFDB.disCN.directionright); BDFDB.toggleClass(svg, BDFDB.disCN.categoryiconcollapsed); BDFDB.toggleClass(svg, BDFDB.disCN.categoryicondefault); BDFDB.toggleEles(ele.nextElementSibling); BDFDB.saveData("hideInfo", BDFDB.isEleHidden(ele.nextElementSibling), this, "hideInfo"); } onNativeContextMenu (instance, menu) { if (instance.props && instance.props.value && instance.props.value.trim() && !menu.querySelector(".chatfilter-item")) { if ((instance.props.type == "NATIVE_TEXT" || instance.props.type == "CHANNEL_TEXT_AREA") && BDFDB.getData("addContextMenu", this, "settings")) this.appendItem(instance, menu, instance.props.value.trim()); } } onMessageContextMenu (instance, menu) { if (instance.props && instance.props.message && instance.props.channel && instance.props.target && !menu.querySelector(".chatfilter-item")) { let text = document.getSelection().toString().trim(); if (text && BDFDB.getData("addContextMenu", this, "settings")) this.appendItem(instance, menu, text); } } appendItem (instance, menu, text) { let chatfilterContextEntry = BDFDB.htmlToElement(this.chatfilterContextEntryMarkup); let devgroup = BDFDB.React.findDOMNodeSafe(BDFDB.getOwnerInstance({node:menu,name:["DeveloperModeGroup","MessageDeveloperModeGroup"]})); if (devgroup) devgroup.parentElement.insertBefore(chatfilterContextEntry, devgroup); else menu.appendChild(chatfilterContextEntry, menu); chatfilterContextEntry.querySelector(".chatfilter-item").addEventListener("click", () => { instance._reactInternalFiber.return.memoizedProps.closeContextMenu(); this.openAddModal(text); }); } processMessage (instance, wrapper) { wrapper.querySelectorAll(`${BDFDB.dotCNC.messagemarkup + BDFDB.dotCN.messageaccessory}`).forEach(message => {this.hideMessage(message);}); } processStandardSidebarView (instance, wrapper) { 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)) { 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(); } }