mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.22.3
* Fixed: Certain page elements not being affected by FFZ theme settings. * Fixed: Do not display new unlisted add-ons on the home page of the FFZ Control Center unless already enabled by the user. * API Added: `getUserBasic(id, login)` in the Twitch Data module, with support for batching. * API Changed: Allow `createTest` to return a null value for a test to be skipped when compiling a complex filter in `createTester()`.
This commit is contained in:
parent
5f0d4b2bfe
commit
c286e6cf93
9 changed files with 173 additions and 22 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.22.2",
|
"version": "4.22.3",
|
||||||
"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",
|
||||||
|
|
|
@ -873,7 +873,7 @@ export default class Chat extends Module {
|
||||||
component: 'setting-text-box',
|
component: 'setting-text-box',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
process: 'to_int',
|
process: 'to_int',
|
||||||
description: 'Mentions of your name have this priority for the purpose of highlighting. See [Chat > Filtering > Highlight](~) for more details.'
|
description: 'Mentions of your name have this priority for the purpose of highlighting. See [Chat > Filtering > Highlight](~chat.filtering.highlight) for more details.'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tw-flex tw-align-items-center">
|
<div v-if="visible_unlisted" class="tw-flex tw-align-items-center">
|
||||||
<div class="tw-flex-grow-1" />
|
<div class="tw-flex-grow-1" />
|
||||||
<div
|
<div
|
||||||
v-on-clickaway="closeUnlisted"
|
v-on-clickaway="closeUnlisted"
|
||||||
|
@ -128,6 +128,10 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
visible_unlisted() {
|
||||||
|
return this.visible_addons.length !== this.sorted_addons.length
|
||||||
|
},
|
||||||
|
|
||||||
visible_addons() {
|
visible_addons() {
|
||||||
return this.sorted_addons.filter(addon => this.shouldShow(addon));
|
return this.sorted_addons.filter(addon => this.shouldShow(addon));
|
||||||
},
|
},
|
||||||
|
@ -180,10 +184,8 @@ export default {
|
||||||
|
|
||||||
if ( value && value.length )
|
if ( value && value.length )
|
||||||
for(const addon of this.item.getAddons())
|
for(const addon of this.item.getAddons())
|
||||||
if ( addon.unlisted && addon.id === value ) {
|
if ( addon.unlisted && (addon.id === value || (addon.short_name && addon.short_name.toLowerCase() === value) || (addon.name && addon.name.toLowerCase() === value)) )
|
||||||
this.unlisted.push(value);
|
this.unlisted.push(addon.id);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$refs.unlisted.value = '';
|
this.$refs.unlisted.value = '';
|
||||||
this.closeUnlisted();
|
this.closeUnlisted();
|
||||||
|
|
|
@ -267,23 +267,28 @@ export default {
|
||||||
if ( addons )
|
if ( addons )
|
||||||
for(const [key, addon] of Object.entries(addons)) {
|
for(const [key, addon] of Object.entries(addons)) {
|
||||||
const enabled = addon_module.isAddonEnabled(key),
|
const enabled = addon_module.isAddonEnabled(key),
|
||||||
copy = {
|
is_new = addon.created && addon.created >= week_ago,
|
||||||
key,
|
is_updated = enabled && addon.updated && addon.updated >= week_ago;
|
||||||
enabled,
|
|
||||||
icon: addon.icon,
|
|
||||||
name: addon.name,
|
|
||||||
name_i18n: addon.name_i18n,
|
|
||||||
updated: addon.updated,
|
|
||||||
settings: addon.settings,
|
|
||||||
version: addon.version
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( addon.created && addon.created >= week_ago )
|
if ( ! is_updated && ! (is_new && ! enabled && ! addon.unlisted) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const copy = {
|
||||||
|
key,
|
||||||
|
enabled,
|
||||||
|
icon: addon.icon,
|
||||||
|
name: addon.name,
|
||||||
|
name_i18n: addon.name_i18n,
|
||||||
|
updated: addon.updated,
|
||||||
|
settings: addon.settings,
|
||||||
|
version: addon.version
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( is_new )
|
||||||
new_out.push(copy);
|
new_out.push(copy);
|
||||||
|
|
||||||
if ( addon.updated && addon.updated >= week_ago && enabled ) {
|
if ( is_updated )
|
||||||
out.push(copy);
|
out.push(copy);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out.sort((a,b) => b.updated - a.updated);
|
out.sort((a,b) => b.updated - a.updated);
|
||||||
|
|
|
@ -485,7 +485,7 @@ The CSS loaded by this setting is far too heavy and can cause performance issues
|
||||||
this.toggleNormalizer(chat_bits.length || bits.length);
|
this.toggleNormalizer(chat_bits.length || bits.length);
|
||||||
|
|
||||||
if ( bits.length )
|
if ( bits.length )
|
||||||
this.css_tweaks.set('colors', `body {${bits.join('\n')}}.channel-info-content .tw-accent-region,.channel-info-content .gocjHQ{${accent_bits.join('\n')}}`);
|
this.css_tweaks.set('colors', `body,body .tw-root--theme-light,body .tw-root--theme-dark {${bits.join('\n')}}.channel-info-content .tw-accent-region,.channel-info-content .gocjHQ{${accent_bits.join('\n')}}`);
|
||||||
else
|
else
|
||||||
this.css_tweaks.delete('colors');
|
this.css_tweaks.delete('colors');
|
||||||
}
|
}
|
||||||
|
|
8
src/utilities/data/user-bulk.gql
Normal file
8
src/utilities/data/user-bulk.gql
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
query FFZ_UserBulk($ids: [ID!], $logins: [String!]) {
|
||||||
|
users(ids: $ids, logins: $logins) {
|
||||||
|
id
|
||||||
|
login
|
||||||
|
displayName
|
||||||
|
profileImageURL(width: 50)
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,8 +26,15 @@ export function createTester(rules, filter_types, inverted = false, or = false,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Construct the test. If no test is returned, we skip this filter.
|
||||||
|
// This can happen depending on configuration rendering a method
|
||||||
|
// pointless.
|
||||||
|
const test = type.createTest(rule.data, filter_types, rebuild);
|
||||||
|
if ( ! test )
|
||||||
|
continue;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
tests.push(type.createTest(rule.data, filter_types, rebuild));
|
tests.push(test);
|
||||||
names.push(`f${i}`);
|
names.push(`f${i}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ export default class TwitchData extends Module {
|
||||||
|
|
||||||
this.inject('site.apollo');
|
this.inject('site.apollo');
|
||||||
|
|
||||||
|
this._waiting_user_ids = new Map;
|
||||||
|
this._waiting_user_logins = new Map;
|
||||||
|
|
||||||
this._waiting_stream_ids = new Map;
|
this._waiting_stream_ids = new Map;
|
||||||
this._waiting_stream_logins = new Map;
|
this._waiting_stream_logins = new Map;
|
||||||
|
|
||||||
|
@ -268,6 +271,130 @@ export default class TwitchData extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch basic information on a user from Twitch. This is automatically batched
|
||||||
|
* for performance, but not directly cached. Either an id or login must be provided.
|
||||||
|
*
|
||||||
|
* @param {Number|String} [id] The ID of the channel
|
||||||
|
* @param {String} [login] The username of the channel
|
||||||
|
*
|
||||||
|
* @returns {Promise} A basic user object.
|
||||||
|
*/
|
||||||
|
getUserBasic(id, login) {
|
||||||
|
return new Promise((s, f) => {
|
||||||
|
if ( id ) {
|
||||||
|
if ( this._waiting_user_ids.has(id) )
|
||||||
|
this._waiting_user_ids.get(id).push([s,f]);
|
||||||
|
else
|
||||||
|
this._waiting_user_ids.set(id, [[s,f]]);
|
||||||
|
} else if ( login ) {
|
||||||
|
if ( this._waiting_user_logins.has(login) )
|
||||||
|
this._waiting_user_logins.get(login).push([s,f]);
|
||||||
|
else
|
||||||
|
this._waiting_user_logins.set(login, [[s,f]]);
|
||||||
|
} else
|
||||||
|
f('id and login cannot both be null');
|
||||||
|
|
||||||
|
if ( ! this._loading_users )
|
||||||
|
this._loadUsers();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async _loadUsers() {
|
||||||
|
if ( this._loading_users )
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._loading_users = true;
|
||||||
|
|
||||||
|
// Get the first 50... things.
|
||||||
|
const ids = [...this._waiting_user_ids.keys()].slice(0, 50),
|
||||||
|
remaining = 50 - ids.length,
|
||||||
|
logins = remaining > 0 ? [...this._waiting_user_logins.keys()].slice(0, remaining) : [];
|
||||||
|
|
||||||
|
let nodes;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await this.queryApollo({
|
||||||
|
query: await import(/* webpackChunkName: 'queries' */ './data/user-bulk.gql'),
|
||||||
|
variables: {
|
||||||
|
ids: ids.length ? ids : null,
|
||||||
|
logins: logins.length ? logins : null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
nodes = get('data.users', data);
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
for(const id of ids) {
|
||||||
|
const promises = this._waiting_user_ids.get(id);
|
||||||
|
this._waiting_user_ids.delete(id);
|
||||||
|
|
||||||
|
for(const pair of promises)
|
||||||
|
pair[1](err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const login of logins) {
|
||||||
|
const promises = this._waiting_user_logins.get(login);
|
||||||
|
this._waiting_user_logins.delete(login);
|
||||||
|
|
||||||
|
for(const pair of promises)
|
||||||
|
pair[1](err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id_set = new Set(ids),
|
||||||
|
login_set = new Set(logins);
|
||||||
|
|
||||||
|
if ( Array.isArray(nodes) )
|
||||||
|
for(const node of nodes) {
|
||||||
|
if ( ! node || ! node.id )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
id_set.delete(node.id);
|
||||||
|
login_set.delete(node.login);
|
||||||
|
|
||||||
|
let promises = this._waiting_user_ids.get(node.id);
|
||||||
|
if ( promises ) {
|
||||||
|
this._waiting_user_ids.delete(node.id);
|
||||||
|
for(const pair of promises)
|
||||||
|
pair[0](node);
|
||||||
|
}
|
||||||
|
|
||||||
|
promises = this._waiting_user_logins.get(node.login);
|
||||||
|
if ( promises ) {
|
||||||
|
this._waiting_user_logins.delete(node.login);
|
||||||
|
for(const pair of promises)
|
||||||
|
pair[0](node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const id of id_set) {
|
||||||
|
const promises = this._waiting_user_ids.get(id);
|
||||||
|
if ( promises ) {
|
||||||
|
this._waiting_user_ids.delete(id);
|
||||||
|
for(const pair of promises)
|
||||||
|
pair[0](null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const login of login_set) {
|
||||||
|
const promises = this._waiting_user_logins.get(login);
|
||||||
|
if ( promises ) {
|
||||||
|
this._waiting_user_logins.delete(login);
|
||||||
|
for(const pair of promises)
|
||||||
|
pair[0](null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._loading_users = false;
|
||||||
|
|
||||||
|
if ( this._waiting_user_ids.size || this._waiting_user_logins.size )
|
||||||
|
this._loadUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// Broadcast ID
|
// Broadcast ID
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
&--size-1 { width: 1rem }
|
||||||
|
&--size-105 { width: 1.5rem }
|
||||||
&--size-2 { width: 2rem }
|
&--size-2 { width: 2rem }
|
||||||
&--size-3 { width: 3rem }
|
&--size-3 { width: 3rem }
|
||||||
&--size-4 { width: 4rem }
|
&--size-4 { width: 4rem }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue