mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-04 11:44:00 +00:00
4.36.0
* Added: Setting to hide specific chat token types from rendering in chat, in case you for some reason don't want to see cheers / emotes / whatever. * Added: Support for the Artist, No Audio, and No Video badges in different badge styles. * API Added: The `site.player` module now exports CSS rules for the player control containers, so that FS Chat (and maybe other add-ons) won't need updates in the future if the CSS rule changes slightly.
This commit is contained in:
parent
168db52e2b
commit
dd248838ad
9 changed files with 125 additions and 13 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.35.2",
|
"version": "4.36.0",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|
|
@ -44,7 +44,10 @@ const CSS_BADGES = {
|
||||||
turbo: { 1: { color: '#59399A' } },
|
turbo: { 1: { color: '#59399A' } },
|
||||||
premium: { 1: { color: '#00A0D6' } },
|
premium: { 1: { color: '#00A0D6' } },
|
||||||
'anonymous-cheerer': { 1: { color: '#4B367C' } },
|
'anonymous-cheerer': { 1: { color: '#4B367C' } },
|
||||||
'clip-champ': { 1: { color: '#9146FF' } }
|
'clip-champ': { 1: { color: '#9146FF' } },
|
||||||
|
'artist-badge': { 1: { color: '#1e69ff' } },
|
||||||
|
'no_audio': { 1: { color: '#323239' } },
|
||||||
|
'no_video': { 1: { color: '#323239' } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,10 @@ function sortPriorityColorTerms(list) {
|
||||||
|
|
||||||
const TERM_FLAGS = ['g', 'gi'];
|
const TERM_FLAGS = ['g', 'gi'];
|
||||||
|
|
||||||
|
const UNBLOCKABLE_TOKENS = [
|
||||||
|
'filter_test'
|
||||||
|
];
|
||||||
|
|
||||||
function formatTerms(data) {
|
function formatTerms(data) {
|
||||||
const out = [];
|
const out = [];
|
||||||
|
|
||||||
|
@ -441,6 +445,29 @@ export default class Chat extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settings.add('chat.filtering.hidden-tokens', {
|
||||||
|
default: [],
|
||||||
|
type: 'array_merge',
|
||||||
|
always_inherit: true,
|
||||||
|
process(ctx, val) {
|
||||||
|
const out = new Set;
|
||||||
|
for(const v of val)
|
||||||
|
if ( v?.v || ! UNBLOCKABLE_TOKENS.includes(v.v) )
|
||||||
|
out.add(v.v);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
|
||||||
|
ui: {
|
||||||
|
path: 'Chat > Appearance >> Hidden Token Types @{"description":"This filter allows you to prevent specific content token types from appearing chat messages, such as hiding all cheers or emotes."}',
|
||||||
|
component: 'blocked-types',
|
||||||
|
data: () => Object
|
||||||
|
.keys(this.tokenizers)
|
||||||
|
.filter(key => ! UNBLOCKABLE_TOKENS.includes(key) && this.tokenizers[key]?.render)
|
||||||
|
.sort()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('chat.filtering.highlight-basic-users', {
|
this.settings.add('chat.filtering.highlight-basic-users', {
|
||||||
default: [],
|
default: [],
|
||||||
type: 'array_merge',
|
type: 'array_merge',
|
||||||
|
@ -1978,12 +2005,14 @@ export default class Chat extends Module {
|
||||||
tokenizers = this.tokenizers,
|
tokenizers = this.tokenizers,
|
||||||
l = tokens.length;
|
l = tokens.length;
|
||||||
|
|
||||||
|
const hidden = this.context.get('chat.filtering.hidden-tokens');
|
||||||
|
|
||||||
for(let i=0; i < l; i++) {
|
for(let i=0; i < l; i++) {
|
||||||
const token = tokens[i],
|
const token = tokens[i],
|
||||||
type = token.type,
|
type = token.type,
|
||||||
tk = tokenizers[type];
|
tk = tokenizers[type];
|
||||||
|
|
||||||
if ( token.hidden )
|
if ( token.hidden || hidden.has(type) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
:key="rule.id"
|
:key="rule.id"
|
||||||
:value="rule"
|
:value="rule"
|
||||||
:filters="filters"
|
:filters="filters"
|
||||||
|
:preview="preview"
|
||||||
:context="context"
|
:context="context"
|
||||||
:data-id="rule.id"
|
:data-id="rule.id"
|
||||||
@input="updateRule(rule.id, $event)"
|
@input="updateRule(rule.id, $event)"
|
||||||
|
@ -61,10 +62,15 @@ export default {
|
||||||
value: Array,
|
value: Array,
|
||||||
filters: Object,
|
filters: Object,
|
||||||
maxRules: {
|
maxRules: {
|
||||||
tpye: Number,
|
type: Number,
|
||||||
required: false,
|
required: false,
|
||||||
default: 0
|
default: 0
|
||||||
},
|
},
|
||||||
|
preview: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
context: {
|
context: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: false
|
required: false
|
||||||
|
|
|
@ -10,10 +10,11 @@
|
||||||
:type="type"
|
:type="type"
|
||||||
:filters="filters"
|
:filters="filters"
|
||||||
:context="context"
|
:context="context"
|
||||||
|
:preview="preview"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="isShort"
|
v-if="isShort && preview"
|
||||||
class="tw-mg-l-1 tw-pd-x-1 tw-border-l tw-flex tw-align-items-center ffz--profile__icon tw-relative ffz-il-tooltip__container"
|
class="tw-mg-l-1 tw-pd-x-1 tw-border-l tw-flex tw-align-items-center ffz--profile__icon tw-relative ffz-il-tooltip__container"
|
||||||
>
|
>
|
||||||
<figure :class="[passes ? 'ffz-i-ok' : 'ffz-i-cancel']" />
|
<figure :class="[passes ? 'ffz-i-ok' : 'ffz-i-cancel']" />
|
||||||
|
@ -31,7 +32,7 @@
|
||||||
:class="[isShort ? '' : 'tw-mg-l-1']"
|
:class="[isShort ? '' : 'tw-mg-l-1']"
|
||||||
class="tw-border-l tw-pd-l-1 tw-flex tw-flex-column tw-flex-wrap tw-justify-content-start tw-align-items-start"
|
class="tw-border-l tw-pd-l-1 tw-flex tw-flex-column tw-flex-wrap tw-justify-content-start tw-align-items-start"
|
||||||
>
|
>
|
||||||
<div v-if="! isShort" class="tw-mg-b-1 tw-border-b tw-pd-b-1 tw-full-width tw-flex tw-justify-content-center ffz--profile__icon tw-relative ffz-il-tooltip__container">
|
<div v-if="! isShort && preview" class="tw-mg-b-1 tw-border-b tw-pd-b-1 tw-full-width tw-flex tw-justify-content-center ffz--profile__icon tw-relative ffz-il-tooltip__container">
|
||||||
<figure :class="[passes ? 'ffz-i-ok' : 'ffz-i-cancel']" />
|
<figure :class="[passes ? 'ffz-i-ok' : 'ffz-i-cancel']" />
|
||||||
<div class="ffz-il-tooltip ffz-il-tooltip--up ffz-il-tooltip--align-right">
|
<div class="ffz-il-tooltip ffz-il-tooltip--up ffz-il-tooltip--align-right">
|
||||||
<span v-if="passes">
|
<span v-if="passes">
|
||||||
|
@ -80,6 +81,11 @@ export default {
|
||||||
context: {
|
context: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: false
|
required: false
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -93,7 +99,7 @@ export default {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
passes() {
|
passes() {
|
||||||
return this.tester && this.tester(this.context);
|
return this.preview && this.tester && this.tester(this.context);
|
||||||
},
|
},
|
||||||
|
|
||||||
type() {
|
type() {
|
||||||
|
|
|
@ -176,6 +176,7 @@
|
||||||
v-model="rules"
|
v-model="rules"
|
||||||
:filters="filters"
|
:filters="filters"
|
||||||
:context="test_context"
|
:context="test_context"
|
||||||
|
:preview="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
60
src/modules/main_menu/components/setting-filter-editor.vue
Normal file
60
src/modules/main_menu/components/setting-filter-editor.vue
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<template lang="html">
|
||||||
|
<div class="ffz--widget ffz--filter-editor tw-border-t tw-pd-y-1">
|
||||||
|
<div
|
||||||
|
v-if="source && source !== profile"
|
||||||
|
class="tw-c-background-accent tw-c-text-overlay tw-pd-1 tw-mg-b-1"
|
||||||
|
>
|
||||||
|
<span class="ffz-i-info" />
|
||||||
|
{{ t('setting.warn-inheritence', 'These values are being overridden by another profile and may not take effect.') }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<filter-editor
|
||||||
|
:value="rules"
|
||||||
|
:filters="filters"
|
||||||
|
:context="test_context"
|
||||||
|
:preview="preview"
|
||||||
|
@input="onInput"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import {deep_copy} from 'utilities/object';
|
||||||
|
|
||||||
|
import SettingMixin from '../setting-mixin';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [SettingMixin],
|
||||||
|
props: ['item', 'context'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
filters: this.item.data(),
|
||||||
|
test_context: this.item.test_context ? this.item.test_context() : {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
preview() {
|
||||||
|
return this.item.preview || false
|
||||||
|
},
|
||||||
|
|
||||||
|
rules() {
|
||||||
|
if ( ! Array.isArray(this.value) || this.value.length <= 0 )
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return this.value.filter(x => x.v).map(x => x.v);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onInput(data) {
|
||||||
|
const val = deep_copy(data);
|
||||||
|
this.set(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -13,6 +13,9 @@ import { getFontsList, useFont } from 'utilities/fonts';
|
||||||
|
|
||||||
const STYLE_VALIDATOR = createElement('span');
|
const STYLE_VALIDATOR = createElement('span');
|
||||||
|
|
||||||
|
const LEFT_CONTROLS = '.video-player__default-player .player-controls__left-control-group';
|
||||||
|
const RIGHT_CONTROLS = '.video-player__default-player .player-controls__right-control-group';
|
||||||
|
|
||||||
const HAS_COMPRESSOR = window.AudioContext && window.DynamicsCompressorNode != null,
|
const HAS_COMPRESSOR = window.AudioContext && window.DynamicsCompressorNode != null,
|
||||||
HAS_GAIN = HAS_COMPRESSOR && window.GainNode != null;
|
HAS_GAIN = HAS_COMPRESSOR && window.GainNode != null;
|
||||||
|
|
||||||
|
@ -75,6 +78,9 @@ export default class PlayerBase extends Module {
|
||||||
|
|
||||||
this.onShortcut = this.onShortcut.bind(this);
|
this.onShortcut = this.onShortcut.bind(this);
|
||||||
|
|
||||||
|
this.LEFT_CONTROLS = LEFT_CONTROLS;
|
||||||
|
this.RIGHT_CONTROLS = RIGHT_CONTROLS;
|
||||||
|
|
||||||
this.registerSettings();
|
this.registerSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1171,7 +1177,7 @@ export default class PlayerBase extends Module {
|
||||||
addGainSlider(inst, visible_only, tries = 0) {
|
addGainSlider(inst, visible_only, tries = 0) {
|
||||||
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
||||||
video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video || inst.props.mediaPlayerInstance?.core?.mediaSinkManager?.video,
|
video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video || inst.props.mediaPlayerInstance?.core?.mediaSinkManager?.video,
|
||||||
container = outer && outer.querySelector('.video-player__default-player .player-controls__left-control-group');
|
container = outer && outer.querySelector(LEFT_CONTROLS);
|
||||||
let gain = video != null && video._ffz_compressed && video._ffz_gain;
|
let gain = video != null && video._ffz_compressed && video._ffz_gain;
|
||||||
|
|
||||||
if ( this.areControlsDisabled(inst) )
|
if ( this.areControlsDisabled(inst) )
|
||||||
|
@ -1302,7 +1308,7 @@ export default class PlayerBase extends Module {
|
||||||
addCompressorButton(inst, visible_only, tries = 0) {
|
addCompressorButton(inst, visible_only, tries = 0) {
|
||||||
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
||||||
video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video || inst.props.mediaPlayerInstance?.core?.mediaSinkManager?.video,
|
video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video || inst.props.mediaPlayerInstance?.core?.mediaSinkManager?.video,
|
||||||
container = outer && outer.querySelector('.video-player__default-player .player-controls__left-control-group'),
|
container = outer && outer.querySelector(LEFT_CONTROLS),
|
||||||
has_comp = HAS_COMPRESSOR && video != null && this.settings.get('player.compressor.enable');
|
has_comp = HAS_COMPRESSOR && video != null && this.settings.get('player.compressor.enable');
|
||||||
|
|
||||||
if ( ! container ) {
|
if ( ! container ) {
|
||||||
|
@ -1730,7 +1736,7 @@ export default class PlayerBase extends Module {
|
||||||
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
||||||
video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video || inst.props.mediaPlayerInstance?.core?.mediaSinkManager?.video,
|
video = inst.props.mediaPlayerInstance?.mediaSinkManager?.video || inst.props.mediaPlayerInstance?.core?.mediaSinkManager?.video,
|
||||||
is_fs = video && document.fullscreenElement && document.fullscreenElement.contains(video),
|
is_fs = video && document.fullscreenElement && document.fullscreenElement.contains(video),
|
||||||
container = outer && outer.querySelector('.video-player__default-player .player-controls__right-control-group'),
|
container = outer && outer.querySelector(RIGHT_CONTROLS),
|
||||||
has_pip = document.pictureInPictureEnabled && this.settings.get('player.button.pip');
|
has_pip = document.pictureInPictureEnabled && this.settings.get('player.button.pip');
|
||||||
|
|
||||||
if ( ! container ) {
|
if ( ! container ) {
|
||||||
|
@ -1833,7 +1839,7 @@ export default class PlayerBase extends Module {
|
||||||
|
|
||||||
addResetButton(inst, tries = 0) {
|
addResetButton(inst, tries = 0) {
|
||||||
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
||||||
container = outer && outer.querySelector('.video-player__default-player .player-controls__right-control-group'),
|
container = outer && outer.querySelector(RIGHT_CONTROLS),
|
||||||
has_reset = this.settings.get('player.button.reset');
|
has_reset = this.settings.get('player.button.reset');
|
||||||
|
|
||||||
if ( ! container ) {
|
if ( ! container ) {
|
||||||
|
@ -2055,7 +2061,7 @@ export default class PlayerBase extends Module {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
const outer = inst.props.containerRef || this.fine.getChildNode(inst),
|
||||||
container = outer && outer.querySelector('.video-player__default-player .player-controls__right-control-group');
|
container = outer && outer.querySelector(RIGHT_CONTROLS);
|
||||||
|
|
||||||
if ( ! container )
|
if ( ! container )
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -45,7 +45,8 @@ export const RERENDER_SETTINGS = [
|
||||||
'chat.filtering.display-deleted',
|
'chat.filtering.display-deleted',
|
||||||
'chat.filtering.display-mod-action',
|
'chat.filtering.display-mod-action',
|
||||||
'chat.replies.style',
|
'chat.replies.style',
|
||||||
'chat.bits.cheer-notice'
|
'chat.bits.cheer-notice',
|
||||||
|
'chat.filtering.hidden-tokens'
|
||||||
];
|
];
|
||||||
|
|
||||||
export const UPDATE_BADGE_SETTINGS = [
|
export const UPDATE_BADGE_SETTINGS = [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue