From 5f0d4b2bfeb928445984ce05dd1eb2e3eb951e0e Mon Sep 17 00:00:00 2001 From: SirStendec Date: Mon, 3 May 2021 15:33:03 -0400 Subject: [PATCH] 4.22.2 * Added: Option to display debugging information in chat when highlight filters are applied to a message. * Changed: Treat a completely transparent highlight color as removing highlights from a message. This allows rules such as preventing messages from bots (Bot Badge) from being highlighted. * Fixed: Detect an invalid IndexedDB database and recreate it when necessary. * API Added: `applyHighlight(msg, priority, color, reason)` method for tokenizers. --- package.json | 2 +- src/modules/chat/index.js | 82 ++++++++++++++++-- src/modules/chat/tokenizers.jsx | 84 +++++++++---------- .../components/badge-term-editor.vue | 13 ++- .../main_menu/components/term-editor.vue | 25 ++++-- src/settings/providers.js | 61 +++++++++++++- .../twitch-twilight/modules/chat/line.js | 5 +- src/std-components/color-picker.vue | 23 ++++- 8 files changed, 225 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 09bfd677..e1f0c4d4 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.22.1", + "version": "4.22.2", "description": "FrankerFaceZ is a Twitch enhancement suite.", "private": true, "license": "Apache-2.0", diff --git a/src/modules/chat/index.js b/src/modules/chat/index.js index 55fbf2fa..3c60e635 100644 --- a/src/modules/chat/index.js +++ b/src/modules/chat/index.js @@ -8,7 +8,8 @@ import dayjs from 'dayjs'; import Module from 'utilities/module'; import {createElement, ManagedStyle} from 'utilities/dom'; -import {timeout, has, glob_to_regex, escape_regex, split_chars, deep_copy} from 'utilities/object'; +import {timeout, has, glob_to_regex, escape_regex, split_chars} from 'utilities/object'; +import {Color} from 'utilities/color'; import Badges from './badges'; import Emotes from './emotes'; @@ -258,6 +259,16 @@ export default class Chat extends Module { } }); + this.settings.add('chat.filtering.debug', { + default: false, + ui: { + path: 'Chat > Filtering > General >> Behavior', + title: 'Display a list of highlight reasons on every chat message for debugging.', + component: 'setting-check-box', + force_seen: true + } + }); + this.settings.addUI('chat.filtering.pad-bottom', { path: 'Chat > Filtering > Highlight', sort: 1000, @@ -414,7 +425,7 @@ export default class Chat extends Module { type: 'array_merge', always_inherit: true, ui: { - path: 'Chat > Filtering > Highlight @{"description": "These settings allow you to highlight messages in chat based on their contents. Setting priorities on rules allows you to determine which highlight color should be applied if a message matches multiple rules. Rules with a higher priority take priority over rules with lower priorities."} >> Users', + path: 'Chat > Filtering > Highlight @{"description": "These settings allow you to highlight messages in chat based on their contents. Setting priorities on rules allows you to determine which highlight color should be applied if a message matches multiple rules. Rules with a higher priority take priority over rules with lower priorities.\\n\\nYou can also create a rule that removes highlights from messages, preventing lower priority rules from highlighting them, by setting a color with an alpha value of zero. Example: `#00000000`"} >> Users', component: 'basic-terms', colored: true, words: false, @@ -433,10 +444,10 @@ export default class Chat extends Module { const temp = new Map; for(const item of val) { - const c = item.c || null, - p = item.p || 0, + const p = item.p || 0, t = item.t; + let c = item.c || null; let v = item.v; if ( t === 'glob' ) @@ -460,6 +471,12 @@ export default class Chat extends Module { temp.set(p, colors); } + if ( c ) { + const test = Color.RGBA.fromCSS(c); + if ( ! test || ! test.a ) + c = false; + } + if ( colors.has(c) ) colors.get(c).push(v); else { @@ -558,10 +575,16 @@ export default class Chat extends Module { const badges = new Map; for(const item of val) { - const c = item.c || null, - p = item.p || 0, + let c = item.c || null; + const p = item.p || 0, v = item.v; + if ( c ) { + const test = Color.RGBA.fromCSS(c); + if ( ! test || ! test.a ) + c = false; + } + const existing = badges.get(v); if ( ! existing || existing[0] < p || (c && ! existing[1] && existing[0] <= p) ) badges.set(v, [p, c]); @@ -633,13 +656,13 @@ export default class Chat extends Module { has_non = false; for(const item of val) { - const c = item.c || null, - p = item.p || 0, + const p = item.p || 0, highlight = can_highlight && (has(item, 'h') ? item.h : true), sensitive = item.s, t = item.t, word = has(item, 'w') ? item.w : t !== 'raw'; + let c = item.c || null; let v = item.v; if ( t === 'glob' ) @@ -668,6 +691,12 @@ export default class Chat extends Module { temp.set(p, colors); } + if ( c ) { + const test = Color.RGBA.fromCSS(c); + if ( ! test || ! test.a ) + c = false; + } + let data = colors.get(c); if ( ! data ) colors.set(c, data = [ @@ -1449,6 +1478,43 @@ export default class Chat extends Module { } + applyHighlight(msg, priority, color, reason, use_null_color = false) { // eslint-disable-line class-methods-use-this + if ( ! msg ) + return msg; + + const is_null = msg.mention_priority == null, + matched = is_null || priority >= msg.mention_priority, + higher = is_null || priority > msg.mention_priority; + + if ( msg.filters ) + msg.filters.push(`${reason}(${priority})${matched && color === false ? ':remove' : color ? `:${color}` : ''}`); + + if ( matched ) { + msg.mention_priority = priority; + + if ( color === false ) { + if ( higher ) { + msg.mentioned = false; + msg.clear_priority = priority; + msg.mention_color = msg.highlights = null; + } + + return; + } + + msg.mentioned = true; + if ( ! msg.highlights ) + msg.highlights = new Set; + } + + if ( msg.mentioned && (msg.clear_priority == null || priority >= msg.clear_priority) ) { + msg.highlights.add(reason); + if ( (color || use_null_color) && (higher || ! msg.mention_color) ) + msg.mention_color = color; + } + } + + standardizeMessage(msg) { // eslint-disable-line class-methods-use-this if ( ! msg ) return msg; diff --git a/src/modules/chat/tokenizers.jsx b/src/modules/chat/tokenizers.jsx index 1e02defc..b338b8e7 100644 --- a/src/modules/chat/tokenizers.jsx +++ b/src/modules/chat/tokenizers.jsx @@ -19,6 +19,35 @@ const EMOTE_CLASS = 'chat-image chat-line__message--emote', MENTION_REGEX = /^(['"*([{<\\/]*)(@)((?:[^\u0000-\u007F]|[\w-])+)(?:\b|$)/; // eslint-disable-line no-control-regex +export const FilterTester = { + type: 'filter_test', + priority: 1000, + + render(token, createElement) { + if ( ! token.msg.filters?.length ) + return null; + + return (
+ { token.msg.filters.join(', ') } +
); + }, + + process(tokens, msg) { + if ( ! tokens || ! tokens.length || ! this.context.get('chat.filtering.debug') ) + return tokens; + + msg.filters = []; + + tokens.push({ + type: 'filter_test', + msg + }); + + return tokens; + } +} + + // ============================================================================ // Links // ============================================================================ @@ -406,14 +435,8 @@ export const Mentions = { recipient: rlower }); - if ( mentioned ) { - (msg.highlights = (msg.highlights || new Set())).add('mention'); - msg.mentioned = true; - if ( msg.color_priority == null || priority > msg.color_priority ) { - msg.mention_color = null; - msg.color_priority = priority; - } - } + if ( mentioned ) + this.applyHighlight(msg, priority, null, 'mention', true); // Push the remaining text from the token. text.push(segment.substr(match[0].length)); @@ -449,17 +472,8 @@ export const UserHighlights = { const u = msg.user; for(const [priority, color, regex] of list) { - if ( regex.test(u.login) || regex.test(u.displayName) ) { - (msg.highlights = (msg.highlights || new Set())).add('user'); - msg.mentioned = true; - if ( color ) { - if ( msg.color_priority == null || priority > msg.color_priority ) { - msg.mention_color = color; - msg.color_priority = priority; - } - return tokens; - } - } + if ( regex.test(u.login) || regex.test(u.displayName) ) + this.applyHighlight(msg, priority, color, 'user'); } return tokens; @@ -539,16 +553,8 @@ export const BadgeStuff = { if ( highlights && highlights.has(badge) ) { const details = highlights.get(badge); - (msg.highlights = (msg.highlights || new Set())).add('badge'); - msg.mentioned = true; - if ( details[1] ) { - if ( msg.color_priority == null || details[0] > msg.color_priority ) { - msg.mention_color = details[1]; - msg.color_priority = details[0]; - } - if ( ! list ) - return tokens; - } + if ( Array.isArray(details) && details.length > 1 ) + this.applyHighlight(msg, details[0], details[1], 'badge'); } } @@ -612,7 +618,7 @@ export const CustomHighlights = { let had_match = false; if ( data.non ) { for(const [priority, color, regexes] of data.non) { - if ( had_match && msg.color_priority != null && msg.color_priority > priority ) + if ( had_match && msg.mention_priority != null && msg.mention_priority > priority ) break; let matched = false; @@ -626,17 +632,8 @@ export const CustomHighlights = { } if ( matched ) { - (msg.highlights = (msg.highlights || new Set())).add('term'); - msg.mentioned = true; had_match = true; - if ( color ) { - if ( msg.color_priority == null || priority > msg.color_priority ) { - msg.mention_color = color; - msg.color_priority = priority; - } - - break; - } + this.applyHighlight(msg, priority, color, 'term'); } } } @@ -676,12 +673,7 @@ export const CustomHighlights = { if ( idx !== nix ) out.push({type: 'text', text: text.slice(idx, nix)}); - (msg.highlights = (msg.highlights || new Set())).add('term'); - msg.mentioned = true; - if ( color && (msg.color_priority == null || priority > msg.color_priority) ) { - msg.mention_color = color; - msg.color_priority = priority; - } + this.applyHighlight(msg, priority, color, 'term'); out.push({ type: 'highlight', diff --git a/src/modules/main_menu/components/badge-term-editor.vue b/src/modules/main_menu/components/badge-term-editor.vue index 3da3e1f9..53245b02 100644 --- a/src/modules/main_menu/components/badge-term-editor.vue +++ b/src/modules/main_menu/components/badge-term-editor.vue @@ -44,11 +44,20 @@
- -
+ +
 
+
+ {{ t('settings.term.color.tip', 'Color') }} +
-
- -
-
-   -
-
-
{{ term_type }}
+
+ +
+
+   +
+
+ {{ t('settings.term.color.tip', 'Color') }} +
+
+
{ + if ( this.manager ) + this.manager.log.error('Error deleting invalid database.', e); + done(false, e); + this._onFinish(delreq); + } + + delreq.onsuccess = () => { + if ( this.manager ) + this.manager.log.info('Deleted invalid database.'); + + this._onFinish(delreq); + this._listeners = null; + this.getDB(true).then(result => { + for(const pair of listeners) + pair[0](result); + }).catch(err => { + for(const pair of listeners) + pair[1](err); + }); + } + } + + return; + } + done(true, this.db); this._onFinish(request); } diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index 90f3e138..35afef95 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -83,6 +83,7 @@ export default class ChatLine extends Module { this.chat.context.on('changed:chat.filtering.process-own', this.updateLines, this); this.chat.context.on('changed:chat.timestamp-format', this.updateLines, this); this.chat.context.on('changed:chat.filtering.mention-priority', this.updateLines, this); + this.chat.context.on('changed:chat.filtering.debug', this.updateLines, this); this.chat.context.on('changed:__filter:highlight-terms', this.updateLines, this); this.chat.context.on('changed:__filter:highlight-users', this.updateLines, this); this.chat.context.on('changed:__filter:highlight-badges', this.updateLines, this); @@ -1061,7 +1062,7 @@ other {# messages were deleted by a moderator.} if ( msg ) { msg.ffz_tokens = null; msg.ffz_badges = null; - msg.highlights = msg.mentioned = msg.mention_color = msg.color_priority = null; + msg.highlights = msg.mentioned = msg.mention_color = msg.mention_priority = msg.clear_priority = null; } } @@ -1070,7 +1071,7 @@ other {# messages were deleted by a moderator.} if ( msg ) { msg.ffz_tokens = null; msg.ffz_badges = null; - msg.highlights = msg.mentioned = msg.mention_color = msg.color_priority = null; + msg.highlights = msg.mentioned = msg.mention_color = msg.mention_priority = msg.clear_priority = null; } } diff --git a/src/std-components/color-picker.vue b/src/std-components/color-picker.vue index 936e0d93..e8cdce28 100644 --- a/src/std-components/color-picker.vue +++ b/src/std-components/color-picker.vue @@ -31,7 +31,11 @@
-
+
+
+ {{ tooltip }} +
+ {{ t('setting.color.nullable', 'Right-Click to Reset') }} +
+
@@ -88,6 +101,10 @@ export default { type: Boolean, default: true }, + tooltip: { + type: String, + default: null + }, openUp: { type: Boolean, default: false @@ -103,6 +120,10 @@ export default { }, computed: { + hasTooltip() { + return this.tooltip?.length > 0 || this.nullable + }, + colors() { try { return Color.RGBA.fromCSS(this.color || this.default)