mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.20.33
* Added: Setting to filter out chat messages by type. Can be used to remove hosting and raid notices, among other things. * Added: Support for clicking badges. It's a native feature that's been missing for ages. * Changed: Make headers slightly bigger in settings so that they stand out more. * Fixed: Certain settings inheriting default values when they should not. * Fixed: Bug in the FFZ Emote Menu when garbage subscription data is returned from Twitch. * Fixed: Do not suppress error messages in the console when an error happens in an event handler.
This commit is contained in:
parent
fd2977f899
commit
129f350a80
12 changed files with 626 additions and 200 deletions
305
.eslintrc.js
305
.eslintrc.js
|
@ -1,158 +1,159 @@
|
|||
/* globals module */
|
||||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:vue/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"vue",
|
||||
"react"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint",
|
||||
"ecmaVersion": 8,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "createElement"
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"import": false,
|
||||
"require": false,
|
||||
"__webpack_hash__": false,
|
||||
"__git_commit__": false,
|
||||
"__version_major__": false,
|
||||
"__version_minor__": false,
|
||||
"__version_patch__": false,
|
||||
"__version_prerelease__": false,
|
||||
"FrankerFaceZ": false
|
||||
},
|
||||
"rules": {
|
||||
"require-atomic-updates": "off",
|
||||
"accessor-pairs": ["error"],
|
||||
"block-scoped-var": ["error"],
|
||||
"class-methods-use-this": ["error"],
|
||||
"for-direction": ["error"],
|
||||
"guard-for-in": ["warn"],
|
||||
"no-alert": ["error"],
|
||||
"no-await-in-loop": ["error"],
|
||||
"no-caller": ["error"],
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-invalid-this": ["error"],
|
||||
"no-iterator": ["error"],
|
||||
"no-labels": ["error"],
|
||||
"no-lone-blocks": ["error"],
|
||||
"no-octal-escape": ["error"],
|
||||
"no-proto": ["warn"],
|
||||
"no-return-await": ["error"],
|
||||
"no-self-compare": ["error"],
|
||||
"no-sequences": ["error"],
|
||||
"no-shadow-restricted-names": ["error"],
|
||||
"no-template-curly-in-string": ["warn"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-undef-init": ["error"],
|
||||
"no-unmodified-loop-condition": ["error"],
|
||||
"no-use-before-define": ["error", {
|
||||
"functions": false,
|
||||
"classes": false
|
||||
}],
|
||||
"no-useless-call": ["warn"],
|
||||
"no-useless-concat": ["warn"],
|
||||
"no-useless-return": ["warn"],
|
||||
"no-void": ["error"],
|
||||
"no-warning-comments": ["warn"],
|
||||
"no-with": ["error"],
|
||||
"radix": ["error"],
|
||||
"require-await": ["warn"],
|
||||
"valid-jsdoc": ["warn"],
|
||||
"yoda": ["warn"],
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es6': true
|
||||
},
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:vue/recommended'
|
||||
],
|
||||
'plugins': [
|
||||
'vue',
|
||||
'react'
|
||||
],
|
||||
'parserOptions': {
|
||||
'parser': 'babel-eslint',
|
||||
'ecmaVersion': 8,
|
||||
'sourceType': 'module',
|
||||
'ecmaFeatures': {
|
||||
'jsx': true
|
||||
}
|
||||
},
|
||||
'settings': {
|
||||
'react': {
|
||||
'pragma': 'createElement'
|
||||
}
|
||||
},
|
||||
'globals': {
|
||||
'import': false,
|
||||
'require': false,
|
||||
'__webpack_hash__': false,
|
||||
'__git_commit__': false,
|
||||
'__version_major__': false,
|
||||
'__version_minor__': false,
|
||||
'__version_patch__': false,
|
||||
'__version_prerelease__': false,
|
||||
'FrankerFaceZ': false
|
||||
},
|
||||
'rules': {
|
||||
'require-atomic-updates': 'off',
|
||||
'accessor-pairs': ['error'],
|
||||
'block-scoped-var': ['error'],
|
||||
'class-methods-use-this': ['error'],
|
||||
'for-direction': ['error'],
|
||||
'guard-for-in': ['warn'],
|
||||
'no-alert': ['error'],
|
||||
'no-await-in-loop': ['error'],
|
||||
'no-caller': ['error'],
|
||||
'no-catch-shadow': ['error'],
|
||||
'no-invalid-this': ['error'],
|
||||
'no-iterator': ['error'],
|
||||
'no-labels': ['error'],
|
||||
'no-lone-blocks': ['error'],
|
||||
'no-octal-escape': ['error'],
|
||||
'no-proto': ['warn'],
|
||||
'no-return-await': ['error'],
|
||||
'no-self-compare': ['error'],
|
||||
'no-sequences': ['error'],
|
||||
'no-shadow-restricted-names': ['error'],
|
||||
'no-template-curly-in-string': ['warn'],
|
||||
'no-throw-literal': ['error'],
|
||||
'no-undef-init': ['error'],
|
||||
'no-unmodified-loop-condition': ['error'],
|
||||
'no-use-before-define': ['error', {
|
||||
'functions': false,
|
||||
'classes': false
|
||||
}],
|
||||
'no-useless-call': ['warn'],
|
||||
'no-useless-concat': ['warn'],
|
||||
'no-useless-return': ['warn'],
|
||||
'no-void': ['error'],
|
||||
'no-warning-comments': ['warn'],
|
||||
'no-with': ['error'],
|
||||
'radix': ['error'],
|
||||
'require-await': ['warn'],
|
||||
'valid-jsdoc': ['warn'],
|
||||
'yoda': ['warn'],
|
||||
|
||||
"arrow-body-style": ["warn", "as-needed"],
|
||||
"arrow-parens": ["warn", "as-needed"],
|
||||
"arrow-spacing": ["warn"],
|
||||
"generator-star-spacing": ["warn"],
|
||||
"no-duplicate-imports": ["error"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-constructor": ["error"],
|
||||
"no-useless-rename": ["error"],
|
||||
"no-var": ["error"],
|
||||
"no-cond-assign": ["warn"],
|
||||
"object-shorthand": ["warn"],
|
||||
"prefer-arrow-callback": ["warn", {"allowUnboundThis": true}],
|
||||
"prefer-const": ["warn", {"ignoreReadBeforeAssign": true}],
|
||||
"prefer-rest-params": ["warn"],
|
||||
"prefer-spread": ["error"],
|
||||
"prefer-template": ["warn"],
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
"yield-star-spacing": ["warn"],
|
||||
'arrow-body-style': ['warn', 'as-needed'],
|
||||
'arrow-parens': ['warn', 'as-needed'],
|
||||
'arrow-spacing': ['warn'],
|
||||
'generator-star-spacing': ['warn'],
|
||||
'no-duplicate-imports': ['error'],
|
||||
'no-useless-computed-key': ['error'],
|
||||
'no-useless-constructor': ['error'],
|
||||
'no-useless-rename': ['error'],
|
||||
'no-var': ['error'],
|
||||
'no-cond-assign': ['warn'],
|
||||
'object-shorthand': ['warn'],
|
||||
'prefer-arrow-callback': ['warn', {'allowUnboundThis': true}],
|
||||
'prefer-const': ['warn', {'ignoreReadBeforeAssign': true}],
|
||||
'prefer-rest-params': ['warn'],
|
||||
'prefer-spread': ['error'],
|
||||
'prefer-template': ['warn'],
|
||||
'rest-spread-spacing': ['error', 'never'],
|
||||
'yield-star-spacing': ['warn'],
|
||||
|
||||
"indent": [
|
||||
"warn",
|
||||
"tab",
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true
|
||||
}
|
||||
],
|
||||
'indent': [
|
||||
'warn',
|
||||
'tab',
|
||||
{
|
||||
'SwitchCase': 1
|
||||
}
|
||||
],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'quotes': [
|
||||
'error',
|
||||
'single',
|
||||
{
|
||||
'avoidEscape': true,
|
||||
'allowTemplateLiterals': true
|
||||
}
|
||||
],
|
||||
|
||||
"vue/html-indent": [
|
||||
"warn",
|
||||
"tab"
|
||||
],
|
||||
"vue/valid-template-root": "off",
|
||||
"vue/max-attributes-per-line": "off",
|
||||
"vue/require-prop-types": "off",
|
||||
"vue/require-default-prop": "off",
|
||||
"vue/html-closing-bracket-newline": [
|
||||
"error",
|
||||
{
|
||||
"singleline": "never",
|
||||
"multiline": "always"
|
||||
}
|
||||
],
|
||||
'vue/html-indent': [
|
||||
'warn',
|
||||
'tab'
|
||||
],
|
||||
'vue/valid-template-root': 'off',
|
||||
'vue/max-attributes-per-line': 'off',
|
||||
'vue/require-prop-types': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/html-closing-bracket-newline': [
|
||||
'error',
|
||||
{
|
||||
'singleline': 'never',
|
||||
'multiline': 'always'
|
||||
}
|
||||
],
|
||||
|
||||
"jsx-quotes": ["error", "prefer-double"],
|
||||
"react/jsx-boolean-value": "error",
|
||||
"react/jsx-closing-bracket-location": ["error", "line-aligned"],
|
||||
//"react/jsx-closing-tag-location": "error" -- stupid rule that doesn't allow line-aligned
|
||||
"react/jsx-equals-spacing": "error",
|
||||
"react/jsx-filename-extension": "error",
|
||||
"react/jsx-first-prop-new-line": ["error", "multiline-multiprop"],
|
||||
"react/jsx-indent": ["warn", "tab"],
|
||||
"react/jsx-indent-props": ["warn", "tab"],
|
||||
//"react/jsx-key": "warn",
|
||||
"react/jsx-no-bind": "error",
|
||||
"react/jsx-no-comment-textnodes": "error",
|
||||
"react/jsx-no-duplicate-props": "error",
|
||||
"react/jsx-no-target-blank": "error",
|
||||
"react/jsx-sort-props": ["error", {
|
||||
"callbacksLast": true,
|
||||
"reservedFirst": true,
|
||||
"noSortAlphabetically": true
|
||||
}],
|
||||
"react/jsx-tag-spacing": ["error", {
|
||||
"beforeClosing": "never"
|
||||
}],
|
||||
"react/jsx-uses-react": "error",
|
||||
"react/jsx-wrap-multilines": "error"
|
||||
}
|
||||
'jsx-quotes': ['error', 'prefer-double'],
|
||||
'react/jsx-boolean-value': 'error',
|
||||
'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
|
||||
//'react/jsx-closing-tag-location': 'error' -- stupid rule that doesn't allow line-aligned
|
||||
'react/jsx-equals-spacing': 'error',
|
||||
'react/jsx-filename-extension': 'error',
|
||||
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
|
||||
'react/jsx-indent': ['warn', 'tab'],
|
||||
'react/jsx-indent-props': ['warn', 'tab'],
|
||||
//'react/jsx-key': 'warn',
|
||||
'react/jsx-no-bind': 'error',
|
||||
'react/jsx-no-comment-textnodes': 'error',
|
||||
'react/jsx-no-duplicate-props': 'error',
|
||||
'react/jsx-no-target-blank': 'error',
|
||||
'react/jsx-sort-props': ['error', {
|
||||
'callbacksLast': true,
|
||||
'reservedFirst': true,
|
||||
'noSortAlphabetically': true
|
||||
}],
|
||||
'react/jsx-tag-spacing': ['error', {
|
||||
'beforeClosing': 'never'
|
||||
}],
|
||||
'react/jsx-uses-react': 'error',
|
||||
'react/jsx-wrap-multilines': 'error'
|
||||
}
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "frankerfacez",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.20.32",
|
||||
"version": "4.20.33",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
|
|
@ -73,6 +73,8 @@ export default class Actions extends Module {
|
|||
],
|
||||
|
||||
type: 'array_merge',
|
||||
inherit_default: true,
|
||||
|
||||
ui: {
|
||||
path: 'Chat > Actions > In-Line @{"description": "Here, you can define custom actions that will appear along messages in chat. If you aren\'t seeing an action you\'ve defined here in chat, please make sure that you have enabled Mod Icons in the chat settings menu."}',
|
||||
component: 'chat-actions',
|
||||
|
@ -103,6 +105,8 @@ export default class Actions extends Module {
|
|||
|
||||
default: [],
|
||||
type: 'array_merge',
|
||||
inherit_default: true,
|
||||
|
||||
ui: {
|
||||
path: 'Chat > Actions > User Context @{"description": "Here, you can define custom actions that will appear in a context menu when you right-click a username in chat."}',
|
||||
component: 'chat-actions',
|
||||
|
@ -131,6 +135,8 @@ export default class Actions extends Module {
|
|||
|
||||
default: [],
|
||||
type: 'array_merge',
|
||||
inherit_default: true,
|
||||
|
||||
ui: {
|
||||
path: 'Chat > Actions > Room @{"description": "Here, you can define custom actions that will appear above the chat input box."}',
|
||||
component: 'chat-actions',
|
||||
|
|
|
@ -91,7 +91,7 @@ export function generateOverrideCSS(data, style) {
|
|||
}
|
||||
|
||||
|
||||
export function generateBadgeCSS(badge, version, data, style, is_dark, badge_version = 2, color_fixer, scale = 1) {
|
||||
export function generateBadgeCSS(badge, version, data, style, is_dark, badge_version = 2, color_fixer, scale = 1, clickable = false) {
|
||||
let color = data.color || 'transparent',
|
||||
base_image = data.image || `${BASE_IMAGE}${badge_version}/${badge}${data.svg ? '.svg' : `/${version}/`}`,
|
||||
trans = false,
|
||||
|
@ -148,7 +148,7 @@ export function generateBadgeCSS(badge, version, data, style, is_dark, badge_ver
|
|||
color = color_fixer.process(color) || color;
|
||||
|
||||
// TODO: Fix the click_url name once we actually support badge clicking.
|
||||
return `${data.__click_url ? 'cursor:pointer;' : ''}${invert ? 'filter:invert(100%);' : ''}${CSS_TEMPLATES[style]({
|
||||
return `${clickable && (data.click_url || data.click_action) ? 'cursor:pointer;' : ''}${invert ? 'filter:invert(100%);' : ''}${CSS_TEMPLATES[style]({
|
||||
scale: 1,
|
||||
color,
|
||||
image,
|
||||
|
@ -203,6 +203,16 @@ export default class Badges extends Module {
|
|||
}
|
||||
});
|
||||
|
||||
this.settings.add('chat.badges.clickable', {
|
||||
default: true,
|
||||
ui: {
|
||||
path: 'Chat > Badges >> Behavior',
|
||||
title: 'Allow clicking badges.',
|
||||
description: 'Certain badges, such as Prime Gaming, act as links when this is enabled.',
|
||||
component: 'setting-check-box'
|
||||
}
|
||||
});
|
||||
|
||||
this.settings.add('chat.badges.fix-colors', {
|
||||
default: true,
|
||||
ui: {
|
||||
|
@ -250,6 +260,8 @@ export default class Badges extends Module {
|
|||
]
|
||||
}
|
||||
});
|
||||
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
getSettingsBadges(include_addons) {
|
||||
|
@ -339,6 +351,7 @@ export default class Badges extends Module {
|
|||
this.parent.context.on('changed:chat.badges.version', this.rebuildAllCSS, this);
|
||||
this.parent.context.on('changed:chat.badges.media-queries', this.rebuildAllCSS, this);
|
||||
this.parent.context.on('changed:chat.badges.fix-colors', this.rebuildColoredBadges, this);
|
||||
this.parent.context.on('changed:chat.badges.clickable', this.rebuildAllCSS, this);
|
||||
|
||||
this.rebuildAllCSS();
|
||||
this.loadGlobalBadges();
|
||||
|
@ -434,6 +447,67 @@ export default class Badges extends Module {
|
|||
}
|
||||
|
||||
|
||||
handleClick(event) {
|
||||
if ( ! this.parent.context.get('chat.badges.clickable') )
|
||||
return;
|
||||
|
||||
const target = event.target;
|
||||
let container = target.parentElement.parentElement;
|
||||
if ( ! container.dataset.roomId )
|
||||
container = target.closest('[data-room-id]');
|
||||
|
||||
const room_id = container.dataset.roomId,
|
||||
room_login = container.dataset.room,
|
||||
data = JSON.parse(target.dataset.badgeData);
|
||||
|
||||
if ( data == null )
|
||||
return;
|
||||
|
||||
let url = null;
|
||||
|
||||
for(const d of data) {
|
||||
const p = d.provider;
|
||||
if ( p === 'twitch' ) {
|
||||
const bd = this.getTwitchBadge(d.badge, d.version, room_id, room_login),
|
||||
global_badge = this.getTwitchBadge(d.badge, d.version, null, null, true) || {};
|
||||
if ( ! bd )
|
||||
continue;
|
||||
|
||||
if ( bd.click_url )
|
||||
url = bd.click_url;
|
||||
else if ( global_badge.click_url )
|
||||
url = global_badge.click_url;
|
||||
else if ( (bd.click_action === 'sub' || global_badge.click_action === 'sub') && room_login )
|
||||
url = `https://www.twitch.tv/subs/${room_login}`;
|
||||
else
|
||||
continue;
|
||||
|
||||
break;
|
||||
|
||||
} else if ( p === 'ffz' ) {
|
||||
const badge = this.badges[target.dataset.badge];
|
||||
if ( badge?.click_url ) {
|
||||
url = badge.click_url;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.log.info('badge-click', event.target);
|
||||
|
||||
if ( url ) {
|
||||
const link = createElement('a', {
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer',
|
||||
href: url
|
||||
});
|
||||
link.click();
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
render(msg, createElement) { // eslint-disable-line class-methods-use-this
|
||||
const hidden_badges = this.parent.context.get('chat.badges.hidden') || {},
|
||||
badge_style = this.parent.context.get('chat.badges.style'),
|
||||
|
@ -603,6 +677,8 @@ export default class Badges extends Module {
|
|||
props['data-tooltip-type'] = 'badge';
|
||||
props['data-badge-data'] = JSON.stringify(data.badges);
|
||||
|
||||
props.onClick = this.handleClick;
|
||||
|
||||
if ( data.replaced )
|
||||
props['data-replaced'] = data.replaced;
|
||||
|
||||
|
@ -756,6 +832,7 @@ export default class Badges extends Module {
|
|||
buildBadgeCSS() {
|
||||
const style = this.parent.context.get('chat.badges.style'),
|
||||
is_dark = this.parent.context.get('theme.is-dark'),
|
||||
can_click = this.parent.context.get('chat.badges.clickable'),
|
||||
use_media = IS_FIREFOX && this.parent.context.get('chat.badges.media-queries');
|
||||
|
||||
const out = [];
|
||||
|
@ -767,11 +844,11 @@ export default class Badges extends Module {
|
|||
out.push(`.ffz-badge[data-replaced="${key}"]{${generateOverrideCSS(data, style, is_dark)}}`);
|
||||
|
||||
if ( use_media ) {
|
||||
out.push(`@media (max-resolution: 99dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, 1)}}}`);
|
||||
out.push(`@media (min-resolution: 100dpi) and (max-resolution:199dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, 2)}}}`);
|
||||
out.push(`@media (min-resolution: 200dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, 4)}}}`);
|
||||
out.push(`@media (max-resolution: 99dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, 1, can_click)}}}`);
|
||||
out.push(`@media (min-resolution: 100dpi) and (max-resolution:199dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, 2, can_click)}}}`);
|
||||
out.push(`@media (min-resolution: 200dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, 4, can_click)}}}`);
|
||||
} else
|
||||
out.push(`${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer)}}`);
|
||||
out.push(`${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, undefined, can_click)}}`);
|
||||
}
|
||||
|
||||
this.style.set('ext-badges', out.join('\n'));
|
||||
|
@ -823,6 +900,8 @@ export default class Badges extends Module {
|
|||
__cat: getBadgeCategory(sid)
|
||||
};
|
||||
|
||||
fixBadgeData(data);
|
||||
|
||||
this.twitch_badge_count++;
|
||||
bs[data.version] = data;
|
||||
}
|
||||
|
@ -832,32 +911,42 @@ export default class Badges extends Module {
|
|||
}
|
||||
|
||||
this.buildTwitchBadgeCSS();
|
||||
this.buildTwitchCSSBadgeCSS();
|
||||
}
|
||||
|
||||
|
||||
buildTwitchCSSBadgeCSS() {
|
||||
const style = this.parent.context.get('chat.badges.style'),
|
||||
is_dark = this.parent.context.get('theme.is-dark'),
|
||||
can_click = this.parent.context.get('chat.badges.clickable'),
|
||||
use_media = IS_FIREFOX && this.parent.context.get('chat.badges.media-queries'),
|
||||
|
||||
badge_version = this.parent.context.get('chat.badges.version'),
|
||||
versioned = CSS_BADGES[badge_version] || {};
|
||||
versioned = CSS_BADGES[badge_version] || {},
|
||||
twitch_data = this.twitch_badges || {};
|
||||
|
||||
const out = [];
|
||||
for(const key in versioned)
|
||||
if ( has(versioned, key) ) {
|
||||
const data = versioned[key];
|
||||
const data = versioned[key],
|
||||
twitch = twitch_data[key];
|
||||
for(const version in data)
|
||||
if ( has(data, version) ) {
|
||||
const d = data[version],
|
||||
td = twitch?.[version],
|
||||
selector = `.ffz-badge[data-badge="${key}"][data-version="${version}"]`;
|
||||
|
||||
if ( td && td.click_url )
|
||||
d.click_url = td.click_url;
|
||||
if ( td && td.click_action )
|
||||
d.click_action = td.click_action;
|
||||
|
||||
if ( use_media ) {
|
||||
out.push(`@media (max-resolution: 99dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, 1)}}}`);
|
||||
out.push(`@media (min-resolution: 100dpi) and (max-resolution:199dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, 2)}}}`);
|
||||
out.push(`@media (min-resolution: 200dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, 4)}}}`);
|
||||
out.push(`@media (max-resolution: 99dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, 1, can_click)}}}`);
|
||||
out.push(`@media (min-resolution: 100dpi) and (max-resolution:199dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, 2, can_click)}}}`);
|
||||
out.push(`@media (min-resolution: 200dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, 4, can_click)}}}`);
|
||||
} else
|
||||
out.push(`${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer)}}`);
|
||||
out.push(`${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, undefined, can_click)}}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -871,6 +960,7 @@ export default class Badges extends Module {
|
|||
|
||||
const badge_version = this.parent.context.get('chat.badges.version'),
|
||||
use_media = IS_FIREFOX && this.parent.context.get('chat.badges.media-queries'),
|
||||
can_click = this.parent.context.get('chat.badges.clickable'),
|
||||
versioned = CSS_BADGES[badge_version] || {};
|
||||
|
||||
const out = [];
|
||||
|
@ -886,6 +976,7 @@ export default class Badges extends Module {
|
|||
selector = `.ffz-badge[data-badge="${key}"][data-version="${version}"]`;
|
||||
|
||||
out.push(`${selector} {
|
||||
${can_click && (data.click_action || data.click_url) ? 'cursor:pointer;' : ''}
|
||||
background-color: transparent;
|
||||
filter: none;
|
||||
${WEBKIT}mask-image: none;
|
||||
|
@ -917,7 +1008,7 @@ export default class Badges extends Module {
|
|||
}
|
||||
|
||||
|
||||
function getBadgeCategory(key) {
|
||||
export function getBadgeCategory(key) {
|
||||
if ( key.startsWith('overwatch-league') )
|
||||
return 'm-owl';
|
||||
else if ( key.startsWith('twitchcon') )
|
||||
|
@ -926,4 +1017,34 @@ function getBadgeCategory(key) {
|
|||
return 'm-game';
|
||||
|
||||
return 'm-twitch';
|
||||
}
|
||||
|
||||
export function fixBadgeData(badge) {
|
||||
if ( ! badge )
|
||||
return badge;
|
||||
|
||||
// Click Behavior
|
||||
if ( badge.clickAction === 'VISIT_URL' && badge.clickURL )
|
||||
badge.click_url = badge.clickURL;
|
||||
|
||||
if ( badge.clickAction === 'TURBO' )
|
||||
badge.click_url = 'https://www.twitch.tv/products/turbo?ref=chat_badge';
|
||||
|
||||
if ( badge.clickAction === 'SUBSCRIBE' && badge.channelName )
|
||||
badge.click_url = `https://www.twitch.tv/subs/${badge.channelName}`;
|
||||
else if ( badge.clickAction )
|
||||
badge.click_action = 'sub';
|
||||
|
||||
// Subscriber Tier
|
||||
if ( badge.setID === 'subscriber' ) {
|
||||
const id = parseInt(badge.version, 10);
|
||||
if ( ! isNaN(id) && isFinite(id) ) {
|
||||
badge.tier = (id - (id % 1000)) / 1000;
|
||||
if ( badge.tier < 0 )
|
||||
badge.tier = 0;
|
||||
} else
|
||||
badge.tier = 0;
|
||||
}
|
||||
|
||||
return badge;
|
||||
}
|
|
@ -10,6 +10,7 @@ import {NEW_API, API_SERVER, WEBKIT_CSS as WEBKIT, IS_FIREFOX} from 'utilities/c
|
|||
|
||||
import {ManagedStyle} from 'utilities/dom';
|
||||
import {has, SourcedSet, set_equals} from 'utilities/object';
|
||||
import { getBadgeCategory, fixBadgeData } from './badges';
|
||||
|
||||
|
||||
export default class Room {
|
||||
|
@ -399,17 +400,11 @@ export default class Room {
|
|||
const b = {};
|
||||
for(const data of badges) {
|
||||
const sid = data.setID,
|
||||
bs = b[sid] = b[sid] || {};
|
||||
bs = b[sid] = b[sid] || {
|
||||
__cat: getBadgeCategory(sid)
|
||||
};
|
||||
|
||||
if ( sid === 'subscriber' ) {
|
||||
const id = parseInt(data.version, 10);
|
||||
if ( ! isNaN(id) && isFinite(id) ) {
|
||||
data.tier = (id - (id % 1000)) / 1000;
|
||||
if ( data.tier < 0 )
|
||||
data.tier = 0;
|
||||
} else
|
||||
data.tier = 0;
|
||||
}
|
||||
fixBadgeData(data);
|
||||
|
||||
bs[data.version] = data;
|
||||
this.badge_count++;
|
||||
|
@ -456,6 +451,7 @@ export default class Room {
|
|||
return this.style.delete('badges');
|
||||
|
||||
const use_media = IS_FIREFOX && this.manager.context.get('chat.badges.media-queries'),
|
||||
can_click = this.manager.context.get('chat.badges.clickable'),
|
||||
out = [],
|
||||
id = this.id;
|
||||
|
||||
|
@ -468,6 +464,7 @@ export default class Room {
|
|||
selector = `[data-room-id="${id}"] .ffz-badge[data-badge="${key}"][data-version="${version}"]`;
|
||||
|
||||
out.push(`${selector} {
|
||||
${can_click && (data.click_action || data.click_url) ? 'cursor:pointer;' : ''}
|
||||
background-color: transparent;
|
||||
filter: none;
|
||||
${WEBKIT}mask-image: none;
|
||||
|
|
119
src/modules/main_menu/components/blocked-type-editor.vue
Normal file
119
src/modules/main_menu/components/blocked-type-editor.vue
Normal file
|
@ -0,0 +1,119 @@
|
|||
<template lang="html">
|
||||
<div class="ffz--term ffz--blocked-type">
|
||||
<div class="tw-align-items-center tw-flex tw-flex-nowrap tw-flex-row tw-full-width">
|
||||
<div class="tw-flex-grow-1 tw-mg-r-05">
|
||||
<h4 v-if="! editing">
|
||||
{{ display.v }}
|
||||
</h4>
|
||||
<select
|
||||
v-if="editing"
|
||||
v-model="edit_data.v"
|
||||
class="tw-block tw-full-width tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-x-1 tw-pd-y-05 tw-mg-y-05"
|
||||
>
|
||||
<option
|
||||
v-for="type in types"
|
||||
:key="type"
|
||||
:value="type"
|
||||
>
|
||||
{{ type }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="adding" class="tw-flex-shrink-0">
|
||||
<button class="tw-button" @click="save">
|
||||
<span class="tw-button__text">
|
||||
{{ t('setting.terms.add-term', 'Add') }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div v-else-if="deleting" class="tw-flex-shrink-0">
|
||||
<button class="tw-button tw-button--text tw-tooltip-wrapper" @click="$emit('remove', term)">
|
||||
<span class="tw-button__text ffz-i-trash" />
|
||||
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
|
||||
{{ t('setting.delete', 'Delete') }}
|
||||
</div>
|
||||
</button>
|
||||
<button class="tw-button tw-button--text tw-tooltip-wrapper" @click="deleting = false">
|
||||
<span class="tw-button__text ffz-i-cancel" />
|
||||
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
|
||||
{{ t('setting.cancel', 'Cancel') }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="tw-flex-shrink-0">
|
||||
<button class="tw-button tw-button--text tw-tooltip-wrapper" @click="deleting = true">
|
||||
<span class="tw-button__text ffz-i-trash" />
|
||||
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
|
||||
{{ t('setting.delete', 'Delete') }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {deep_copy} from 'utilities/object';
|
||||
|
||||
let id = 0;
|
||||
|
||||
export default {
|
||||
props: {
|
||||
types: Array,
|
||||
term: Object,
|
||||
colored: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
removable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
adding: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
if ( this.adding )
|
||||
return {
|
||||
editor_id: id++,
|
||||
deleting: false,
|
||||
editing: true,
|
||||
edit_data: deep_copy(this.term)
|
||||
};
|
||||
|
||||
return {
|
||||
editor_id: id++,
|
||||
deleting: false,
|
||||
editing: false,
|
||||
edit_data: null
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
display() {
|
||||
return this.editing ? this.edit_data : this.term;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
cancel() {
|
||||
if ( this.adding )
|
||||
this.edit_data = deep_copy(this.term);
|
||||
else {
|
||||
this.editing = false;
|
||||
this.edit_data = null
|
||||
}
|
||||
},
|
||||
|
||||
save() {
|
||||
this.$emit('save', this.edit_data);
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
105
src/modules/main_menu/components/blocked-types.vue
Normal file
105
src/modules/main_menu/components/blocked-types.vue
Normal file
|
@ -0,0 +1,105 @@
|
|||
<template lang="html">
|
||||
<section class="ffz--widget ffz--blocked-types">
|
||||
<blocked-type-editor
|
||||
:term="default_type"
|
||||
:types="data"
|
||||
:adding="true"
|
||||
@save="new_term"
|
||||
/>
|
||||
<div v-if="! val.length || val.length === 1 && hasInheritance" class="tw-mg-t-05 tw-c-text-alt-2 tw-font-size-4 tw-align-center tw-c-text-alt-2 tw-pd-05">
|
||||
{{ t('setting.terms.no-terms', 'no terms are defined in this profile') }}
|
||||
</div>
|
||||
<ul v-else class="ffz--term-list tw-mg-t-05">
|
||||
<blocked-type-editor
|
||||
v-for="term in terms"
|
||||
:key="term.id"
|
||||
:term="term.v"
|
||||
:types="data"
|
||||
@remove="remove(term)"
|
||||
@save="save(term, $event)"
|
||||
/>
|
||||
</ul>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import SettingMixin from '../setting-mixin';
|
||||
import {deep_copy} from 'utilities/object';
|
||||
|
||||
let last_id = 0;
|
||||
|
||||
export default {
|
||||
mixins: [SettingMixin],
|
||||
props: ['item', 'context'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
default_type: {
|
||||
v: 'Hosted'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
hasInheritance() {
|
||||
for(const val of this.val)
|
||||
if ( val.t === 'inherit' )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
terms() {
|
||||
const out = [];
|
||||
|
||||
if ( Array.isArray(this.val) )
|
||||
for(const term of this.val)
|
||||
if ( term && term.t !== 'inherit' )
|
||||
out.push(term);
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
val() {
|
||||
if ( ! this.has_value )
|
||||
return [];
|
||||
|
||||
return this.value.map(x => {
|
||||
x.id = x.id || `${Date.now()}-${Math.random()}-${last_id++}`;
|
||||
return x;
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
new_term(term) {
|
||||
if ( ! term.v )
|
||||
return;
|
||||
|
||||
const vals = Array.from(this.val);
|
||||
vals.push({v: term});
|
||||
this.set(deep_copy(vals));
|
||||
},
|
||||
|
||||
remove(val) {
|
||||
const vals = Array.from(this.val),
|
||||
idx = vals.indexOf(val);
|
||||
|
||||
if ( idx !== -1 ) {
|
||||
vals.splice(idx, 1);
|
||||
if ( vals.length )
|
||||
this.set(deep_copy(vals));
|
||||
else
|
||||
this.clear();
|
||||
}
|
||||
},
|
||||
|
||||
save(val, new_val) {
|
||||
val.v = new_val;
|
||||
this.set(deep_copy(this.val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
|
@ -1,11 +1,11 @@
|
|||
<template lang="html">
|
||||
<div v-if="item.contents" :class="classes">
|
||||
<header v-if="! item.no_header">
|
||||
<header v-if="! item.no_header" class="tw-font-size-5">
|
||||
{{ t(item.i18n_key, item.title) }}
|
||||
</header>
|
||||
<section
|
||||
v-if="item.description"
|
||||
class="tw-pd-b-1"
|
||||
class="tw-pd-b-1 tw-c-text-alt"
|
||||
>
|
||||
<markdown :source="t(item.desc_i18n_key, item.description)" />
|
||||
</section>
|
||||
|
|
|
@ -60,7 +60,9 @@ export const array_merge = {
|
|||
let trailing = [];
|
||||
let had_value = false;
|
||||
|
||||
const profs = [...profiles, DEFAULT];
|
||||
let profs = profiles;
|
||||
if ( definition.inherit_default )
|
||||
profs = [...profiles, DEFAULT];
|
||||
|
||||
for(const profile of profs) {
|
||||
let value;
|
||||
|
|
|
@ -2287,7 +2287,7 @@ export default class EmoteMenu extends Module {
|
|||
|
||||
if ( nodes && nodes.length )
|
||||
for(const node of nodes) {
|
||||
const product = node.product,
|
||||
const product = node && node.product,
|
||||
set_id = product && product.emoteSetID;
|
||||
|
||||
if ( ! set_id )
|
||||
|
|
|
@ -68,6 +68,26 @@ const AUTOMOD_TYPES = make_enum(
|
|||
'MessageModDenied'
|
||||
);
|
||||
|
||||
const UNBLOCKABLE_TYPES = [
|
||||
'Message',
|
||||
'Notice',
|
||||
'Moderation',
|
||||
'ModerationAction',
|
||||
'TargetedModerationAction',
|
||||
'AutoMod',
|
||||
'SubscriberOnlyMode',
|
||||
'FollowerOnlyMode',
|
||||
'SlowMode',
|
||||
'EmoteOnlyMode',
|
||||
'R9KMode',
|
||||
'Connected',
|
||||
'Disconnected',
|
||||
'Reconnect',
|
||||
'RoomMods',
|
||||
'RoomState',
|
||||
'BadgesUpdated'
|
||||
]
|
||||
|
||||
const CHAT_TYPES = make_enum(
|
||||
'Message',
|
||||
'ExtensionMessage',
|
||||
|
@ -250,6 +270,28 @@ export default class ChatHook extends Module {
|
|||
|
||||
// Settings
|
||||
|
||||
this.settings.add('chat.filtering.blocked-types', {
|
||||
default: [],
|
||||
type: 'array_merge',
|
||||
always_inherit: true,
|
||||
process(ctx, val) {
|
||||
const out = new Set;
|
||||
for(const v of val)
|
||||
if ( v?.v || ! UNBLOCKABLE_TYPES.includes(v.v) )
|
||||
out.add(v.v);
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
ui: {
|
||||
path: 'Chat > Filtering >> Blocked Message Types @{"description":"This filter allows you to remove all messages of a certain type from Twitch chat. It can be used to filter system messages, such as Hosts or Raids. Some types, such as moderation actions, cannot be blocked to prevent chat functionality from breaking."}',
|
||||
component: 'blocked-types',
|
||||
data: () => Object
|
||||
.keys(this.chat_types)
|
||||
.filter(key => ! UNBLOCKABLE_TYPES.includes(key) && ! /^\d+$/.test(key))
|
||||
}
|
||||
});
|
||||
|
||||
this.settings.add('chat.replies.style', {
|
||||
default: 1,
|
||||
ui: {
|
||||
|
@ -1113,21 +1155,24 @@ export default class ChatHook extends Module {
|
|||
if ( ! reward )
|
||||
return;
|
||||
|
||||
const msg = {
|
||||
id: data.id,
|
||||
type: this.chat_types.Message,
|
||||
ffz_type: 'points',
|
||||
ffz_reward: reward,
|
||||
messageParts: [],
|
||||
user: {
|
||||
id: data.user.id,
|
||||
login: data.user.login,
|
||||
displayName: data.user.display_name
|
||||
},
|
||||
timestamp: new Date(message.data.timestamp || data.redeemed_at).getTime()
|
||||
};
|
||||
if ( ! this.chat.context.get('chat.filtering.blocked-types').has('ChannelPointsReward') ) {
|
||||
const msg = {
|
||||
id: data.id,
|
||||
type: this.chat_types.Message,
|
||||
ffz_type: 'points',
|
||||
ffz_reward: reward,
|
||||
messageParts: [],
|
||||
user: {
|
||||
id: data.user.id,
|
||||
login: data.user.login,
|
||||
displayName: data.user.display_name
|
||||
},
|
||||
timestamp: new Date(message.data.timestamp || data.redeemed_at).getTime()
|
||||
};
|
||||
|
||||
service.postMessageToCurrentChannel({}, msg);
|
||||
}
|
||||
|
||||
service.postMessageToCurrentChannel({}, msg);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
@ -1328,7 +1373,11 @@ export default class ChatHook extends Module {
|
|||
if ( msg ) {
|
||||
try {
|
||||
const types = t.chat_types || {},
|
||||
mod_types = t.mod_types || {};
|
||||
mod_types = t.mod_types || {},
|
||||
blocked_types = t.chat.context.get('chat.filtering.blocked-types');
|
||||
|
||||
if ( blocked_types.has(types[msg.type]) )
|
||||
return;
|
||||
|
||||
if ( msg.type === types.RewardGift && ! t.chat.context.get('chat.bits.show-rewards') )
|
||||
return;
|
||||
|
@ -1776,7 +1825,7 @@ export default class ChatHook extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
const old_chat = this.onChatMessageEvent;
|
||||
/*const old_chat = this.onChatMessageEvent;
|
||||
this.onChatMessageEvent = function(e) {
|
||||
/*if ( e && e.sentByCurrentUser ) {
|
||||
try {
|
||||
|
@ -1788,7 +1837,7 @@ export default class ChatHook extends Module {
|
|||
} catch(err) {
|
||||
t.log.capture(err, {extra: e});
|
||||
}
|
||||
}*/
|
||||
}* /
|
||||
|
||||
return old_chat.call(i, e);
|
||||
}
|
||||
|
@ -1806,15 +1855,18 @@ export default class ChatHook extends Module {
|
|||
} catch(err) {
|
||||
t.log.capture(err, {extra: e});
|
||||
}
|
||||
}*/
|
||||
}* /
|
||||
|
||||
return old_action.call(i, e);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
const old_sub = this.onSubscriptionEvent;
|
||||
this.onSubscriptionEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('Subscription') )
|
||||
return;
|
||||
|
||||
if ( t.chat.context.get('chat.subs.show') < 3 )
|
||||
return;
|
||||
|
||||
|
@ -1849,6 +1901,9 @@ export default class ChatHook extends Module {
|
|||
const old_resub = this.onResubscriptionEvent;
|
||||
this.onResubscriptionEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('Resubscription') )
|
||||
return;
|
||||
|
||||
if ( t.chat.context.get('chat.subs.show') < 2 && ! e.body )
|
||||
return;
|
||||
|
||||
|
@ -1875,6 +1930,9 @@ export default class ChatHook extends Module {
|
|||
const old_subgift = this.onSubscriptionGiftEvent;
|
||||
this.onSubscriptionGiftEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('SubGift') )
|
||||
return;
|
||||
|
||||
const key = `${e.channel}:${e.user.userID}`,
|
||||
mystery = mysteries[key];
|
||||
|
||||
|
@ -1922,6 +1980,9 @@ export default class ChatHook extends Module {
|
|||
const old_anonsubgift = this.onAnonSubscriptionGiftEvent;
|
||||
this.onAnonSubscriptionGiftEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('AnonSubGift') )
|
||||
return;
|
||||
|
||||
const key = `${e.channel}:ANON`,
|
||||
mystery = mysteries[key];
|
||||
|
||||
|
@ -1970,6 +2031,9 @@ export default class ChatHook extends Module {
|
|||
const old_submystery = this.onSubscriptionMysteryGiftEvent;
|
||||
this.onSubscriptionMysteryGiftEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('SubMysteryGift') )
|
||||
return;
|
||||
|
||||
let mystery = null;
|
||||
if ( e.massGiftCount > t.chat.context.get('chat.subs.merge-gifts') ) {
|
||||
const key = `${e.channel}:${e.user.userID}`;
|
||||
|
@ -2000,6 +2064,9 @@ export default class ChatHook extends Module {
|
|||
const old_anonsubmystery = this.onAnonSubscriptionMysteryGiftEvent;
|
||||
this.onAnonSubscriptionMysteryGiftEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('AnonSubMysteryGift') )
|
||||
return;
|
||||
|
||||
let mystery = null;
|
||||
if ( e.massGiftCount > t.chat.context.get('chat.subs.merge-gifts') ) {
|
||||
const key = `${e.channel}:ANON`;
|
||||
|
@ -2031,6 +2098,9 @@ export default class ChatHook extends Module {
|
|||
const old_ritual = this.onRitualEvent;
|
||||
this.onRitualEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('Ritual') )
|
||||
return;
|
||||
|
||||
const out = i.convertMessage(e);
|
||||
out.ffz_type = 'ritual';
|
||||
out.ritual = e.type;
|
||||
|
@ -2046,6 +2116,9 @@ export default class ChatHook extends Module {
|
|||
const old_points = this.onChannelPointsRewardEvent;
|
||||
this.onChannelPointsRewardEvent = function(e) {
|
||||
try {
|
||||
if ( t.chat.context.get('chat.filtering.blocked-types').has('ChannelPointsReward') )
|
||||
return;
|
||||
|
||||
const reward = e.rewardID && get(e.rewardID, i.props.rewardMap);
|
||||
if ( reward ) {
|
||||
const out = i.convertMessage(e);
|
||||
|
|
|
@ -209,8 +209,10 @@ export class EventEmitter {
|
|||
try {
|
||||
ret = fn.apply(ctx, args);
|
||||
} catch(err) {
|
||||
if ( this.log )
|
||||
if ( this.log ) {
|
||||
this.log.capture(err, {tags: {event}, extra:{args}});
|
||||
this.log.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ret === Detach )
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue