mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-07 14:50:56 +00:00
4.9.0
Added: Chat Room Actions can now be filtered by a room being in emote-only mode, subs-only mode, or slow mode. Added: Option to hide Latest Videos in the Following directory. Added: Option to display the current stream delay in a warning color if it exceeds a certain value. Fixed: Emote previews not appearing correctly in tool-tips. Fixed: Option to hide Rerun bar not functioning correctly. Fixed: Favorite emotes from add-ons and other extensions not being sorted correctly for tab-completion.
This commit is contained in:
parent
f32b2efd1a
commit
c39f6799d3
10 changed files with 231 additions and 30 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.8.2",
|
"version": "4.9.0",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -133,7 +133,7 @@ export default class Actions extends Module {
|
||||||
ui: {
|
ui: {
|
||||||
path: 'Chat > Actions > Room @{"description": "Here, you can define custom actions that will appear above the chat input box."}',
|
path: 'Chat > Actions > Room @{"description": "Here, you can define custom actions that will appear above the chat input box."}',
|
||||||
component: 'chat-actions',
|
component: 'chat-actions',
|
||||||
context: ['room'],
|
context: ['room', 'room-mode'],
|
||||||
inline: true,
|
inline: true,
|
||||||
|
|
||||||
data: () => {
|
data: () => {
|
||||||
|
@ -436,7 +436,10 @@ export default class Actions extends Module {
|
||||||
if ( ! def || disp.disabled ||
|
if ( ! def || disp.disabled ||
|
||||||
(disp.mod_icons != null && disp.mod_icons !== !!mod_icons) ||
|
(disp.mod_icons != null && disp.mod_icons !== !!mod_icons) ||
|
||||||
(disp.mod != null && disp.mod !== (current_user ? !!current_user.mod : false)) ||
|
(disp.mod != null && disp.mod !== (current_user ? !!current_user.mod : false)) ||
|
||||||
(disp.staff != null && disp.staff !== (current_user ? !!current_user.staff : false)) )
|
(disp.staff != null && disp.staff !== (current_user ? !!current_user.staff : false)) ||
|
||||||
|
(disp.emoteOnly != null && disp.emoteOnly !== current_room.emoteOnly) ||
|
||||||
|
(disp.slowMode != null && disp.slowMode !== current_room.slowMode) ||
|
||||||
|
(disp.subsMode != null && disp.subsMode !== current_room.subsMode) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const has_color = def.colored && ap.color,
|
const has_color = def.colored && ap.color,
|
||||||
|
|
|
@ -5,8 +5,6 @@ query FFZ_GetEmoteInfo($id: ID!) {
|
||||||
text
|
text
|
||||||
subscriptionProduct {
|
subscriptionProduct {
|
||||||
id
|
id
|
||||||
displayName
|
|
||||||
state
|
|
||||||
owner {
|
owner {
|
||||||
id
|
id
|
||||||
login
|
login
|
||||||
|
@ -14,12 +12,6 @@ query FFZ_GetEmoteInfo($id: ID!) {
|
||||||
}
|
}
|
||||||
tier
|
tier
|
||||||
url
|
url
|
||||||
self {
|
|
||||||
benefit {
|
|
||||||
id
|
|
||||||
endsAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -798,6 +798,41 @@ export default class Emotes extends Module {
|
||||||
return tes.get(emote_id);
|
return tes.get(emote_id);
|
||||||
|
|
||||||
tes.set(emote_id, null);
|
tes.set(emote_id, null);
|
||||||
|
|
||||||
|
/*const apollo = this.resolve('site.apollo');
|
||||||
|
if ( apollo?.client ) {
|
||||||
|
timeout(apollo.client.query({
|
||||||
|
query: GET_EMOTE,
|
||||||
|
variables: {
|
||||||
|
id: `${emote_id}`
|
||||||
|
}
|
||||||
|
}), 1000).then(result => {
|
||||||
|
const emote = result?.data?.emote;
|
||||||
|
|
||||||
|
if ( ! emote ) {
|
||||||
|
tes.delete(emote_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const set_id = parseInt(emote.setID, 10),
|
||||||
|
channel = emote?.subscriptionProduct?.owner;
|
||||||
|
|
||||||
|
this.__twitch_set_to_channel.set(set_id, {
|
||||||
|
s_id: set_id,
|
||||||
|
c_id: channel ? channel.id : null,
|
||||||
|
c_name: channel ? channel.login : null,
|
||||||
|
c_title: channel ? channel.displayName : null
|
||||||
|
});
|
||||||
|
|
||||||
|
tes.set(emote_id, set_id);
|
||||||
|
if ( callback )
|
||||||
|
callback(set_id);
|
||||||
|
|
||||||
|
}).catch(() => tes.delete(emote_id));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
timeout(this.socket.call('get_emote', emote_id), 1000).then(data => {
|
timeout(this.socket.call('get_emote', emote_id), 1000).then(data => {
|
||||||
const set_id = data['s_id'];
|
const set_id = data['s_id'];
|
||||||
tes.set(emote_id, set_id);
|
tes.set(emote_id, set_id);
|
||||||
|
@ -827,6 +862,7 @@ export default class Emotes extends Module {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
tes.set(set_id, null);
|
tes.set(set_id, null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await timeout(this.socket.call('get_emote_set', set_id), 1000);
|
const data = await timeout(this.socket.call('get_emote_set', set_id), 1000);
|
||||||
tes.set(set_id, data);
|
tes.set(set_id, data);
|
||||||
|
|
|
@ -1028,7 +1028,7 @@ export const AddonEmotes = {
|
||||||
const set_id = this.emotes.getTwitchEmoteSet(emote_id, tip.rerender),
|
const set_id = this.emotes.getTwitchEmoteSet(emote_id, tip.rerender),
|
||||||
emote_set = set_id != null && this.emotes.getTwitchSetChannel(set_id, tip.rerender);
|
emote_set = set_id != null && this.emotes.getTwitchSetChannel(set_id, tip.rerender);
|
||||||
|
|
||||||
preview = `//static-cdn.jtvnw.net/emoticons/v1/${emote_id}/4.0?_=preview`;
|
preview = `//static-cdn.jtvnw.net/emoticons/v1/${emote_id}/3.0?_=preview`;
|
||||||
fav_source = 'twitch';
|
fav_source = 'twitch';
|
||||||
|
|
||||||
if ( emote_set ) {
|
if ( emote_set ) {
|
||||||
|
|
|
@ -140,6 +140,72 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="has_mode" class="tw-flex tw-align-items-center">
|
||||||
|
<label for="vis_emote">
|
||||||
|
{{ t('setting.actions.edit-visible.emote-only', 'Emote-Only Mode') }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<select
|
||||||
|
id="vis_emote"
|
||||||
|
v-model="edit_data.display.emoteOnly"
|
||||||
|
class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
|
||||||
|
>
|
||||||
|
<option :value="undefined" selected>
|
||||||
|
{{ t('setting.unset', 'Unset') }}
|
||||||
|
</option>
|
||||||
|
<option :value="true">
|
||||||
|
{{ t('setting.true', 'True') }}
|
||||||
|
</option>
|
||||||
|
<option :value="false">
|
||||||
|
{{ t('setting.false', 'False') }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="has_mode" class="tw-flex tw-align-items-center">
|
||||||
|
<label for="vis_slow">
|
||||||
|
{{ t('setting.actions.edit-visible.slow', 'Slow Mode') }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<select
|
||||||
|
id="vis_slow"
|
||||||
|
v-model="edit_data.display.slowMode"
|
||||||
|
class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
|
||||||
|
>
|
||||||
|
<option :value="undefined" selected>
|
||||||
|
{{ t('setting.unset', 'Unset') }}
|
||||||
|
</option>
|
||||||
|
<option :value="true">
|
||||||
|
{{ t('setting.true', 'True') }}
|
||||||
|
</option>
|
||||||
|
<option :value="false">
|
||||||
|
{{ t('setting.false', 'False') }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="has_mode" class="tw-flex tw-align-items-center">
|
||||||
|
<label for="vis_subs">
|
||||||
|
{{ t('setting.actions.edit-visible.subs', 'Subs Mode') }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<select
|
||||||
|
id="vis_subs"
|
||||||
|
v-model="edit_data.display.subsMode"
|
||||||
|
class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
|
||||||
|
>
|
||||||
|
<option :value="undefined" selected>
|
||||||
|
{{ t('setting.unset', 'Unset') }}
|
||||||
|
</option>
|
||||||
|
<option :value="true">
|
||||||
|
{{ t('setting.true', 'True') }}
|
||||||
|
</option>
|
||||||
|
<option :value="false">
|
||||||
|
{{ t('setting.false', 'False') }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="has_modifiers" class="tw-flex tw-align-items-start">
|
<div v-if="has_modifiers" class="tw-flex tw-align-items-start">
|
||||||
<label for="vis_modifiers">
|
<label for="vis_modifiers">
|
||||||
{{ t('setting.actions.edit-visible.modifier', 'Modifiers') }}
|
{{ t('setting.actions.edit-visible.modifier', 'Modifiers') }}
|
||||||
|
@ -325,6 +391,10 @@ export default {
|
||||||
return this.context && this.context.includes('message')
|
return this.context && this.context.includes('message')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
has_mode() {
|
||||||
|
return this.context && this.context.includes('room-mode')
|
||||||
|
},
|
||||||
|
|
||||||
has_modifiers() {
|
has_modifiers() {
|
||||||
return this.modifiers
|
return this.modifiers
|
||||||
},
|
},
|
||||||
|
@ -467,6 +537,23 @@ export default {
|
||||||
else if ( disp.deleted === false )
|
else if ( disp.deleted === false )
|
||||||
out.push(this.t('setting.actions.visible.undeleted', 'if message not deleted'));
|
out.push(this.t('setting.actions.visible.undeleted', 'if message not deleted'));
|
||||||
|
|
||||||
|
if ( this.has_mode ) {
|
||||||
|
if ( disp.emoteOnly === true )
|
||||||
|
out.push(this.t('setting.actions.visible.emote-only', 'when emote-only mode'));
|
||||||
|
else if ( disp.emoteOnly === false )
|
||||||
|
out.push(this.t('setting.actions.visible.no-emote', 'when not emote-only mode'));
|
||||||
|
|
||||||
|
if ( disp.slowMode === true )
|
||||||
|
out.push(this.t('setting.actions.visible.slow', 'when slow mode'));
|
||||||
|
else if ( disp.slowMode === false )
|
||||||
|
out.push(this.t('setting.actions.visible.no-slow', 'when not slow mode'));
|
||||||
|
|
||||||
|
if ( disp.subsMode === true )
|
||||||
|
out.push(this.t('setting.actions.visible.subs', 'when subs mode'));
|
||||||
|
else if ( disp.subsMode === false )
|
||||||
|
out.push(this.t('setting.actions.visible.no-subs', 'when not subs mode'));
|
||||||
|
}
|
||||||
|
|
||||||
if ( disp.keys ) {
|
if ( disp.keys ) {
|
||||||
const key_out = [];
|
const key_out = [];
|
||||||
if ( disp.keys & 1 )
|
if ( disp.keys & 1 )
|
||||||
|
|
|
@ -57,6 +57,51 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="has_mode" class="tw-pd-x-1 tw-checkbox">
|
||||||
|
<input
|
||||||
|
id="with_slow"
|
||||||
|
ref="with_slow"
|
||||||
|
:checked="with_slow"
|
||||||
|
type="checkbox"
|
||||||
|
class="tw-checkbox__input"
|
||||||
|
@change="onPreview"
|
||||||
|
>
|
||||||
|
|
||||||
|
<label for="with_slow" class="tw-checkbox__label">
|
||||||
|
{{ t('setting.actions.preview.slow', 'Slow Mode') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="has_mode" class="tw-pd-x-1 tw-checkbox">
|
||||||
|
<input
|
||||||
|
id="with_emote"
|
||||||
|
ref="with_emote"
|
||||||
|
:checked="with_emote"
|
||||||
|
type="checkbox"
|
||||||
|
class="tw-checkbox__input"
|
||||||
|
@change="onPreview"
|
||||||
|
>
|
||||||
|
|
||||||
|
<label for="with_emote" class="tw-checkbox__label">
|
||||||
|
{{ t('setting.actions.preview.emote-only', 'Emote-Only') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="has_mode" class="tw-pd-x-1 tw-checkbox">
|
||||||
|
<input
|
||||||
|
id="with_subs"
|
||||||
|
ref="with_subs"
|
||||||
|
:checked="with_subs"
|
||||||
|
type="checkbox"
|
||||||
|
class="tw-checkbox__input"
|
||||||
|
@change="onPreview"
|
||||||
|
>
|
||||||
|
|
||||||
|
<label for="with_subs" class="tw-checkbox__label">
|
||||||
|
{{ t('setting.actions.preview.subs', 'Subs Only') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tw-pd-x-1 tw-checkbox">
|
<div class="tw-pd-x-1 tw-checkbox">
|
||||||
<input
|
<input
|
||||||
id="show_all"
|
id="show_all"
|
||||||
|
@ -242,6 +287,11 @@ export default {
|
||||||
return {
|
return {
|
||||||
is_moderator: true,
|
is_moderator: true,
|
||||||
with_mod_icons: true,
|
with_mod_icons: true,
|
||||||
|
|
||||||
|
with_emote: false,
|
||||||
|
with_subs: false,
|
||||||
|
with_slow: false,
|
||||||
|
|
||||||
is_staff: false,
|
is_staff: false,
|
||||||
is_deleted: false,
|
is_deleted: false,
|
||||||
show_all: false,
|
show_all: false,
|
||||||
|
@ -300,6 +350,10 @@ export default {
|
||||||
return this.item.context && this.item.context.includes('room')
|
return this.item.context && this.item.context.includes('room')
|
||||||
},
|
},
|
||||||
|
|
||||||
|
has_mode() {
|
||||||
|
return this.item.context && this.item.context.includes('room-mode')
|
||||||
|
},
|
||||||
|
|
||||||
has_msg() {
|
has_msg() {
|
||||||
return this.item.context && this.item.context.includes('message')
|
return this.item.context && this.item.context.includes('message')
|
||||||
},
|
},
|
||||||
|
@ -485,6 +539,10 @@ export default {
|
||||||
this.is_staff = false; //this.$refs.as_staff.checked;
|
this.is_staff = false; //this.$refs.as_staff.checked;
|
||||||
this.with_mod_icons = this.has_icons && this.$refs.with_mod_icons.checked;
|
this.with_mod_icons = this.has_icons && this.$refs.with_mod_icons.checked;
|
||||||
this.is_deleted = this.has_msg && this.$refs.is_deleted.checked;
|
this.is_deleted = this.has_msg && this.$refs.is_deleted.checked;
|
||||||
|
|
||||||
|
this.with_emote = this.has_mode && this.$refs.with_emote.checked;
|
||||||
|
this.with_subs = this.has_mode && this.$refs.with_subs.checked;
|
||||||
|
this.with_slow = this.has_mode && this.$refs.with_slow.checked;
|
||||||
},
|
},
|
||||||
|
|
||||||
displayAction(action) {
|
displayAction(action) {
|
||||||
|
@ -510,6 +568,17 @@ export default {
|
||||||
if ( disp.deleted != null && disp.deleted !== this.is_deleted )
|
if ( disp.deleted != null && disp.deleted !== this.is_deleted )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if ( this.has_mode ) {
|
||||||
|
if ( disp.emoteOnly != null && disp.emoteOnly !== this.with_emote )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( disp.slowMode != null && disp.slowMode !== this.with_slow )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( disp.subsMode != null && disp.subsMode !== this.with_subs )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default class Metadata extends Module {
|
||||||
ui: {
|
ui: {
|
||||||
path: 'Channel > Metadata >> Player',
|
path: 'Channel > Metadata >> Player',
|
||||||
title: 'Stream Delay Warning',
|
title: 'Stream Delay Warning',
|
||||||
description: 'Define a maximum delay in seconds after which the indicator will be shown in warning colors. (0 for no warning colors)',
|
description: 'When the current stream delay exceeds this number of seconds, display the stream delay in a warning color to draw attention to the large delay. Set to zero to disable.',
|
||||||
|
|
||||||
component: 'setting-text-box',
|
component: 'setting-text-box',
|
||||||
process(val) {
|
process(val) {
|
||||||
|
|
|
@ -171,12 +171,24 @@ export default class Input extends Module {
|
||||||
r = {
|
r = {
|
||||||
id: props.channelID,
|
id: props.channelID,
|
||||||
login: props.channelLogin,
|
login: props.channelLogin,
|
||||||
displayName: props.channelDisplayName
|
displayName: props.channelDisplayName,
|
||||||
|
emoteOnly: props.emoteOnlyMode,
|
||||||
|
slowMode: props.slowMode,
|
||||||
|
slowDuration: props.slowModeDuration,
|
||||||
|
subsMode: props.subsOnlyMode
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = t.actions.renderRoom(t.chat.context.get('context.chat.showModIcons'), u, r, createElement);
|
const actions = t.actions.renderRoom(t.chat.context.get('context.chat.showModIcons'), u, r, createElement);
|
||||||
|
|
||||||
|
// TODO: Instead of putting actions above the chat input,
|
||||||
|
// put them next to the settings menu. This involves going
|
||||||
|
// exploring in the React render output, which is a mess.
|
||||||
|
//t.log.info('chat-input-render', out);
|
||||||
|
|
||||||
if ( actions )
|
if ( actions )
|
||||||
out.props.children.unshift(actions);
|
out.props.children.unshift(actions);
|
||||||
|
else
|
||||||
|
out.props.children.unshift(null);
|
||||||
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
t.log.error(err);
|
t.log.error(err);
|
||||||
|
@ -527,22 +539,24 @@ export default class Input extends Module {
|
||||||
channel_login
|
channel_login
|
||||||
);
|
);
|
||||||
|
|
||||||
for(const set of sets)
|
for(const set of sets) {
|
||||||
for(const emote of Object.values(set.emotes))
|
if ( set && set.emotes )
|
||||||
if ( inst.doesEmoteMatchTerm(emote, search) ) {
|
for(const emote of Object.values(set.emotes))
|
||||||
const favorite = this.emotes.isFavorite(set.source || 'ffz', emote.id);
|
if ( inst.doesEmoteMatchTerm(emote, search) ) {
|
||||||
results.push({
|
const favorite = this.emotes.isFavorite(set.source || 'ffz', emote.id);
|
||||||
current: input,
|
results.push({
|
||||||
replacement: emote.name,
|
current: input,
|
||||||
element: inst.renderEmoteSuggestion({
|
replacement: emote.name,
|
||||||
token: emote.name,
|
element: inst.renderEmoteSuggestion({
|
||||||
id: `${set.source}-${emote.id}`,
|
token: emote.name,
|
||||||
srcSet: emote.srcSet,
|
id: `${set.source}-${emote.id}`,
|
||||||
|
srcSet: emote.srcSet,
|
||||||
|
favorite
|
||||||
|
}),
|
||||||
favorite
|
favorite
|
||||||
}),
|
});
|
||||||
favorite
|
}
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ const CLASSES = {
|
||||||
'player-ext-hover': '.player:not([data-controls="true"]) .extension-container,.player:not([data-controls="true"]) .extensions-dock__layout,.player:not([data-controls="true"]) .extensions-notifications,.player:not([data-controls="true"]) .extensions-video-overlay-size-container',
|
'player-ext-hover': '.player:not([data-controls="true"]) .extension-container,.player:not([data-controls="true"]) .extensions-dock__layout,.player:not([data-controls="true"]) .extensions-notifications,.player:not([data-controls="true"]) .extensions-video-overlay-size-container',
|
||||||
|
|
||||||
'player-event-bar': '.channel-root .live-event-banner-ui__header',
|
'player-event-bar': '.channel-root .live-event-banner-ui__header',
|
||||||
'player-rerun-bar': '.channel-root__player_container div.tw-c-text-overlay:not([data-a-target="hosting-ui-header"])',
|
'player-rerun-bar': '.channel-root__player-container div.tw-c-text-overlay:not([data-a-target="hosting-ui-header"])',
|
||||||
|
|
||||||
'pinned-cheer': '.pinned-cheer,.pinned-cheer-v2',
|
'pinned-cheer': '.pinned-cheer,.pinned-cheer-v2',
|
||||||
'whispers': 'body .whispers',
|
'whispers': 'body .whispers',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue