1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00
* Added: Option to prevent Pinned Messages from being displayed. Closes #1470
* Removed: Setting to allow the Golden Kappa Train to appear. This wasn't working correctly, so nothing of value has been lost.
* Fixed: Blocking chat users by username worked inconsistently.
* Fixed: Hiding channels in the directory by title worked inconsistently. Closes #1473
* API Changed: The `chat:get-tab-commands` event now has a `channel` object with the ID and login of the current channel, as well as a reference to the relevant input component.
* API Added: The `chat` module now has `addTabCommandPrefix(prefix: string | string[])` and `removeTabCommandPrefix(prefix: string | string[])` methods. By default, tab-completion for chat commands only triggers with the `/` and `!` prefix for performance reasons. This can be used to add additional prefix characters.
This commit is contained in:
SirStendec 2024-03-19 16:36:44 -04:00
parent 8807e09ea3
commit 10d35468a9
6 changed files with 104 additions and 33 deletions

View file

@ -1,7 +1,7 @@
{
"name": "frankerfacez",
"author": "Dan Salvato LLC",
"version": "4.69.0",
"version": "4.70.0",
"description": "FrankerFaceZ is a Twitch enhancement suite.",
"private": true,
"license": "Apache-2.0",

View file

@ -11,7 +11,7 @@ import Module, { buildAddonProxy } from 'utilities/module';
import {Color} from 'utilities/color';
import {createElement, ManagedStyle} from 'utilities/dom';
import {getFontsList} from 'utilities/fonts';
import {timeout, has, addWordSeparators, glob_to_regex, escape_regex, split_chars, makeAddonIdChecker, deep_copy} from 'utilities/object';
import {timeout, has, addWordSeparators, glob_to_regex, escape_regex, split_chars, makeAddonIdChecker, deep_copy, SourcedSet} from 'utilities/object';
import Badges from './badges';
import Emotes from './emotes';
@ -93,6 +93,9 @@ export default class Chat extends Module {
this.context = this.settings.context({});
this.CommandPrefixes = new SourcedSet(true);
this.CommandPrefixes.set('ffz', ['/', '!']);
this.rooms = {};
this.users = {};
@ -614,7 +617,7 @@ export default class Chat extends Module {
if ( ! data.length )
return null;
return new RegExp(`^(?:${data.join('|')})$`, 'gi');
return new RegExp(`^(?:${data.join('|')})$`, 'i');
});
}
});
@ -1414,6 +1417,24 @@ export default class Chat extends Module {
);
}
overrides.addTabCommandPrefix = (prefix, provider = null) => {
if ( provider == null )
provider = addon_id;
if ( is_dev && provider !== addon_id )
module.log.warn('[DEV-CHECK] Used addTabCommandPrefix with incorrect provider.');
return this.addTabCommandPrefix(prefix, provider);
}
overrides.removeTabCommandPrefix = (prefix, provider = null) => {
if ( provider == null )
provider = addon_id;
if ( is_dev && provider !== addon_id )
module.log.warn('[DEV-CHECK] Used removeTabCommandPrefix with incorrect provider.');
return this.removeTabCommandPrefix(prefix, provider);
}
overrides.addTokenizer = tokenizer => {
if ( tokenizer )
tokenizer.__source = addon_id;
@ -1580,6 +1601,8 @@ export default class Chat extends Module {
}
}
this.CommandPrefixes.delete(addon_id);
for(const item of this.iterateAllRoomsAndUsers())
removed += item._unloadAddon(addon_id) ?? 0;
@ -2305,6 +2328,26 @@ export default class Chat extends Module {
return Object.values(this._hl_reasons);
}
addTabCommandPrefix(prefix, source = 'ffz') {
if ( ! Array.isArray(prefix) )
prefix = [prefix];
for(const item of prefix) {
if ( typeof item !== 'string' || item.length !== 1 )
throw new Error('Invalid command prefix. Must be string of length 1.');
this.CommandPrefixes.push(source, item);
}
}
removeTabCommandPrefix(prefix, source = 'ffz') {
if ( ! Array.isArray(prefix) )
prefix = [prefix];
for(const item of prefix)
this.CommandPrefixes.remove(source, item);
}
addTokenizer(tokenizer) {
const type = tokenizer.type;
if ( has(this.tokenizers, type) ) {

View file

@ -461,7 +461,7 @@ export default class ChatHook extends Module {
}
});
this.settings.add('chat.banners.kappa-train', {
/*this.settings.add('chat.banners.kappa-train', {
default: false,
ui: {
path: 'Chat > Appearance >> Community',
@ -469,6 +469,15 @@ export default class ChatHook extends Module {
description: '**Note**: This setting is currently theoretical and may not work, or may cause non-Kappa hype trains to appear. Due to the infrequent nature of hype trains, and especially the golden kappa hype train, it is very hard to test.',
component: 'setting-check-box'
}
});*/
this.settings.add('chat.banners.pinned-message', {
default: true,
ui: {
path: 'Chat > Appearance >> Community',
title: 'Allow Pinned Messages to be displayed in chat.',
component: 'setting-check-box'
}
});
this.settings.add('chat.banners.drops', {
@ -1042,6 +1051,7 @@ export default class ChatHook extends Module {
this.chat.context.on('changed:chat.banners.polls', this.cleanHighlights, this);
this.chat.context.on('changed:chat.banners.prediction', this.cleanHighlights, this);
this.chat.context.on('changed:chat.banners.drops', this.cleanHighlights, this);
this.chat.context.on('changed:chat.banners.pinned-message', this.cleanHighlights, this);
this.chat.context.on('changed:chat.disable-handling', this.updateDisableHandling, this);
@ -1722,6 +1732,7 @@ export default class ChatHook extends Module {
'hype_train': this.chat.context.get('chat.banners.hype-train'),
'prediction': this.chat.context.get('chat.banners.prediction'),
'poll': this.chat.context.get('chat.banners.polls'),
'pinned_chat': this.chat.context.get('chat.banners.pinned-message'),
'mw-drop-available': this.chat.context.get('chat.banners.drops')
};
@ -1736,8 +1747,8 @@ export default class ChatHook extends Module {
const type = entry.event.type;
if ( type && has(types, type) && ! types[type] ) {
// Attempt to allow Golden Kappa hype trains?
if ( type === 'hype_train' && entry.event.typeDetails === '0' && this.chat.context.get('chat.banners.kappa-train') )
continue;
//if ( type === 'hype_train' && entry.event.typeDetails === '0' && this.chat.context.get('chat.banners.kappa-train') )
// continue;
this.log.info('Removing community highlight: ', type, '#', entry.id);
this.community_dispatch({

View file

@ -7,15 +7,11 @@
import Module from 'utilities/module';
import { findReactFragment } from 'utilities/dom';
import { getTwitchEmoteSrcSet } from 'utilities/object';
import { SourcedSet, getTwitchEmoteSrcSet } from 'utilities/object';
import { TWITCH_POINTS_SETS, TWITCH_GLOBAL_SETS, TWITCH_PRIME_SETS, KNOWN_CODES, REPLACEMENTS, REPLACEMENT_BASE, KEYS } from 'utilities/constants';
import Twilight from 'site';
const COMMAND_KEYS = [
'!',
'/'
];
// Prefer using these statically-allocated collators to String.localeCompare
const locale = Intl.Collator();
@ -75,7 +71,6 @@ export default class Input extends Module {
this.inject('site.fine');
this.inject('site');
// Settings
this.settings.add('chat.hype.display-input', {
@ -783,7 +778,7 @@ export default class Input extends Module {
inst.getMatches = function(input, unknown, index) {
try {
return index === 0 && COMMAND_KEYS.includes(input[0])
return index === 0 && t.chat.CommandPrefixes.includes(input[0])
? inst.getCommands(input) : null;
} catch(err) {
@ -797,11 +792,22 @@ export default class Input extends Module {
isEditor: inst.props.isCurrentUserEditor
});
// Get the parent-input so we can do stuff.
const parent = t.fine.searchParent(inst,
n => n?.props?.channelID && n?.props?.setTray, 50);
const event = t.makeEvent({
input,
permissionLevel: inst.props.permissionLevel,
isEditor: inst.props.isCurrentUserEditor,
commands
commands,
// Extra details, if we managed to find our parent.
__input: parent,
channel: parent ? {
id: parent.props.channelID,
login: parent.props.channelLogin
} : null
});
t.emit('chat:get-tab-commands', event);

View file

@ -616,17 +616,17 @@ export default class Directory extends Module {
// Are we getting a clip, a video, or a stream?
if ( props.slug ) {
// Clip
console.log('need flags for clip', props.slug);
//console.log('need flags for clip', props.slug);
el._ffz_flags = [];
} else if ( props.vodID ) {
// Video
console.log('need flags for vod', props.vodID);
//console.log('need flags for vod', props.vodID);
el._ffz_flags = [];
} else {
// Stream?
console.log('need flags for stream', props.channelLogin);
//console.log('need flags for stream', props.channelLogin);
this.twitch_data.getStreamFlags(null, props.channelLogin).then(data => {
el._ffz_flags = data ?? [];
this.updateCard(el);
@ -670,11 +670,15 @@ export default class Directory extends Module {
}
if ( ! should_blur ) {
const regexes = this.settings.get('__filter:directory.blur-titles');
if ( regexes &&
(( regexes[0] && regexes[0].test(props.title) ) ||
( regexes[1] && regexes[1].test(props.title) ))
)
should_blur = true;
if ( regexes ) {
if ( regexes[0] )
regexes[0].lastIndex = -1;
if ( regexes[1] )
regexes[1].lastIndex = -1;
if (( regexes[0] && regexes[0].test(props.title) ) || ( regexes[1] && regexes[1].test(props.title) ))
should_blur = true;
}
}
el.classList.toggle('ffz-hide-thumbnail', should_blur);
@ -700,11 +704,15 @@ export default class Directory extends Module {
if ( ! should_hide ) {
const regexes = this.settings.get('__filter:directory.block-titles');
if ( regexes &&
(( regexes[0] && regexes[0].test(props.title) ) ||
( regexes[1] && regexes[1].test(props.title) ))
)
should_hide = true;
if ( regexes ) {
if ( regexes[0] )
regexes[0].lastIndex = -1;
if ( regexes[1] )
regexes[1].lastIndex = -1;
if (( regexes[0] && regexes[0].test(props.title) ) || ( regexes[1] && regexes[1].test(props.title) ))
should_hide = true;
}
}
}

View file

@ -385,11 +385,14 @@ export default class Layout extends Module {
else {
const regexes = this.settings.get('__filter:directory.block-titles');
const title = stream?.broadcaster?.broadcastSettings?.title;
if ( regexes && title &&
(( regexes[0] && regexes[0].test(title) ) ||
( regexes[1] && regexes[1].test(title) ))
)
should_hide = true;
if ( regexes && title ) {
if ( regexes[0] )
regexes[0].lastIndex = -1;
if ( regexes[1] )
regexes[1].lastIndex = -1;
if ( (regexes[0] && regexes[0].test(title)) || (regexes[1] && regexes[1].test(title)) )
should_hide = true;
}
}
card.classList.toggle('ffz--side-nav-card-rerun', rerun);
@ -421,4 +424,4 @@ export default class Layout extends Module {
updatePortraitMode() {
}
}
}