mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-07 06:40:54 +00:00
4.69.0
* API Added: When adding a command to tab-completion with the `chat:get-tab-commands` event, you can now specify a `prefix` for your command. Valid options: `!` and `/`. Defaults to `/` if not specified. * API Added: New `chat:update-line` event. Signature: `(messageId: string, clearTokens: boolean = true, clearBadges?: boolean)`. To re-render a chatline without re-tokenizing it, pass `false` as the second argument. * API Changed: Whisper / video chat messages now have their message IDs correctly added to their standardized message objects.
This commit is contained in:
parent
3aeb70f0fb
commit
8807e09ea3
6 changed files with 133 additions and 5 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.68.2",
|
"version": "4.69.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",
|
||||||
|
|
|
@ -1895,6 +1895,7 @@ export default class Chat extends Module {
|
||||||
offset = is_action ? 4 : 0,
|
offset = is_action ? 4 : 0,
|
||||||
|
|
||||||
out = msg._ffz_message = {
|
out = msg._ffz_message = {
|
||||||
|
id: msg.id,
|
||||||
user: {...msg.from}, // Apollo seals this~
|
user: {...msg.from}, // Apollo seals this~
|
||||||
message: msg.content.slice(offset),
|
message: msg.content.slice(offset),
|
||||||
is_action,
|
is_action,
|
||||||
|
|
|
@ -38,6 +38,7 @@ export default class Line extends Module {
|
||||||
onEnable() {
|
onEnable() {
|
||||||
this.on('chat.overrides:changed', id => this.updateLinesByUser(id, null, false, false), this);
|
this.on('chat.overrides:changed', id => this.updateLinesByUser(id, null, false, false), this);
|
||||||
this.on('chat:update-lines-by-user', this.updateLinesByUser, this);
|
this.on('chat:update-lines-by-user', this.updateLinesByUser, this);
|
||||||
|
this.on('chat:update-line', this.updateLineById, this);
|
||||||
this.on('chat:update-lines', this.updateLines, this);
|
this.on('chat:update-lines', this.updateLines, this);
|
||||||
this.on('chat:rerender-lines', this.rerenderLines, this);
|
this.on('chat:rerender-lines', this.rerenderLines, this);
|
||||||
this.on('chat:update-line-tokens', this.updateLineTokens, this);
|
this.on('chat:update-line-tokens', this.updateLineTokens, this);
|
||||||
|
@ -174,6 +175,21 @@ export default class Line extends Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateLineById(id, clear_tokens = true, clear_badges = null) {
|
||||||
|
if ( clear_badges == null )
|
||||||
|
clear_badges = clear_tokens;
|
||||||
|
|
||||||
|
for(const inst of this.ChatLine.instances) {
|
||||||
|
const msg = inst.props.node;
|
||||||
|
if ( msg?.id === id ) {
|
||||||
|
if ( clear_tokens || clear_badges )
|
||||||
|
this.messages.delete(msg);
|
||||||
|
|
||||||
|
inst.forceUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
maybeUpdateLines() {
|
maybeUpdateLines() {
|
||||||
if ( this.chat.context.get('chat.rich.all-links') )
|
if ( this.chat.context.get('chat.rich.all-links') )
|
||||||
|
|
|
@ -12,6 +12,11 @@ import { TWITCH_POINTS_SETS, TWITCH_GLOBAL_SETS, TWITCH_PRIME_SETS, KNOWN_CODES,
|
||||||
|
|
||||||
import Twilight from 'site';
|
import Twilight from 'site';
|
||||||
|
|
||||||
|
const COMMAND_KEYS = [
|
||||||
|
'!',
|
||||||
|
'/'
|
||||||
|
];
|
||||||
|
|
||||||
// Prefer using these statically-allocated collators to String.localeCompare
|
// Prefer using these statically-allocated collators to String.localeCompare
|
||||||
const locale = Intl.Collator();
|
const locale = Intl.Collator();
|
||||||
const localeCaseInsensitive = Intl.Collator(undefined, {sensitivity: 'accent'});
|
const localeCaseInsensitive = Intl.Collator(undefined, {sensitivity: 'accent'});
|
||||||
|
@ -771,9 +776,22 @@ export default class Input extends Module {
|
||||||
|
|
||||||
inst._ffz_override = true;
|
inst._ffz_override = true;
|
||||||
inst.oldCommands = inst.getCommands;
|
inst.oldCommands = inst.getCommands;
|
||||||
|
inst.oldMatches = inst.getMatches;
|
||||||
|
inst.oldReplacement = inst.determineReplacement;
|
||||||
|
|
||||||
const t = this;
|
const t = this;
|
||||||
|
|
||||||
|
inst.getMatches = function(input, unknown, index) {
|
||||||
|
try {
|
||||||
|
return index === 0 && COMMAND_KEYS.includes(input[0])
|
||||||
|
? inst.getCommands(input) : null;
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
t.log.error('Error getting matches from command handler.', err);
|
||||||
|
return inst.oldCommands(input, unknown, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inst.getCommands = function(input) { try {
|
inst.getCommands = function(input) { try {
|
||||||
const commands = inst.props.getCommands(inst.props.permissionLevel, {
|
const commands = inst.props.getCommands(inst.props.permissionLevel, {
|
||||||
isEditor: inst.props.isCurrentUserEditor
|
isEditor: inst.props.isCurrentUserEditor
|
||||||
|
@ -792,9 +810,13 @@ export default class Input extends Module {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Trim off the starting /
|
// Trim off the starting /
|
||||||
const i = input.slice(1);
|
const prefix = input[0],
|
||||||
|
i = input.slice(1);
|
||||||
|
|
||||||
|
const sorted = commands
|
||||||
|
.filter(cmd => prefix === (cmd.prefix ?? '/') && inst.doesCommandMatchTerm(cmd, i))
|
||||||
|
.sort(inst.sortCommands);
|
||||||
|
|
||||||
const sorted = commands.filter(cmd => inst.doesCommandMatchTerm(cmd, i)).sort(inst.sortCommands);
|
|
||||||
const out = [];
|
const out = [];
|
||||||
for(const cmd of sorted) {
|
for(const cmd of sorted) {
|
||||||
const arg = cmd.commandArgs?.[0];
|
const arg = cmd.commandArgs?.[0];
|
||||||
|
@ -813,12 +835,44 @@ export default class Input extends Module {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we're working with a non-/ prefix, and have no items,
|
||||||
|
// return null so we don't display ANY UI.
|
||||||
|
if ( prefix !== '/' && ! out.length )
|
||||||
|
return null;
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
return inst.oldCommands(input);
|
return inst.oldCommands(input);
|
||||||
}}
|
} }
|
||||||
|
|
||||||
|
inst.determineReplacement = function(cmd) {
|
||||||
|
const out = inst.oldReplacement(cmd);
|
||||||
|
if ( (cmd.prefix ?? '/') !== '/' && out.startsWith('/') )
|
||||||
|
return cmd.prefix + out.slice(1);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const React = this.site.getReact(),
|
||||||
|
createElement = React?.createElement;
|
||||||
|
|
||||||
|
if ( createElement )
|
||||||
|
inst.renderCommandSuggestion = function(cmd, input) {
|
||||||
|
const args = Array.isArray(cmd?.commandArgs)
|
||||||
|
? cmd.commandArgs.map(arg => (<div class={`tw-mg-r-05${arg.isRequired ? '' : ' tw-c-text-alt'}`}>[{arg.name}]</div>))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return (<div class="tw-pd-05">
|
||||||
|
<div class="tw-flex">
|
||||||
|
<div class="tw-mg-r-05">
|
||||||
|
<span>{ cmd.prefix ?? '/' }</span>
|
||||||
|
<span class="tw-semibold">{ cmd.name }</span>
|
||||||
|
</div>
|
||||||
|
{args}
|
||||||
|
</div>
|
||||||
|
<p class="tw-c-text-alt-2 tw-font-size-7">{ cmd.description }</p>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -486,6 +486,7 @@ export default class ChatLine extends Module {
|
||||||
async onEnable() {
|
async onEnable() {
|
||||||
this.on('chat.overrides:changed', id => this.updateLinesByUser(id, null, false, false), this);
|
this.on('chat.overrides:changed', id => this.updateLinesByUser(id, null, false, false), this);
|
||||||
this.on('chat:update-lines-by-user', this.updateLinesByUser, this);
|
this.on('chat:update-lines-by-user', this.updateLinesByUser, this);
|
||||||
|
this.on('chat:update-line', this.updateLineById, this);
|
||||||
this.on('chat:update-lines', this.updateLines, this);
|
this.on('chat:update-lines', this.updateLines, this);
|
||||||
this.on('chat:rerender-lines', this.rerenderLines, this);
|
this.on('chat:rerender-lines', this.rerenderLines, this);
|
||||||
this.on('chat:update-line-tokens', this.updateLineTokens, this);
|
this.on('chat:update-line-tokens', this.updateLineTokens, this);
|
||||||
|
@ -1440,6 +1441,39 @@ other {# messages were deleted by a moderator.}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateLineById(id, clear_tokens = true, clear_badges = null) {
|
||||||
|
if ( clear_badges == null )
|
||||||
|
clear_badges = clear_tokens;
|
||||||
|
|
||||||
|
for(const inst of this.ChatLine.instances) {
|
||||||
|
const msg = inst.props.message;
|
||||||
|
if ( msg?.id === id ) {
|
||||||
|
if ( clear_badges )
|
||||||
|
msg.ffz_badges = msg.ffz_badge_cache = null;
|
||||||
|
|
||||||
|
if ( clear_tokens ) {
|
||||||
|
msg.ffz_tokens = null;
|
||||||
|
msg.ffz_reply = null;
|
||||||
|
msg.highlights = msg.mentioned = msg.mention_color = msg.color_priority = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
inst.forceUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const inst of this.WhisperLine.instances) {
|
||||||
|
const msg = inst.props.message?._ffz_message;
|
||||||
|
if ( msg?.id === id ) {
|
||||||
|
// TODO: Better support for clear_tokens and clear_badges
|
||||||
|
if ( clear_badges || clear_tokens )
|
||||||
|
msg._ffz_message = null;
|
||||||
|
|
||||||
|
inst.forceUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateLinesByUser(id, login, clear_tokens = true, clear_badges = true) {
|
updateLinesByUser(id, login, clear_tokens = true, clear_badges = true) {
|
||||||
for(const inst of this.ChatLine.instances) {
|
for(const inst of this.ChatLine.instances) {
|
||||||
|
|
|
@ -99,6 +99,7 @@ export default class VideoChatHook extends Module {
|
||||||
this.chat.context.on('changed:chat.video-chat.timestamps', this.rerenderLines, this);
|
this.chat.context.on('changed:chat.video-chat.timestamps', this.rerenderLines, this);
|
||||||
this.on('chat.overrides:changed', id => this.updateLinesByUser(id, null, false, false), this);
|
this.on('chat.overrides:changed', id => this.updateLinesByUser(id, null, false, false), this);
|
||||||
this.on('chat:update-lines-by-user', this.updateLinesByUser, this);
|
this.on('chat:update-lines-by-user', this.updateLinesByUser, this);
|
||||||
|
this.on('chat:update-line', this.updateLineById, this);
|
||||||
this.on('chat:update-lines', this.updateLines, this);
|
this.on('chat:update-lines', this.updateLines, this);
|
||||||
this.on('chat:rerender-lines', this.rerenderLines, this);
|
this.on('chat:rerender-lines', this.rerenderLines, this);
|
||||||
this.on('chat:update-line-tokens', this.updateLineTokens, this);
|
this.on('chat:update-line-tokens', this.updateLineTokens, this);
|
||||||
|
@ -488,6 +489,27 @@ export default class VideoChatHook extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateLineById(id, clear_tokens = true, clear_badges = null) {
|
||||||
|
if ( clear_badges == null )
|
||||||
|
clear_badges = clear_tokens;
|
||||||
|
|
||||||
|
for(const inst of this.VideoChatLine.instances) {
|
||||||
|
const context = inst.props.messageContext;
|
||||||
|
if ( ! context.comment )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ( context.comment?.id === id ) {
|
||||||
|
// TODO: Better support for clear_tokens and clear_badges
|
||||||
|
if ( clear_tokens || clear_badges )
|
||||||
|
context.comment._ffz_message = null;
|
||||||
|
|
||||||
|
inst.forceUpdate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
checkEffects() {
|
checkEffects() {
|
||||||
for(const inst of this.VideoChatLine.instances) {
|
for(const inst of this.VideoChatLine.instances) {
|
||||||
const context = inst.props.messageContext,
|
const context = inst.props.messageContext,
|
||||||
|
@ -516,6 +538,7 @@ export default class VideoChatHook extends Module {
|
||||||
msg_id = params && params['msg-id'];
|
msg_id = params && params['msg-id'];
|
||||||
|
|
||||||
const out = comment._ffz_message = {
|
const out = comment._ffz_message = {
|
||||||
|
id: comment.id,
|
||||||
user: {
|
user: {
|
||||||
color: comment.message.userColor,
|
color: comment.message.userColor,
|
||||||
id: author.id,
|
id: author.id,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue