From b616bf9a8abbc129f8047fb38c48e11552267ef2 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Wed, 24 Jan 2024 15:02:44 -0500 Subject: [PATCH] No Bad Emotes 1.0.0 New add-on! This add-on uses the new FrankerFaceZ client API to let users hide emotes based on their names. Tired of people replacing common words with emotes and turning normal sentences into nonsense? This is for you. --- src/no-bad-emotes/common.json | 1048 +++++++++++++++++++++++++++++++ src/no-bad-emotes/index.js | 290 +++++++++ src/no-bad-emotes/manifest.json | 13 + webpack.config.js | 10 + 4 files changed, 1361 insertions(+) create mode 100644 src/no-bad-emotes/common.json create mode 100644 src/no-bad-emotes/index.js create mode 100644 src/no-bad-emotes/manifest.json diff --git a/src/no-bad-emotes/common.json b/src/no-bad-emotes/common.json new file mode 100644 index 00000000..46562dda --- /dev/null +++ b/src/no-bad-emotes/common.json @@ -0,0 +1,1048 @@ +{ + "description": "Common English words, mainly from https://github.com/dariusk/corpora/blob/master/data/words/common.json", + "words": + [ + "a", + "able", + "about", + "absolute", + "accept", + "account", + "achieve", + "across", + "act", + "active", + "actual", + "add", + "address", + "admit", + "advertise", + "affect", + "afford", + "after", + "afternoon", + "again", + "against", + "age", + "agent", + "ago", + "agree", + "air", + "all", + "allow", + "almost", + "along", + "already", + "alright", + "also", + "although", + "always", + "america", + "amount", + "and", + "ant", + "antenna", + "another", + "answer", + "any", + "angry", + "apart", + "apparent", + "appear", + "apply", + "appoint", + "approach", + "appropriate", + "area", + "argue", + "arm", + "around", + "arrange", + "art", + "as", + "ask", + "associate", + "assume", + "at", + "attend", + "authority", + "available", + "aware", + "away", + "awful", + "baby", + "back", + "bad", + "bag", + "balance", + "ball", + "bank", + "bar", + "base", + "basis", + "be", + "bear", + "beat", + "beauty", + "because", + "become", + "bed", + "before", + "begin", + "behind", + "believe", + "benefit", + "best", + "bet", + "between", + "big", + "bill", + "binoculars", + "birth", + "bit", + "black", + "bloke", + "blood", + "blow", + "blue", + "board", + "boat", + "body", + "book", + "both", + "bother", + "bottle", + "bottom", + "box", + "boy", + "break", + "brief", + "brilliant", + "bring", + "britain", + "brother", + "budget", + "build", + "bus", + "business", + "busy", + "but", + "buy", + "by", + "bye", + "cake", + "call", + "can", + "car", + "card", + "care", + "carry", + "case", + "cat", + "catch", + "cause", + "cent", + "centre", + "certain", + "chair", + "chairman", + "chance", + "change", + "chap", + "character", + "charge", + "cheap", + "check", + "chicken", + "child", + "choice", + "choose", + "Christ", + "Christmas", + "church", + "city", + "claim", + "class", + "classic", + "clean", + "clear", + "client", + "clock", + "close", + "closes", + "clothe", + "club", + "coffee", + "cold", + "colleague", + "collect", + "college", + "colour", + "come", + "comment", + "commit", + "committee", + "common", + "community", + "company", + "compare", + "complete", + "compute", + "concern", + "conch", + "condition", + "confer", + "consider", + "consult", + "contact", + "continue", + "contract", + "control", + "converse", + "cook", + "copy", + "corner", + "correct", + "cost", + "could", + "council", + "count", + "country", + "county", + "couple", + "course", + "court", + "cover", + "create", + "cross", + "cup", + "current", + "cut", + "dad", + "danger", + "date", + "day", + "dead", + "deal", + "dear", + "debate", + "decide", + "decision", + "deep", + "definite", + "degree", + "department", + "depend", + "describe", + "design", + "detail", + "develop", + "die", + "difference", + "difficult", + "dinner", + "direct", + "disbelief", + "discuss", + "district", + "divide", + "do", + "doctor", + "document", + "dog", + "door", + "double", + "doubt", + "down", + "draw", + "dress", + "drink", + "drive", + "drop", + "dry", + "due", + "during", + "each", + "early", + "east", + "easy", + "eat", + "economy", + "educate", + "effect", + "egg", + "eight", + "either", + "elect", + "electric", + "eleven", + "else", + "employ", + "encourage", + "end", + "engine", + "english", + "enjoy", + "enough", + "enter", + "environment", + "equal", + "especial", + "europe", + "even", + "evening", + "ever", + "every", + "evidence", + "exact", + "example", + "except", + "excuse", + "exercise", + "exist", + "expect", + "expense", + "experience", + "explain", + "express", + "exquisite", + "extra", + "eye", + "face", + "fact", + "fair", + "fall", + "family", + "far", + "farm", + "fast", + "father", + "favour", + "feed", + "feel", + "few", + "field", + "fight", + "figure", + "file", + "fill", + "film", + "final", + "finance", + "find", + "fine", + "finish", + "fire", + "first", + "fish", + "fishing", + "fit", + "five", + "flat", + "flash", + "flashback", + "flirt", + "floor", + "fly", + "follow", + "food", + "foot", + "for", + "force", + "forget", + "form", + "fortune", + "forward", + "four", + "france", + "free", + "friday", + "friend", + "from", + "front", + "full", + "fun", + "function", + "fund", + "further", + "future", + "game", + "garden", + "gas", + "gaze", + "general", + "germany", + "get", + "girl", + "give", + "glass", + "go", + "god", + "good", + "goodbye", + "govern", + "grand", + "grant", + "great", + "green", + "ground", + "group", + "grow", + "guess", + "guy", + "hack", + "hacking", + "hair", + "half", + "hall", + "hand", + "hang", + "happen", + "happy", + "hard", + "hate", + "have", + "he", + "head", + "health", + "hear", + "heart", + "heat", + "heavy", + "hell", + "hello", + "help", + "here", + "hi", + "high", + "history", + "hit", + "hold", + "holiday", + "home", + "honest", + "hope", + "horse", + "hospital", + "hot", + "hour", + "house", + "how", + "however", + "hullo", + "hundred", + "husband", + "idea", + "identify", + "idiot", + "if", + "imagine", + "important", + "improve", + "in", + "include", + "income", + "increase", + "indeed", + "individual", + "industry", + "inform", + "inside", + "instead", + "insure", + "interest", + "into", + "intro", + "introduce", + "invest", + "involve", + "issue", + "it", + "item", + "jesus", + "job", + "join", + "judge", + "jump", + "just", + "keep", + "key", + "kid", + "kill", + "kind", + "king", + "kitchen", + "knock", + "know", + "labour", + "lad", + "lady", + "land", + "language", + "large", + "last", + "late", + "laugh", + "law", + "lay", + "lead", + "learn", + "leave", + "left", + "leg", + "less", + "let", + "letter", + "level", + "lie", + "life", + "light", + "like", + "likely", + "limit", + "line", + "link", + "list", + "listen", + "listening", + "little", + "live", + "load", + "local", + "lock", + "london", + "long", + "look", + "lord", + "lose", + "lot", + "love", + "low", + "luck", + "lunch", + "machine", + "main", + "major", + "make", + "man", + "manage", + "many", + "mark", + "market", + "marry", + "match", + "matter", + "maw", + "may", + "maybe", + "mean", + "meaning", + "measure", + "meow", + "meet", + "member", + "mention", + "middle", + "might", + "mile", + "milk", + "million", + "mind", + "minister", + "minus", + "minute", + "miss", + "mister", + "mitosis", + "mod", + "mods", + "modding", + "moderator", + "moderators", + "moment", + "monday", + "money", + "month", + "more", + "morning", + "most", + "mother", + "motion", + "move", + "mrs", + "much", + "music", + "must", + "name", + "nation", + "nature", + "near", + "necessary", + "need", + "never", + "new", + "news", + "next", + "nice", + "night", + "nine", + "no", + "non", + "none", + "normal", + "north", + "not", + "note", + "notes", + "notice", + "now", + "number", + "observe", + "observing", + "obvious", + "occasion", + "odd", + "of", + "off", + "offer", + "office", + "often", + "ok", + "okay", + "old", + "on", + "once", + "one", + "only", + "open", + "operate", + "opportunity", + "oppose", + "or", + "orange", + "order", + "organize", + "original", + "other", + "otherwise", + "ought", + "out", + "over", + "own", + "pack", + "pain", + "page", + "paint", + "pair", + "panic", + "paper", + "paragraph", + "pardon", + "parent", + "park", + "part", + "particular", + "party", + "pass", + "past", + "pay", + "pence", + "pension", + "people", + "per", + "percent", + "perfect", + "perhaps", + "period", + "person", + "photograph", + "pick", + "picture", + "piece", + "place", + "plan", + "play", + "please", + "plus", + "point", + "police", + "policy", + "politic", + "poor", + "position", + "positive", + "possible", + "post", + "pound", + "power", + "practise", + "prepare", + "present", + "press", + "pressure", + "presume", + "pretty", + "previous", + "price", + "prince", + "princess", + "print", + "private", + "probable", + "problem", + "proceed", + "process", + "produce", + "product", + "programme", + "project", + "proper", + "propose", + "protect", + "provide", + "public", + "pull", + "purpose", + "push", + "put", + "quality", + "quarter", + "question", + "quick", + "quid", + "quiet", + "quite", + "radio", + "rail", + "raise", + "range", + "rate", + "rather", + "react", + "reacting", + "read", + "ready", + "real", + "realise", + "really", + "reason", + "receive", + "recent", + "reckon", + "recognize", + "recommend", + "record", + "recording", + "red", + "reduce", + "refer", + "regard", + "region", + "regret", + "relation", + "remember", + "report", + "represent", + "require", + "research", + "resource", + "respect", + "responsible", + "rest", + "result", + "return", + "rid", + "right", + "ring", + "rise", + "road", + "role", + "roll", + "room", + "round", + "rule", + "run", + "safe", + "sale", + "same", + "saturday", + "save", + "say", + "scare", + "scared", + "scheme", + "school", + "science", + "score", + "scotland", + "seat", + "second", + "secretary", + "section", + "secure", + "see", + "seem", + "self", + "sell", + "send", + "sense", + "separate", + "serious", + "serve", + "service", + "set", + "settle", + "seven", + "sex", + "shall", + "share", + "she", + "sheet", + "shoe", + "shoot", + "shop", + "short", + "should", + "show", + "shut", + "sick", + "side", + "sign", + "similar", + "simple", + "since", + "sing", + "single", + "sir", + "sister", + "sit", + "sitting", + "site", + "situate", + "six", + "size", + "sleep", + "slight", + "slow", + "small", + "smoke", + "sneak", + "sneaking", + "so", + "social", + "society", + "some", + "son", + "soon", + "sorry", + "sort", + "sound", + "south", + "space", + "speak", + "special", + "specific", + "speed", + "spell", + "spend", + "square", + "staff", + "stage", + "stairs", + "stand", + "standard", + "start", + "state", + "station", + "stay", + "step", + "stick", + "still", + "stop", + "story", + "straight", + "strategy", + "street", + "strike", + "strong", + "structure", + "student", + "study", + "stuff", + "stupid", + "subject", + "succeed", + "such", + "sudden", + "suggest", + "suit", + "summer", + "sun", + "sunday", + "supply", + "support", + "suppose", + "sure", + "surprise", + "switch", + "system", + "table", + "take", + "talk", + "tape", + "tax", + "tea", + "teach", + "team", + "telephone", + "television", + "tell", + "ten", + "tend", + "term", + "terrible", + "test", + "than", + "thank", + "the", + "then", + "there", + "therefore", + "they", + "thing", + "think", + "thirteen", + "thirty", + "this", + "thou", + "though", + "thousand", + "three", + "through", + "throw", + "thursday", + "tie", + "time", + "timeout", + "to", + "today", + "together", + "tomorrow", + "tonight", + "too", + "top", + "total", + "touch", + "toward", + "town", + "trade", + "traffic", + "train", + "transport", + "travel", + "treat", + "tree", + "trouble", + "true", + "trust", + "try", + "tuesday", + "turn", + "twelve", + "twenty", + "two", + "type", + "under", + "understand", + "union", + "unit", + "unite", + "university", + "unless", + "until", + "up", + "upon", + "use", + "usual", + "value", + "various", + "very", + "vibe", + "vibing", + "video", + "view", + "village", + "visit", + "voice", + "voices", + "vote", + "wage", + "wait", + "waiting", + "walk", + "walking", + "wall", + "want", + "war", + "warm", + "warn", + "warning", + "wash", + "waste", + "watch", + "watching", + "water", + "way", + "we", + "wear", + "wednesday", + "wee", + "week", + "weigh", + "welcome", + "well", + "west", + "what", + "when", + "where", + "whether", + "which", + "while", + "white", + "who", + "whole", + "why", + "wide", + "wife", + "will", + "win", + "wind", + "window", + "wish", + "with", + "within", + "without", + "woman", + "wonder", + "wood", + "woof", + "word", + "work", + "world", + "worry", + "worse", + "worth", + "would", + "wow", + "write", + "wrong", + "year", + "yes", + "yesterday", + "yet", + "yellow", + "yo", + "you", + "young" + ] +} diff --git a/src/no-bad-emotes/index.js b/src/no-bad-emotes/index.js new file mode 100644 index 00000000..4c7dd69f --- /dev/null +++ b/src/no-bad-emotes/index.js @@ -0,0 +1,290 @@ +const { has, addWordSeparators, glob_to_regex, escape_regex } = FrankerFaceZ.utilities.object; + + +const COMMON_WORDS = require('./common.json'); + +const TERM_FLAGS = ['g', 'gi']; + +function formatTerms(data) { + const out = []; + + for(let i=0; i < data.length; i++) { + const list = data[i]; + if ( list[0].length ) + list[1].push(`^(?:${list[0].join('|')})$`); + + out.push(list[1].length ? new RegExp(list[1].join('|'), TERM_FLAGS[i] || 'gi') : null); + } + + return out; +} + +class NoBadEmotes extends Addon { + + constructor(name, parent) { + super(name, parent); + + this._use_common = null; + + this.inject('chat.emotes'); + + this.doesEmoteMatch = this.doesEmoteMatch.bind(this); + + // Settings + this.settings.add('addon.nobademotes.no-filter-personal', { + default: false, + ui: { + path: 'Add-Ons > No Bad Emotes >> General @{"sort": -99}', + title: 'Do not filter emotes out of personal emote sets.', + component: 'setting-check-box' + }, + changed: () => this.emotes.updateFiltered() + }); + + this.settings.add('addon.nobademotes.no-filter-global', { + default: false, + ui: { + path: 'Add-Ons > No Bad Emotes >> General @{"sort": -99}', + title: 'Do not filter emotes out of global emote sets.', + component: 'setting-check-box' + }, + changed: () => this.emotes.updateFiltered() + }); + + this.settings.add('addon.nobademotes.use-all-lower', { + default: false, + ui: { + path: 'Add-Ons > No Bad Emotes >> Basic', + title: 'Filter out emotes with names that are all lowercase letters.', + component: 'setting-check-box' + }, + changed: () => this.emotes.updateFiltered() + }); + + this.settings.add('addon.nobademotes.ban-short', { + default: false, + ui: { + path: 'Add-Ons > No Bad Emotes >> Basic', + title: 'Filter out emotes with names shorter than 3 characters.', + component: 'setting-check-box' + }, + changed: () => this.emotes.updateFiltered() + }); + + this.settings.add('addon.nobademotes.custom-names', { + default: [], + type: 'array_merge', + always_inherit: true, + ui: { + path: 'Add-Ons > No Bad Emotes >> Custom Words @{"description": "Flexible filters for removing emotes based on their name. Please see [Chat > Filtering > Syntax Help](~) for details on how to use this."}', + component: 'basic-terms' + } + }); + + this.settings.add('__filter:addon.nobademotes.custom-names', { + requires: ['addon.nobademotes.custom-names'], + equals: 'requirements', + process(ctx) { + const val = ctx.get('addon.nobademotes.custom-names'); + if ( ! val || ! val.length ) + return null; + + const data = [ + [ // sensitive + [], [] // word + ], + [ // intensitive + [], [] + ] + ]; + + let had_non = false; + + for(const item of val) { + const t = item.t, + sensitive = item.s, + word = has(item, 'w') ? item.w : t !== 'raw'; + let v = item.v; + + if ( t === 'glob' ) + v = glob_to_regex(v); + + else if ( t !== 'regex' && t !== 'raw' ) + v = escape_regex(v); + + if ( ! v || ! v.length ) + continue; + + had_non = true; + + data[sensitive ? 0 : 1][word ? 0 : 1].push(v); + } + + if ( ! had_non ) + return null; + + return had_non ? formatTerms(data) : null + }, + changed: () => this.emotes.updateFiltered() + }); + + this.settings.add('addon.nobademotes.use-common', { + default: true, + ui: { + path: 'Add-Ons > No Bad Emotes >> Common Words', + title: 'Filter out emotes with names matching a list of common English words.', + component: 'setting-check-box' + }, + changed: val => this.onUseCommon(val) + }); + + this.settings.add('addon.nobademotes.capitalization-mode', { + default: 0, + ui: { + path: 'Add-Ons > No Bad Emotes >> Common Words', + title: 'Capitalization Mode', + sort: 99, + description: 'By default, we only filter common words if the emote name is all lower-case. You can optionally include emotes with the first letter capitalized.', + component: 'setting-select-box', + data: [ + {value: 0, title: 'Lowercase Only'}, + {value: 1, title: 'Lowercase or Initial Capital'} + ] + }, + changed: () => { + if ( this._use_common && this.common_words?.length ) + this.emotes.updateFiltered() + } + }); + + } + + onEnable() { + // Call this before adding our filter so we only process once. + this.onUseCommon(this.settings.get('addon.nobademotes.use-common')); + + this.emotes.addFilter({ + type: 'nobademotes', + test: this.doesEmoteMatch + }); + } + + onDisable() { + this.emotes.removeFilter('nobademotes'); + } + + // Common Words + + onUseCommon(val) { + // No change? No problem :D + if ( this._use_common === val ) + return; + + // Check if we have set this before. We don't update filters the first + // time around. + const was_set = this._use_common == null; + + // And update the value. + this._use_common = val; + + // If we're just disabling, or if we've already loaded, then we don't + // need to worry about loading. + if ( ! val || this.common_words ) { + // But we might need to update the filters. + if ( was_set ) + this.emotes.updateFiltered(); + return; + } + + this.loadCommonWords(); + } + + async loadCommonWords() { + if ( this._loading_common || this.common_words?.length ) + return; + + this._loading_common = true; + + let data; + try { + data = await fetch(COMMON_WORDS).then(resp => resp.ok ? resp.json() : null); + } catch(err) { + this.log.warn('Unable to load common words list.', err); + this._loading_common = false; + return; + } + + if ( ! Array.isArray(data?.words) ) { + this._loading_common = false; + this.common_words = []; + return; + } + + this._loading_common = false; + this.common_words = data.words; + this.log.info(`Loaded ${data.words.length} common words.`); + + if ( this._use_common ) + this.emotes.updateFiltered(); + } + + + // Filtering + + doesEmoteMatch(emote, set) { + if ( set ) { + if ( this.settings.get('addon.nobademotes.no-filter-global') && this.emotes.default_sets.includes(set.id) ) + return false; + + if ( set.personal && this.settings.get('addon.nobademotes.no-filter-personal') ) + return false; + } + + const no_short = this.settings.get('addon.nobademotes.ban-short'); + if ( no_short && emote.name.length < 3 ) + return true; + + const lname = emote.name.toLowerCase(); + + const no_lower = this.settings.get('addon.nobademotes.use-all-lower'); + if ( no_lower && lname === emote.name ) + return true; + + if ( this.doesCommonNameMatch(emote, lname) ) + return true; + + if ( this.doesCustomMatch(emote) ) + return true; + } + + doesCommonNameMatch(emote, lname) { + if ( ! this._use_common || ! this.common_words ) + return false; + + const cap_mode = this.settings.get('addon.nobademotes.capitalization-mode'); + if ( cap_mode === 0 && lname !== emote.name ) + return false; + + if ( cap_mode === 1 && emote.name.slice(1) !== lname.slice(1) ) + return false; + + return this.common_words.includes(lname); + } + + doesCustomMatch(emote) { + const filters = this.settings.get('__filter:addon.nobademotes.custom-names'); + if ( ! filters ) + return false; + + for(let i = 0; i < filters.length; i++) { + if ( filters[i] ) { + filters[i].lastIndex = -1; + if ( filters[i].test(emote.name) ) + return true; + } + } + } + +} + +NoBadEmotes.register(); diff --git a/src/no-bad-emotes/manifest.json b/src/no-bad-emotes/manifest.json new file mode 100644 index 00000000..4448577b --- /dev/null +++ b/src/no-bad-emotes/manifest.json @@ -0,0 +1,13 @@ +{ + "enabled": true, + "requires": [], + "version": "1.0.0", + "icon": "https://cdn.frankerfacez.com/badge/2/4/solid", + "short_name": "NoBadEmotes", + "name": "No Bad Emotes", + "author": "SirStendec", + "description": "This add-on removes undesired emotes from chat, so you only see the words. Tired of people using replacing stupidly common words like 'the' with emotes using platforms without any sort of common sense restrictions? Just grab this.", + "settings": "add_ons.no_bad_emotes", + "created": "2024-01-24T20:02:45.938Z", + "updated": "2024-01-24T20:02:45.938Z" +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index b492f30a..5b5375b0 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -216,6 +216,16 @@ const config = { target: TARGET } }, + { + test: /\.json$/, + include: /src/, + type: 'asset/resource', + generator: { + filename: (FOR_EXTENSION || DEV_BUILD) + ? '[name].json' + : '[name].[contenthash:8].json' + } + }, { test: /\.(graphql|gql)$/, exclude: /node_modules/,