1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00
* Added: Add a `Reset` button to the headers of the badge visibility controls.
* Changed: Move some Twitch badges into a new `Twitch: Other` category.
* Changed: Do not display the badges in a category when the category is hidden to save space.
* Changed: Expose more data on emotes/emoji to tab completion.
* Fixed: Missing localization for certain items in Chat > Actions > Rooms.
* API Fixed: Ensure that emote set and badge IDs are cast to strings for consistent comparisons.
* API Fixed: Fix reference counting issues for emote sets when a set or badge is added from multiple providers.
* API Changed: Newly loaded emote sets are automatically scheduled for garbage collection if they have no users.
* API Changed: Added `removeAllSets(provider)` method to `Room`s and `Users`s.
* API Changed: Standardize `addSet(provider, set_id, data)` to allow passing set data in `Room` and `User`.
* API Changed: `addSet(...)` and `removeSet(...)` now return a boolean of whether or not the set was added or removed.
This commit is contained in:
SirStendec 2021-06-10 18:53:16 -04:00
parent a74faa95d3
commit 2a57ecb8a7
9 changed files with 188 additions and 59 deletions

View file

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

View file

@ -294,6 +294,7 @@ export default class Badges extends Module {
getSettingsBadges(include_addons, callback) {
const twitch = [],
other = [],
owl = [],
tcon = [],
game = [],
@ -333,7 +334,9 @@ export default class Badges extends Module {
if ( v ) {
let cat;
if ( badge.__cat === 'm-owl' )
if ( badge.__cat === 'm-other' )
cat = other;
else if ( badge.__cat === 'm-owl' )
cat = owl;
else if ( badge.__cat === 'm-tcon' )
cat = tcon;
@ -382,6 +385,7 @@ export default class Badges extends Module {
return [
{title: 'Twitch', id: 'm-twitch', badges: twitch},
{title: 'Twitch: TwitchCon', id: 'm-tcon', badges: tcon},
{title: 'Twitch: Other', id: 'm-other', badges: other},
{title: 'Twitch: Overwatch League', id: 'm-owl', badges: owl},
{title: 'Twitch: Game', id: 'm-game', key: 'game', badges: game},
{title: 'FrankerFaceZ', id: 'm-ffz', badges: ffz},
@ -1148,10 +1152,22 @@ export default class Badges extends Module {
}
const OTHER_BADGES = [
'vga-champ-2017',
'warcraft',
'samusoffer_beta',
'power-rangers',
'bits-charity',
'glhf-pledge'
];
export function getBadgeCategory(key) {
if ( key.startsWith('overwatch-league') )
if ( OTHER_BADGES.includes(key) )
return 'm-other';
else if ( key.startsWith('overwatch-league') )
return 'm-owl';
else if ( key.startsWith('twitchcon') )
else if ( key.startsWith('twitchcon') || key.startsWith('glitchcon') )
return 'm-tcon';
else if ( /_\d+$/.test(key) )
return 'm-game';

View file

@ -100,6 +100,8 @@ export default class Emoji extends Module {
// For some reason, splitter is a function.
this.splitter = splitter();
this.categories = CATEGORIES;
this.emoji = {};
this.names = {};
this.chars = new Map;

View file

@ -57,7 +57,6 @@ const MODIFIERS = {
};
export default class Emotes extends Module {
constructor(...args) {
super(...args);
@ -636,30 +635,42 @@ export default class Emotes extends Module {
// ========================================================================
addDefaultSet(provider, set_id, data) {
let changed = false;
if ( typeof set_id === 'number' )
set_id = `${set_id}`;
let changed = false, added = false;
if ( ! this.default_sets.sourceIncludes(provider, set_id) ) {
changed = ! this.default_sets.includes(set_id);
this.default_sets.push(provider, set_id);
this.refSet(set_id);
changed = true;
added = true;
}
if ( data )
this.loadSetData(set_id, data);
if ( changed )
if ( changed ) {
this.refSet(set_id);
this.emit(':update-default-sets', provider, set_id, true);
}
return added;
}
removeDefaultSet(provider, set_id) {
let changed = false;
if ( typeof set_id === 'number' )
set_id = `${set_id}`;
if ( this.default_sets.sourceIncludes(provider, set_id) ) {
this.default_sets.remove(provider, set_id);
this.unrefSet(set_id);
changed = true;
if ( ! this.default_sets.includes(set_id) ) {
this.unrefSet(set_id);
this.emit(':update-default-sets', provider, set_id, false);
}
return true;
}
if ( changed )
this.emit(':update-default-sets', provider, set_id, false);
return false;
}
refSet(set_id) {
@ -668,7 +679,6 @@ export default class Emotes extends Module {
clearTimeout(this._set_timers[set_id]);
this._set_timers[set_id] = null;
}
}
unrefSet(set_id) {
@ -885,6 +895,11 @@ export default class Emotes extends Module {
this.log.info(`Loaded emote set #${set_id}: ${data.title} (${count} emotes)`);
this.emit(':loaded', set_id, data);
// Don't let people endlessly load unused sets.
const refs = this._set_refs[set_id] || 0;
if ( refs <= 0 && ! this._set_timers[set_id] )
this._set_timers[set_id] = setTimeout(() => this.unloadSet(set_id), 5000);
}
@ -904,6 +919,11 @@ export default class Emotes extends Module {
if ( ! suppress_log )
this.log.info(`Unloaded emote set #${set_id}: ${old_set.title}`);
if ( this._set_timers[set_id] ) {
clearTimeout(this._set_timers[set_id]);
this._set_timers[set_id] = null;
}
this.emit(':unloaded', set_id, old_set);
this.emote_sets[set_id] = null;
}

View file

@ -306,13 +306,10 @@ export default class Room {
this.data = d;
if ( d.set ) {
if ( ! this.emote_sets )
this.emote_sets = new SourcedSet;
this.emote_sets.set('main', d.set);
} else if ( this.emote_sets )
this.emote_sets.delete('main');
if ( d.set )
this.addSet('main', d.set);
else
this.removeAllSets('main');
if ( data.sets )
for(const set_id in data.sets)
@ -349,29 +346,59 @@ export default class Room {
if ( ! this.emote_sets )
this.emote_sets = new SourcedSet;
let changed = false;
if ( typeof set_id === 'number' )
set_id = `${set_id}`;
let changed = false, added = false;
if ( ! this.emote_sets.sourceIncludes(provider, set_id) ) {
changed = ! this.emote_sets.includes(set_id);
this.emote_sets.push(provider, set_id);
this.manager.emotes.refSet(set_id);
changed = true;
added = true;
}
if ( data )
this.manager.emotes.loadSetData(set_id, data);
if ( changed )
if ( changed ) {
this.manager.emotes.refSet(set_id);
this.manager.emotes.emit(':update-room-sets', this, provider, set_id, true);
}
return added;
}
removeAllSets(provider) {
if ( this.destroyed || ! this.emote_sets )
return false;
const sets = this.emote_sets.get(provider);
if ( ! Array.isArray(sets) || ! sets.length )
return false;
for(const set_id of sets)
this.removeSet(provider, set_id);
return true;
}
removeSet(provider, set_id) {
if ( this.destroyed || ! this.emote_sets )
return;
if ( typeof set_id === 'number' )
set_id = `${set_id}`;
if ( this.emote_sets.sourceIncludes(provider, set_id) ) {
this.emote_sets.remove(provider, set_id);
this.manager.emotes.unrefSet(set_id);
this.manager.emotes.emit(':update-room-sets', this, provider, set_id, false);
if ( ! this.emote_sets.includes(set_id) ) {
this.manager.emotes.unrefSet(set_id);
this.manager.emotes.emit(':update-room-sets', this, provider, set_id, false);
}
return true;
}
return false;
}

View file

@ -106,6 +106,9 @@ export default class User {
if ( this.destroyed )
return;
if ( typeof badge_id === 'number' )
badge_id = `${badge_id}`;
if ( data )
data.id = badge_id;
else
@ -132,7 +135,7 @@ export default class User {
return null;
for(const badge of this.badges._cache)
if ( badge.id == badge_id )
if ( badge.id == badge_id )
return badge;
}
@ -155,29 +158,64 @@ export default class User {
// Emote Sets
// ========================================================================
addSet(provider, set_id) {
addSet(provider, set_id, data) {
if ( this.destroyed )
return;
if ( ! this.emote_sets )
this.emote_sets = new SourcedSet;
if ( typeof set_id === 'number' )
set_id = `${set_id}`;
let changed = false, added = false;
if ( ! this.emote_sets.sourceIncludes(provider, set_id) ) {
changed = ! this.emote_sets.includes(set_id);
this.emote_sets.push(provider, set_id);
added = true;
}
if ( data )
this.manager.emotes.loadSetData(set_id, data);
if ( changed ) {
this.manager.emotes.refSet(set_id);
this.manager.emotes.emit(':update-user-sets', this, provider, set_id, true);
return true;
}
return added;
}
removeAllSets(provider) {
if ( this.destroyed || ! this.emote_sets )
return false;
const sets = this.emote_sets.get(provider);
if ( ! Array.isArray(sets) || ! sets.length )
return false;
for(const set_id of sets)
this.removeSet(provider, set_id);
return true;
}
removeSet(provider, set_id) {
if ( this.destroyed || ! this.emote_sets )
return;
if ( typeof set_id === 'number' )
set_id = `${set_id}`;
if ( this.emote_sets.sourceIncludes(provider, set_id) ) {
this.emote_sets.remove(provider, set_id);
this.manager.emotes.unrefSet(set_id);
this.manager.emotes.emit(':update-user-sets', this, provider, set_id, false);
if ( ! this.emote_sets.includes(set_id) ) {
this.manager.emotes.unrefSet(set_id);
this.manager.emotes.emit(':update-user-sets', this, provider, set_id, false);
}
return true;
}
return false;
}
}

View file

@ -32,7 +32,7 @@
<header
v-if="sec.id"
:class="{default: badgeDefault(sec.id)}"
class="tw-flex ffz-checkbox"
class="tw-flex ffz-checkbox tw-align-items-center tw-z-above"
>
<input
:id="sec.id"
@ -40,23 +40,33 @@
type="checkbox"
class="ffz-checkbox__input"
@click="onChange(sec.id, $event)"
@contextmenu.prevent="reset(sec.id)"
>
<label
:for="sec.id"
:title="t('setting.right-click-reset', 'Right-Click to Reset')"
class="ffz-checkbox__label"
@contextmenu.prevent="reset(sec.id)"
>
<span class="tw-mg-l-1">
{{ sec.title }}
</span>
</label>
<div class="ffz--reset-button">
<button
v-if="! badgeDefault(sec.id)"
class="tw-mg-l-05 tw-button tw-button--text ffz-il-tooltip__container"
@click="reset(sec.id)"
>
<span class="tw-button__text ffz-i-cancel" />
<div class="ffz-il-tooltip ffz-il-tooltip--down ffz-il-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</div>
</button>
</div>
</header>
<header v-else>
{{ sec.title }}
</header>
<ul class="tw-flex tw-flex-wrap tw-align-content-start">
<ul v-if="! sec.id || badgeChecked(sec.id)" class="tw-flex tw-flex-wrap tw-align-content-start">
<li
v-for="i in sec.badges"
:key="i.id"
@ -96,7 +106,7 @@
class="tw-mg-t-05 tw-button ffz-button--hollow ffz-il-tooltip__container"
@click="reset(i.id)"
>
<span class="tw-button__text">Reset</span>
<span class="tw-button__text ffz-i-cancel" />
<span class="ffz-il-tooltip ffz-il-tooltip--down ffz-il-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</span>
@ -106,6 +116,11 @@
</label>
</li>
</ul>
<div v-else class="tw-c-text-alt-2 tw-font-size-4 tw-align-center tw-pd-05">
{{ t('setting.badges.hidden', '{count,plural,one{# badge is} other{# badges are} } hidden in this set', {
count: sec.badges.length
}) }}
</div>
</section>
</div>
</template>

View file

@ -472,6 +472,7 @@ export default {
if ( ! this.item.inline ) {
out.push({
title: 'New Line',
title_i18n: 'setting.new-line',
value: {
v: {type: 'new-line'}
}
@ -479,6 +480,7 @@ export default {
out.push({
title: 'Space (Small)',
title_i18n: 'setting.space-small',
value: {
v: {type: 'space-small'}
}
@ -486,6 +488,7 @@ export default {
out.push({
title: 'Space (Expanding)',
title_i18n: 'setting.space',
value: {
v: {type: 'space'}
}

View file

@ -588,28 +588,29 @@ export default class Input extends Module {
favorites = this.emotes.getFavorites('twitch');
for(const set of emotes) {
if ( has_hidden ) {
const int_id = parseInt(set.id, 10),
owner = set.owner,
is_points = TWITCH_POINTS_SETS.includes(int_id) || owner?.login === 'channel_points',
channel = is_points ? null : owner;
const int_id = parseInt(set.id, 10),
owner = set.owner,
is_points = TWITCH_POINTS_SETS.includes(int_id) || owner?.login === 'channel_points',
channel = is_points ? null : owner;
let key = `twitch-set-${set.id}`;
let key = `twitch-set-${set.id}`;
let extra = null;
if ( channel?.login )
key = `twitch-${channel.id}`;
else if ( is_points )
key = 'twitch-points';
else if ( TWITCH_GLOBAL_SETS.includes(int_id) )
key = 'twitch-global';
else if ( TWITCH_PRIME_SETS.includes(int_id) )
key = 'twitch-prime';
else
key = 'twitch-misc';
if ( channel?.login ) {
key = `twitch-${channel.id}`;
extra = channel.displayName || channel.login;
if ( hidden_sets.includes(key) )
continue;
}
} else if ( is_points )
key = 'twitch-points';
else if ( TWITCH_GLOBAL_SETS.includes(int_id) )
key = 'twitch-global';
else if ( TWITCH_PRIME_SETS.includes(int_id) )
key = 'twitch-prime';
else
key = 'twitch-misc';
if ( has_hidden && hidden_sets.includes(key) )
continue;
for(const emote of set.emotes) {
if ( ! emote || ! emote.id || hidden_emotes.includes(emote.id) )
@ -635,6 +636,8 @@ export default class Input extends Module {
out.push({
id,
source: key,
extra,
setID: set.id,
token,
tokenLower: token.toLowerCase(),
@ -721,15 +724,17 @@ export default class Input extends Module {
included.add(source.raw);
const srcSet = this.emoji.getFullImageSet(source.image, style);
const matched = `:${name}:`;
const favorite = favorites.includes(emoji.code);
results.push({
current: input,
emoji: source,
matched,
srcSet,
replacement: source.raw,
element: inst.renderFFZEmojiSuggestion({
token: `:${name}:`,
token: matched,
id: `emoji-${emoji.code}`,
src: this.emoji.getFullImage(source.image, style),
srcSet,
@ -760,6 +765,7 @@ export default class Input extends Module {
continue;
const source = set.source || 'ffz',
source_line = set.source_line || (`${set.source || 'FFZ'} ${set.title || 'Global'}`),
key = `${set.merge_source || source}-${set.merge_id || set.id}`;
if ( has_hidden && hidden_sets.includes(key) )
@ -779,6 +785,8 @@ export default class Input extends Module {
out.push({
id: `${source}-${emote.id}`,
source,
extra: source_line,
token: emote.name,
tokenLower: emote.name.toLowerCase(),
srcSet: anim && emote.animSrcSet || emote.srcSet,