mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-02 16:08:31 +00:00
4.20.7
* Changed: Start fetching FFZ badges based on user ID rather than user login, for both data savings and resilience against name changes. * Changed: Implement a hot path for the Supporter badge (which is now applied to over 20,000 users) to reduce resource usage, notably RAM. * API Changed: Update to a newer method of getting an APIv2 authentication token that doesn't require a socket server connection.
This commit is contained in:
parent
bc1ca88a1e
commit
22fd300b28
4 changed files with 112 additions and 12 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.20.6",
|
"version": "4.20.7",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -169,6 +169,13 @@ export default class Badges extends Module {
|
||||||
this.inject('experiments');
|
this.inject('experiments');
|
||||||
|
|
||||||
this.style = new ManagedStyle('badges');
|
this.style = new ManagedStyle('badges');
|
||||||
|
|
||||||
|
// Special data structure for supporters to greatly reduce
|
||||||
|
// memory usage and speed things up for people who only have
|
||||||
|
// a supporter badge.
|
||||||
|
this.supporter_id = null;
|
||||||
|
this.supporters = new Set;
|
||||||
|
|
||||||
this.badges = {};
|
this.badges = {};
|
||||||
this.twitch_badges = {};
|
this.twitch_badges = {};
|
||||||
|
|
||||||
|
@ -646,8 +653,13 @@ export default class Badges extends Module {
|
||||||
global_user = this.parent.getUser(user_id, user_login, true),
|
global_user = this.parent.getUser(user_id, user_login, true),
|
||||||
room_user = room && room.getUser(user_id, user_login, true);
|
room_user = room && room.getUser(user_id, user_login, true);
|
||||||
|
|
||||||
return (global_user ? global_user.badges._cache : []).concat(
|
const out = (global_user ? global_user.badges._cache : []).concat(
|
||||||
room_user ? room_user.badges._cache : []);
|
room_user ? room_user.badges._cache : []);
|
||||||
|
|
||||||
|
if ( this.supporter_id && this.supporters.has(`${user_id}`) )
|
||||||
|
out.push({id: this.supporter_id});
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -656,11 +668,11 @@ export default class Badges extends Module {
|
||||||
|
|
||||||
if ( this.experiments.getAssignment('api_load') && tries < 1 )
|
if ( this.experiments.getAssignment('api_load') && tries < 1 )
|
||||||
try {
|
try {
|
||||||
fetch(`${NEW_API}/v1/badges`).catch(() => {});
|
fetch(`${NEW_API}/v2/badges`).catch(() => {});
|
||||||
} catch(err) { /* do nothing */ }
|
} catch(err) { /* do nothing */ }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await fetch(`${API_SERVER}/v1/badges`);
|
response = await fetch(`${API_SERVER}/v1/badges/ids`);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
tries++;
|
tries++;
|
||||||
if ( tries < 10 )
|
if ( tries < 10 )
|
||||||
|
@ -694,13 +706,21 @@ export default class Badges extends Module {
|
||||||
if ( has(data.users, badge_id) ) {
|
if ( has(data.users, badge_id) ) {
|
||||||
const badge = this.badges[badge_id];
|
const badge = this.badges[badge_id];
|
||||||
let c = 0;
|
let c = 0;
|
||||||
for(const user_login of data.users[badge_id]) {
|
|
||||||
const user = this.parent.getUser(undefined, user_login);
|
if ( badge?.name === 'supporter' ) {
|
||||||
if ( user.addBadge('ffz-global', badge_id) ) {
|
this.supporter_id = badge_id;
|
||||||
c++;
|
for(const user_id of data.users[badge_id])
|
||||||
users++;
|
this.supporters.add(`${user_id}`);
|
||||||
|
|
||||||
|
c = this.supporters.size;
|
||||||
|
} else
|
||||||
|
for(const user_id of data.users[badge_id]) {
|
||||||
|
const user = this.parent.getUser(user_id, undefined);
|
||||||
|
if ( user.addBadge('ffz-global', badge_id) ) {
|
||||||
|
c++;
|
||||||
|
users++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( c > 0 )
|
if ( c > 0 )
|
||||||
this.log.info(`Added "${badge ? badge.name : `#${badge_id}`}" to ${c} users.`);
|
this.log.info(`Added "${badge ? badge.name : `#${badge_id}`}" to ${c} users.`);
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
.ffz--meta-tray {
|
||||||
|
& > :first-child > :first-child {
|
||||||
|
display: none !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
import {DEBUG, WS_CLUSTERS} from 'utilities/constants';
|
import {DEBUG, WS_CLUSTERS} from 'utilities/constants';
|
||||||
|
import { on } from 'utilities/dom';
|
||||||
|
|
||||||
|
|
||||||
export const State = {
|
export const State = {
|
||||||
|
@ -140,7 +141,80 @@ export default class SocketClient extends Module {
|
||||||
return new Promise((s, f) => {
|
return new Promise((s, f) => {
|
||||||
this._token_waiters.push([s, f]);
|
this._token_waiters.push([s, f]);
|
||||||
|
|
||||||
this.call('get_api_token').then(token => {
|
let done = false, timer = null;
|
||||||
|
|
||||||
|
const fail = err => {
|
||||||
|
if ( done )
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearTimeout(timer);
|
||||||
|
done = true;
|
||||||
|
this.log.error('Unable to get API token.', err);
|
||||||
|
const waiters = this._token_waiters;
|
||||||
|
this._token_waiters = null;
|
||||||
|
|
||||||
|
for(const pair of waiters)
|
||||||
|
pair[1](err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = this.resolve('site')?.getUser?.();
|
||||||
|
if ( ! user || ! user.id )
|
||||||
|
return fail(new Error('Unable to get current user or not logged in.'));
|
||||||
|
|
||||||
|
const es = new EventSource(`https://api-test.frankerfacez.com/auth/ext_verify/${user.id}`);
|
||||||
|
|
||||||
|
on(es, 'challenge', event => {
|
||||||
|
const conn = this.resolve('site.chat')?.ChatService?.first?.client?.connection;
|
||||||
|
if ( conn && conn.send )
|
||||||
|
conn.send(`PRIVMSG #frankerfacezauthorizer :AUTH ${event.data}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
on(es, 'token', event => {
|
||||||
|
if ( done )
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearTimeout(timer);
|
||||||
|
|
||||||
|
let token = null;
|
||||||
|
try {
|
||||||
|
token = JSON.parse(event.data);
|
||||||
|
} catch(err) {
|
||||||
|
fail(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! token || ! token.token ) {
|
||||||
|
fail(new Error('Received empty token from server.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
token.expires = (new Date(token.expires)).getTime();
|
||||||
|
this._cached_token = token;
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
|
||||||
|
const waiters = this._token_waiters;
|
||||||
|
this._token_waiters = null;
|
||||||
|
|
||||||
|
for(const pair of waiters)
|
||||||
|
pair[0](token);
|
||||||
|
});
|
||||||
|
|
||||||
|
on(es, 'error', err => {
|
||||||
|
fail(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
on(es, 'close', () => {
|
||||||
|
es.close();
|
||||||
|
if ( ! done )
|
||||||
|
fail(new Error('Connection closed unexpectedly.'));
|
||||||
|
});
|
||||||
|
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fail(new Error('timeout'));
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
/*this.call('get_api_token').then(token => {
|
||||||
token.expires = (new Date(token.expires)).getTime();
|
token.expires = (new Date(token.expires)).getTime();
|
||||||
this._cached_token = token;
|
this._cached_token = token;
|
||||||
|
|
||||||
|
@ -157,7 +231,7 @@ export default class SocketClient extends Module {
|
||||||
|
|
||||||
for(const pair of waiters)
|
for(const pair of waiters)
|
||||||
pair[1](err);
|
pair[1](err);
|
||||||
});
|
});*/
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue