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",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.22.2",
|
||||
"version": "4.22.3",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
|
|
|
@ -873,7 +873,7 @@ export default class Chat extends Module {
|
|||
component: 'setting-text-box',
|
||||
type: 'number',
|
||||
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 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
|
||||
v-on-clickaway="closeUnlisted"
|
||||
|
@ -128,6 +128,10 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
visible_unlisted() {
|
||||
return this.visible_addons.length !== this.sorted_addons.length
|
||||
},
|
||||
|
||||
visible_addons() {
|
||||
return this.sorted_addons.filter(addon => this.shouldShow(addon));
|
||||
},
|
||||
|
@ -180,10 +184,8 @@ export default {
|
|||
|
||||
if ( value && value.length )
|
||||
for(const addon of this.item.getAddons())
|
||||
if ( addon.unlisted && addon.id === value ) {
|
||||
this.unlisted.push(value);
|
||||
break;
|
||||
}
|
||||
if ( addon.unlisted && (addon.id === value || (addon.short_name && addon.short_name.toLowerCase() === value) || (addon.name && addon.name.toLowerCase() === value)) )
|
||||
this.unlisted.push(addon.id);
|
||||
|
||||
this.$refs.unlisted.value = '';
|
||||
this.closeUnlisted();
|
||||
|
|
|
@ -267,23 +267,28 @@ export default {
|
|||
if ( addons )
|
||||
for(const [key, addon] of Object.entries(addons)) {
|
||||
const enabled = addon_module.isAddonEnabled(key),
|
||||
copy = {
|
||||
key,
|
||||
enabled,
|
||||
icon: addon.icon,
|
||||
name: addon.name,
|
||||
name_i18n: addon.name_i18n,
|
||||
updated: addon.updated,
|
||||
settings: addon.settings,
|
||||
version: addon.version
|
||||
};
|
||||
is_new = addon.created && addon.created >= week_ago,
|
||||
is_updated = enabled && addon.updated && addon.updated >= week_ago;
|
||||
|
||||
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);
|
||||
|
||||
if ( addon.updated && addon.updated >= week_ago && enabled ) {
|
||||
if ( is_updated )
|
||||
out.push(copy);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
// 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++;
|
||||
tests.push(type.createTest(rule.data, filter_types, rebuild));
|
||||
tests.push(test);
|
||||
names.push(`f${i}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@ export default class TwitchData extends Module {
|
|||
|
||||
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_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
|
||||
// ========================================================================
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
|
||||
&--size-1 { width: 1rem }
|
||||
&--size-105 { width: 1.5rem }
|
||||
&--size-2 { width: 2rem }
|
||||
&--size-3 { width: 3rem }
|
||||
&--size-4 { width: 4rem }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue