1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 15:27:43 +00:00
* 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:
SirStendec 2021-05-07 18:22:55 -04:00
parent 5f0d4b2bfe
commit c286e6cf93
9 changed files with 173 additions and 22 deletions

View file

@ -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",

View file

@ -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.'
} }
}); });

View file

@ -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();

View file

@ -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);

View file

@ -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');
} }

View file

@ -0,0 +1,8 @@
query FFZ_UserBulk($ids: [ID!], $logins: [String!]) {
users(ids: $ids, logins: $logins) {
id
login
displayName
profileImageURL(width: 50)
}
}

View file

@ -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}`);
} }

View file

@ -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
// ======================================================================== // ========================================================================

View file

@ -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 }