1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-02 16:08:31 +00:00
* Changed: Animated Emotes is now set to Enabled by default, to reflect the vanilla Twitch experience.
* Fixed: Native animated emotes not appearing with animation.
* Fixed: Typo in the tooltip for Playback Statistics metadata.
* Maintenance: Update the `@ffz/icu-msgparser` dependency.
This commit is contained in:
SirStendec 2021-06-17 14:27:04 -04:00
parent 2a57ecb8a7
commit ce38c3c251
10 changed files with 80 additions and 59 deletions

8
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"version": "4.22.9", "version": "4.23.2",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -580,9 +580,9 @@
} }
}, },
"@ffz/icu-msgparser": { "@ffz/icu-msgparser": {
"version": "1.0.2", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@ffz/icu-msgparser/-/icu-msgparser-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@ffz/icu-msgparser/-/icu-msgparser-2.0.0.tgz",
"integrity": "sha512-LTtWOQ4fftxcC7Z86u9LTi1eZ4X07hQH5yvcURlYSpVTaY9dXXE/h5BdtJB0TIk7FkSiAuN/3sRkfHD0u3+S7Q==" "integrity": "sha512-VYohS74qsdjZl9KMMlpHIKVGDVFy6kktz/rtvZgfWyngKiqJalHqfdhnQ9meu1hCFQZnTUNi+PUe5xoVAZgYGg=="
}, },
"@npmcli/move-file": { "@npmcli/move-file": {
"version": "1.0.1", "version": "1.0.1",

View file

@ -1,7 +1,7 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"author": "Dan Salvato LLC", "author": "Dan Salvato LLC",
"version": "4.23.1", "version": "4.23.2",
"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",
@ -67,7 +67,7 @@
"url": "https://github.com/FrankerFaceZ/FrankerFaceZ.git" "url": "https://github.com/FrankerFaceZ/FrankerFaceZ.git"
}, },
"dependencies": { "dependencies": {
"@ffz/icu-msgparser": "^1.0.2", "@ffz/icu-msgparser": "^2.0.0",
"chartjs": "^0.3.24", "chartjs": "^0.3.24",
"chartjs-plugin-waterfall": "^1.0.3", "chartjs-plugin-waterfall": "^1.0.3",
"chartjs-plugin-zoom": "^0.7.7", "chartjs-plugin-zoom": "^0.7.7",

View file

@ -1079,30 +1079,12 @@ export default class Chat extends Module {
}); });
this.settings.add('chat.emotes.animated', { this.settings.add('chat.emotes.animated', {
requires: ['context.bttv.gifs'], default: 1,
default: null,
process(ctx, val) {
if ( val == null ) {
const temp = ctx.get('ffzap.betterttv.gif_emoticons_mode');
if ( temp == null )
val = ctx.get('context.bttv.gifs') ? 1 : 0;
else
val = temp === 2 ? 1 : 0;
}
return val;
},
ui: { ui: {
path: 'Chat > Appearance >> Emotes', path: 'Chat > Appearance >> Emotes',
sort: -50, sort: -50,
title: 'Animated Emotes', title: 'Animated Emotes',
default(ctx) {
const temp = ctx.get('ffzap.betterttv.gif_emoticons_mode');
if ( temp == null )
return ctx.get('context.bttv.gifs') ? 1 : 0;
return temp === 2 ? 1 : 0;
},
getExtraTerms: () => GIF_TERMS, getExtraTerms: () => GIF_TERMS,
description: 'This controls whether or not animated emotes are allowed to play in chat. When this is `Disabled`, emotes will appear as static images. Setting this to `Enable on Hover` may cause performance issues.', description: 'This controls whether or not animated emotes are allowed to play in chat. When this is `Disabled`, emotes will appear as static images. Setting this to `Enable on Hover` may cause performance issues.',

View file

@ -5,9 +5,9 @@
// ============================================================================ // ============================================================================
import {sanitize, createElement} from 'utilities/dom'; import {sanitize, createElement} from 'utilities/dom';
import {has, split_chars} from 'utilities/object'; import {has, getTwitchEmoteURL, split_chars, getTwitchEmoteSrcSet} from 'utilities/object';
import {TWITCH_EMOTE_BASE, EmoteTypes, REPLACEMENT_BASE, REPLACEMENTS} from 'utilities/constants'; import {EmoteTypes, REPLACEMENT_BASE, REPLACEMENTS} from 'utilities/constants';
import {CATEGORIES} from './emoji'; import {CATEGORIES} from './emoji';
@ -1328,7 +1328,7 @@ export const AddonEmotes = {
const set_id = hide_source ? null : await this.emotes.getTwitchEmoteSet(emote_id), const set_id = hide_source ? null : await this.emotes.getTwitchEmoteSet(emote_id),
emote_set = set_id != null && await this.emotes.getTwitchSetChannel(set_id); emote_set = set_id != null && await this.emotes.getTwitchSetChannel(set_id);
preview = `${TWITCH_EMOTE_BASE}${ds.id}/3.0?_=preview`; preview = `${getTwitchEmoteURL(ds.id, 4, true, true)}?_=preview`;
fav_source = 'twitch'; fav_source = 'twitch';
if ( emote_set ) { if ( emote_set ) {
@ -1641,6 +1641,7 @@ export const TwitchEmotes = {
return tokens; return tokens;
const data = msg.ffz_emotes, const data = msg.ffz_emotes,
anim = this.context.get('chat.emotes.animated'),
big = this.context.get('chat.emotes.2x'), big = this.context.get('chat.emotes.2x'),
use_replacements = this.context.get('chat.fix-bad-emotes'), use_replacements = this.context.get('chat.fix-bad-emotes'),
emotes = []; emotes = [];
@ -1713,8 +1714,8 @@ export const TwitchEmotes = {
text: text.slice(idx - t_start, e_start - t_start).join('') text: text.slice(idx - t_start, e_start - t_start).join('')
}); });
let src, srcSet; let src, srcSet, animSrc, animSrcSet;
let src2, srcSet2; let src2, srcSet2, animSrc2, animSrcSet2;
let can_big = true; let can_big = true;
const replacement = REPLACEMENTS[e_id]; const replacement = REPLACEMENTS[e_id];
@ -1724,12 +1725,22 @@ export const TwitchEmotes = {
can_big = false; can_big = false;
} else { } else {
src = `${TWITCH_EMOTE_BASE}${e_id}/1.0`; src = getTwitchEmoteURL(e_id, 1, false);
srcSet = `${TWITCH_EMOTE_BASE}${e_id}/1.0 1x, ${TWITCH_EMOTE_BASE}${e_id}/2.0 2x`; srcSet = getTwitchEmoteSrcSet(e_id, false);
if ( anim > 0 ) {
animSrc = getTwitchEmoteURL(e_id, 1, true);
animSrcSet = getTwitchEmoteSrcSet(e_id, true);
}
if ( big ) { if ( big ) {
src2 = `${TWITCH_EMOTE_BASE}${e_id}/2.0`; src2 = getTwitchEmoteURL(e_id, 2, false);
srcSet2 = `${TWITCH_EMOTE_BASE}${e_id}/2.0 1x, ${TWITCH_EMOTE_BASE}${e_id}/3.0 2x`; srcSet2 = getTwitchEmoteSrcSet(e_id, false, true, true);
if ( anim > 0 ) {
animSrc2 = getTwitchEmoteURL(e_id, 2, true);
animSrcSet2 = getTwitchEmoteSrcSet(e_id, true, true, true);
}
} }
} }
@ -1741,6 +1752,11 @@ export const TwitchEmotes = {
srcSet, srcSet,
src2, src2,
srcSet2, srcSet2,
animSrc,
animSrc2,
animSrcSet,
animSrcSet2,
anim,
big, big,
can_big, can_big,
height: 28, // Not always accurate but close enough. height: 28, // Not always accurate but close enough.

View file

@ -461,7 +461,7 @@ export default class Metadata extends Module {
const stats = data.stats, const stats = data.stats,
video_info = this.i18n.t( video_info = this.i18n.t(
'metadata.player-stats.video-info', 'metadata.player-stats.video-info',
'Video: {videoResolution}p{fps}\nPlayback Rate: {playbackRate,number} Kbps\nDropped Frames:{skippedFrames,number}', 'Video: {videoResolution}p{fps}\nPlayback Rate: {playbackRate, number} Kbps\nDropped Frames: {skippedFrames, number}',
stats stats
); );

View file

@ -4,8 +4,8 @@
// Chat Emote Menu // Chat Emote Menu
// ============================================================================ // ============================================================================
import {has, get, once, maybe_call, set_equals} from 'utilities/object'; import {has, get, once, maybe_call, set_equals, getTwitchEmoteURL, getTwitchEmoteSrcSet} from 'utilities/object';
import {TWITCH_GLOBAL_SETS, EmoteTypes, TWITCH_POINTS_SETS, TWITCH_PRIME_SETS, WEBKIT_CSS as WEBKIT, IS_OSX, KNOWN_CODES, TWITCH_EMOTE_BASE, REPLACEMENT_BASE, REPLACEMENTS, KEYS} from 'utilities/constants'; import {TWITCH_GLOBAL_SETS, EmoteTypes, TWITCH_POINTS_SETS, TWITCH_PRIME_SETS, WEBKIT_CSS as WEBKIT, IS_OSX, KNOWN_CODES, REPLACEMENT_BASE, REPLACEMENTS, KEYS} from 'utilities/constants';
import {HIDDEN_CATEGORIES, CATEGORIES, CATEGORY_SORT, IMAGE_PATHS} from 'src/modules/chat/emoji'; import {HIDDEN_CATEGORIES, CATEGORIES, CATEGORY_SORT, IMAGE_PATHS} from 'src/modules/chat/emoji';
import {ClickOutside} from 'utilities/dom'; import {ClickOutside} from 'utilities/dom';
@ -639,8 +639,8 @@ export default class EmoteMenu extends Module {
this.props.stopObserving(this.ref); this.props.stopObserving(this.ref);
} }
keyInteract(code) { keyInteract(code) { // eslint-disable-line
/* no-op */
} }
clickEmote(event) { clickEmote(event) {
@ -1855,14 +1855,16 @@ export default class EmoteMenu extends Module {
overridden = mapped && mapped.id != new_id, overridden = mapped && mapped.id != new_id,
replacement = REPLACEMENTS[new_id]; replacement = REPLACEMENTS[new_id];
let src, srcSet; let src, srcSet, animSrc, animSrcSet;
if ( replacement && t.chat.context.get('chat.fix-bad-emotes') ) if ( replacement && t.chat.context.get('chat.fix-bad-emotes') )
src = `${REPLACEMENT_BASE}${replacement}`; src = `${REPLACEMENT_BASE}${replacement}`;
else { else {
const base = `${TWITCH_EMOTE_BASE}${new_id}`; src = getTwitchEmoteURL(new_id, 1, false);
src = `${base}/1.0`; srcSet = getTwitchEmoteSrcSet(new_id, false);
srcSet = `${src} 1x, ${base}/2.0 2x`
animSrc = getTwitchEmoteURL(new_id, 1, true);
animSrcSet = getTwitchEmoteSrcSet(new_id, true);
} }
const em = { const em = {
@ -1872,6 +1874,8 @@ export default class EmoteMenu extends Module {
name: new_name, name: new_name,
src, src,
srcSet, srcSet,
animSrc,
animSrcSet,
order: order++, order: order++,
overridden: overridden ? mapped.id : null, overridden: overridden ? mapped.id : null,
misc: ! chan, misc: ! chan,
@ -1967,7 +1971,6 @@ export default class EmoteMenu extends Module {
continue; continue;
const id = emote.id, const id = emote.id,
base = `${TWITCH_EMOTE_BASE}${id}`,
name = KNOWN_CODES[emote.token] || emote.token, name = KNOWN_CODES[emote.token] || emote.token,
seen = twitch_seen.has(id), seen = twitch_seen.has(id),
is_fav = twitch_favorites.includes(id); is_fav = twitch_favorites.includes(id);
@ -1979,8 +1982,10 @@ export default class EmoteMenu extends Module {
name, name,
order: order++, order: order++,
locked: locked && ! seen, locked: locked && ! seen,
src: `${base}/1.0`, src: getTwitchEmoteURL(id, 1, false),
srcSet: `${base}/1.0 1x, ${base}/2.0 2x`, srcSet: getTwitchEmoteSrcSet(id, false),
animSrc: getTwitchEmoteURL(id, 1, true),
animSrcSet: getTwitchEmoteSrcSet(id, true),
favorite: is_fav, favorite: is_fav,
hidden: twitch_hidden.includes(id) hidden: twitch_hidden.includes(id)
}; };
@ -2024,8 +2029,7 @@ export default class EmoteMenu extends Module {
emotes: new Set([emote.id]) emotes: new Set([emote.id])
} }
const base = `${TWITCH_EMOTE_BASE}${id}`, const is_fav = twitch_favorites.includes(id);
is_fav = twitch_favorites.includes(id);
/*if ( Array.isArray(emote.modifiers) && emote.modifiers.length ) /*if ( Array.isArray(emote.modifiers) && emote.modifiers.length )
modifiers[id] = emote.modifiers;*/ modifiers[id] = emote.modifiers;*/
@ -2037,8 +2041,10 @@ export default class EmoteMenu extends Module {
name: emote.token, name: emote.token,
locked, locked,
order: order++, order: order++,
src: `${base}/1.0`, src: getTwitchEmoteURL(id, 1, false),
srcSet: `${base}/1.0 1x, ${base}/2.0 2x`, srcSet: getTwitchEmoteSrcSet(id, false),
animSrc: getTwitchEmoteURL(id, 1, true),
animSrcSet: getTwitchEmoteSrcSet(id, true),
bits: true, bits: true,
bit_value: summary.threshold, bit_value: summary.threshold,
favorite: is_fav, favorite: is_fav,

View file

@ -6,10 +6,11 @@
import Module from 'utilities/module'; import Module from 'utilities/module';
import { findReactFragment } from 'utilities/dom'; import { findReactFragment } from 'utilities/dom';
import { TWITCH_POINTS_SETS, TWITCH_GLOBAL_SETS, TWITCH_PRIME_SETS, KNOWN_CODES, REPLACEMENTS, REPLACEMENT_BASE, TWITCH_EMOTE_BASE, KEYS } from 'utilities/constants'; import { TWITCH_POINTS_SETS, TWITCH_GLOBAL_SETS, TWITCH_PRIME_SETS, KNOWN_CODES, REPLACEMENTS, REPLACEMENT_BASE, KEYS } from 'utilities/constants';
import Twilight from 'site'; import Twilight from 'site';
import { FFZEvent } from 'src/utilities/events'; import { FFZEvent } from 'src/utilities/events';
import { getTwitchEmoteSrcSet, getTwitchEmoteURL } from 'src/utilities/object';
export default class Input extends Module { export default class Input extends Module {
constructor(...args) { constructor(...args) {
@ -623,15 +624,13 @@ export default class Input extends Module {
continue; continue;
const replacement = REPLACEMENTS[id]; const replacement = REPLACEMENTS[id];
let src, srcSet; let srcSet, animSrcSet;
if ( replacement && this.chat.context.get('chat.fix-bad-emotes') ) { if ( replacement && this.chat.context.get('chat.fix-bad-emotes') ) {
src = `${REPLACEMENT_BASE}${replacement}`; srcSet = `${REPLACEMENT_BASE}${replacement} 1x`;
srcSet = `${src} 1x`;
} else { } else {
const base = `${TWITCH_EMOTE_BASE}${id}`; srcSet = getTwitchEmoteSrcSet(id, false);
src = `${base}/1.0`; animSrcSet = getTwitchEmoteSrcSet(id, true);
srcSet = `${src} 1x, ${base}/2.0 2x`
} }
out.push({ out.push({
@ -642,6 +641,7 @@ export default class Input extends Module {
token, token,
tokenLower: token.toLowerCase(), tokenLower: token.toLowerCase(),
srcSet, srcSet,
animSrcSet,
favorite: favorites.includes(id) favorite: favorites.includes(id)
}); });
} }

View file

@ -55,6 +55,7 @@ export const KEYS = {
export const TWITCH_EMOTE_BASE = '//static-cdn.jtvnw.net/emoticons/v1/'; export const TWITCH_EMOTE_BASE = '//static-cdn.jtvnw.net/emoticons/v1/';
export const TWITCH_EMOTE_V2 = '//static-cdn.jtvnw.net/emoticons/v2';
export const KNOWN_CODES = { export const KNOWN_CODES = {
'#-?[\\\\/]': '#-/', '#-?[\\\\/]': '#-/',

View file

@ -1,9 +1,20 @@
'use strict'; 'use strict';
import {BAD_HOTKEYS} from 'utilities/constants'; import {BAD_HOTKEYS, TWITCH_EMOTE_V2} from 'utilities/constants';
const HOP = Object.prototype.hasOwnProperty; const HOP = Object.prototype.hasOwnProperty;
export function getTwitchEmoteURL(id, scale, animated = false, dark = true) {
return `${TWITCH_EMOTE_V2}/${id}/${animated ? 'default' : 'static'}/${dark ? 'dark' : 'light'}/${scale}.0`
}
export function getTwitchEmoteSrcSet(id, animated = false, dark = true, big = false) {
if ( big )
return `${getTwitchEmoteURL(id, 2, animated, dark)} 1x, ${getTwitchEmoteURL(id, 4, animated, dark)} 2x`;
return `${getTwitchEmoteURL(id, 1, animated, dark)} 1x, ${getTwitchEmoteURL(id, 2, animated, dark)} 2x, ${getTwitchEmoteURL(id, 4, animated, dark)} 4x`;
}
export function isValidShortcut(key) { export function isValidShortcut(key) {
if ( ! key ) if ( ! key )
return false; return false;

View file

@ -12,6 +12,11 @@ dayjs.extend(RelativeTime);
import Parser from '@ffz/icu-msgparser'; import Parser from '@ffz/icu-msgparser';
const DEFAULT_PARSER_OPTIONS = {
allowTags: false,
requireOther: false
};
import {get} from 'utilities/object'; import {get} from 'utilities/object';
import {duration_to_string} from 'utilities/time'; import {duration_to_string} from 'utilities/time';
@ -217,7 +222,7 @@ export default class TranslationCore {
this.formats[key] = Object.assign({}, this.formats[key], options.formats[key]); this.formats[key] = Object.assign({}, this.formats[key], options.formats[key]);
this.types = Object.assign({}, DEFAULT_TYPES, options.types || {}); this.types = Object.assign({}, DEFAULT_TYPES, options.types || {});
this.parser = new Parser(options.parserOptions); this.parser = new Parser(Object.assign({}, DEFAULT_PARSER_OPTIONS, options.parserOptions));
if ( options.phrases ) if ( options.phrases )
this.extend(options.phrases); this.extend(options.phrases);