1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-07-05 18:48:31 +00:00

Start using SourcedSet for emoticon sets so that, in the future, special events, featured channels, etc. can add and remove emote sets without worrying about reference counting or anything like that. Also implement the method to get your Twitch Inventory emote sets.

This commit is contained in:
SirStendec 2017-11-15 21:59:13 -05:00
parent bd518aea01
commit 3607159929
5 changed files with 172 additions and 33 deletions

View file

@ -6,8 +6,8 @@
import Module from 'utilities/module'; import Module from 'utilities/module';
import {ManagedStyle} from 'utilities/dom'; import {ManagedStyle} from 'utilities/dom';
import {has, timeout} from 'utilities/object'; import {has, timeout, SourcedSet} from 'utilities/object';
import {API_SERVER} from 'utilities/constants'; import {CLIENT_ID, API_SERVER} from 'utilities/constants';
const MODIFIERS = { const MODIFIERS = {
@ -61,13 +61,16 @@ export default class Emotes extends Module {
this.__twitch_emote_to_set = new Map; this.__twitch_emote_to_set = new Map;
this.__twitch_set_to_channel = new Map; this.__twitch_set_to_channel = new Map;
this.default_sets = new Set; this.default_sets = new SourcedSet;
this.global_sets = new Set; this.global_sets = new SourcedSet;
this.emote_sets = {}; this.emote_sets = {};
} }
onEnable() { onEnable() {
// Just in case there's a weird load order going on.
this.on('site:enabled', this.refresh_twitch_inventory);
this.style = new ManagedStyle('emotes'); this.style = new ManagedStyle('emotes');
if ( Object.keys(this.emote_sets).length ) { if ( Object.keys(this.emote_sets).length ) {
@ -96,9 +99,9 @@ export default class Emotes extends Module {
const room = this.parent.getRoom(room_id, room_login, true), const room = this.parent.getRoom(room_id, room_login, true),
user = this.parent.getUser(user_id, user_login, true); user = this.parent.getUser(user_id, user_login, true);
return (user ? user.emote_sets : []).concat( return (user ? user.emote_sets._cache : []).concat(
room ? room.emote_sets : [], room ? room.emote_sets._cache : [],
Array.from(this.default_sets) this.default_sets._cache
); );
} }
@ -136,12 +139,11 @@ export default class Emotes extends Module {
const sets = data.sets || {}; const sets = data.sets || {};
for(const set_id of data.default_sets) this.default_sets.extend('ffz-global', ...data.default_sets);
this.default_sets.add(set_id);
for(const set_id in sets) for(const set_id in sets)
if ( has(sets, set_id) ) { if ( has(sets, set_id) ) {
this.global_sets.add(set_id); this.global_sets.push('ffz-global', set_id);
this.load_set_data(set_id, sets[set_id]); this.load_set_data(set_id, sets[set_id]);
} }
@ -160,8 +162,7 @@ export default class Emotes extends Module {
const user = this.parent.getUser(undefined, login), const user = this.parent.getUser(undefined, login),
sets = user.emote_sets; sets = user.emote_sets;
if ( sets.indexOf(set_id) === -1 ) sets.push('ffz-global', set_id);
sets.push(set_id);
} }
this.log.info(`Added "${emote_set ? emote_set.title : set_id}" emote set to ${users.length} users.`); this.log.info(`Added "${emote_set ? emote_set.title : set_id}" emote set to ${users.length} users.`);
@ -279,8 +280,27 @@ export default class Emotes extends Module {
// Twitch Data Lookup // Twitch Data Lookup
// ======================================================================== // ========================================================================
refresh_twitch_inventory() { async refresh_twitch_inventory() {
this.log.debug('Unimplemented: refresh_twitch_inventory'); const user = this.resolve('site').getUser();
if ( ! user )
return;
let data;
try {
data = await fetch('https://api.twitch.tv/v5/inventory/emoticons', {
headers: {
'Client-ID': CLIENT_ID,
'Authorization': `OAuth ${user.authToken}`
}
}).then(r => r.json());
} catch(err) {
this.log.error('Error loading Twitch inventory.', err);
return;
}
this.twitch_inventory_sets = data.emoticon_sets ? Object.keys(data.emoticon_sets) : [];
this.log.info('Twitch Inventory Sets:', this.twitch_inventory_sets);
} }

View file

@ -9,7 +9,7 @@ const WEBKIT = IS_WEBKIT ? '-webkit-' : '';
import Module from 'utilities/module'; import Module from 'utilities/module';
import {createElement, ManagedStyle} from 'utilities/dom'; import {createElement, ManagedStyle} from 'utilities/dom';
import {timeout, has} from 'utilities/object'; import {timeout, has, SourcedSet} from 'utilities/object';
import Badges from './badges'; import Badges from './badges';
import Emotes from './emotes'; import Emotes from './emotes';
@ -283,7 +283,7 @@ export default class Chat extends Module {
return null; return null;
else else
user = {id, login, badges: [], emote_sets: []}; user = {id, login, badges: [], emote_sets: new SourcedSet};
if ( id && id !== user.id ) { if ( id && id !== user.id ) {
// If the ID isn't what we expected, something is very wrong here. // If the ID isn't what we expected, something is very wrong here.

View file

@ -8,7 +8,7 @@ import {API_SERVER, IS_WEBKIT} from 'utilities/constants';
import {EventEmitter} from 'utilities/events'; import {EventEmitter} from 'utilities/events';
import {createElement as e, ManagedStyle} from 'utilities/dom'; import {createElement as e, ManagedStyle} from 'utilities/dom';
import {has} from 'utilities/object'; import {has, SourcedSet} from 'utilities/object';
const WEBKIT = IS_WEBKIT ? '-webkit-' : ''; const WEBKIT = IS_WEBKIT ? '-webkit-' : '';
@ -20,42 +20,71 @@ export default class Room extends EventEmitter {
this._destroy_timer = null; this._destroy_timer = null;
this.manager = manager; this.manager = manager;
this.id = id; this._id = id;
this.login = login; this.login = login;
if ( login )
this.manager.rooms[login] = this;
if ( id ) if ( id )
this.manager.room_ids[id] = this; this.manager.room_ids[id] = this;
this.refs = new Set; this.refs = new Set;
this.style = new ManagedStyle(`room--${login}`); this.style = new ManagedStyle(`room--${login}`);
this.emote_sets = []; this.emote_sets = new SourcedSet;
this.users = []; this.users = [];
this.user_ids = []; this.user_ids = [];
if ( this.login ) { this.manager.emit(':room-add', this);
this.manager.socket.subscribe(`room.${login}`);
this.load_data(); this.load_data();
} }
}
destroy() { destroy() {
clearTimeout(this._destroy_timer); clearTimeout(this._destroy_timer);
this._destroy_timer = null; this._destroy_timer = null;
this.destroyed = true; this.destroyed = true;
this.manager.socket.unsubscribe(`room.${this.login}`); this.manager.emit(':room-remove', this);
this.style.destroy(); this.style.destroy();
if ( this._login ) {
if ( this.manager.rooms[this._login] === this )
this.manager.rooms[this._login] = null;
this.manager.socket.unsubscribe(`room.${this.login}`);
}
if ( this.manager.room_ids[this.id] === this ) if ( this.manager.room_ids[this.id] === this )
this.manager.room_ids[this.id] = null; this.manager.room_ids[this.id] = null;
}
if ( this.manager.rooms[this.login] === this )
this.manager.rooms[this.login] = null; get id() {
return this._id;
}
get login() {
return this._login;
}
set login(val) {
if ( this._login === val )
return;
if ( this._login ) {
if ( this.manager.rooms[this._login] === this )
this.manager.rooms[this._login] = null;
this.manager.socket.unsubscribe(`room.${this.login}`);
}
this._login = val;
if ( ! val )
return;
this.manager.socket.subscribe(`room.${val}`);
this.manager.emit(':room-update-login', this, val);
} }
@ -69,7 +98,7 @@ export default class Room extends EventEmitter {
let response, data; let response, data;
try { try {
response = await fetch(`${API_SERVER}/v1/room/${this.login}`); response = await fetch(`${API_SERVER}/v1/room/${this.id ? `id/${this.id}` : this.login}`);
} catch(err) { } catch(err) {
tries++; tries++;
if ( tries < 10 ) if ( tries < 10 )
@ -89,9 +118,26 @@ export default class Room extends EventEmitter {
return false; return false;
} }
const d = this.data = data.room; const d = data.room,
if ( d.set && this.emote_sets.indexOf(d) === -1 ) id = '' + d.twitch_id;
this.emote_sets.push(d.set);
if ( ! this._id ) {
this._id = id;
this.manager.room_ids[id] = this;
} else if ( this._id !== id ) {
this.manager.log.warn(`Received data for ${this.id}:${this.login} with the wrong ID: ${id}`);
return false;
}
this.login = d.id;
this.data = d;
if ( d.set )
this.emote_sets.set('main', d.set);
else
this.emote_sets.delete('main');
if ( data.sets ) if ( data.sets )
for(const set_id in data.sets) for(const set_id in data.sets)

View file

@ -3,6 +3,7 @@
export const DEBUG = localStorage.ffzDebugMode === 'true' && document.body.classList.contains('ffz-dev'); export const DEBUG = localStorage.ffzDebugMode === 'true' && document.body.classList.contains('ffz-dev');
export const SERVER = DEBUG ? '//localhost:8000' : 'https://cdn.frankerfacez.com'; export const SERVER = DEBUG ? '//localhost:8000' : 'https://cdn.frankerfacez.com';
export const CLIENT_ID = 'a3bc9znoz6vi8ozsoca0inlcr4fcvkl';
export const API_SERVER = '//api.frankerfacez.com'; export const API_SERVER = '//api.frankerfacez.com';
export const WS_CLUSTERS = { export const WS_CLUSTERS = {

View file

@ -165,3 +165,75 @@ export function maybe_call(fn, ctx, ...args) {
return fn; return fn;
} }
export class SourcedSet {
constructor() {
this._cache = [];
}
_rebuild() {
if ( ! this._sources )
return;
this._cache = [];
for(const items of this._sources.values())
for(const i of items)
if ( ! this._cache.includes(i) )
this._cache.push(i);
}
get(key) { return this._sources && this._sources.get(key) }
has(key) { return this._sources ? this._sources.has(key) : false }
delete(key) {
if ( this._sources && this._sources.has(key) ) {
this._sources.delete(key);
this._rebuild();
}
}
extend(key, ...items) {
if ( ! this._sources )
this._sources = new Map;
const had = this.has(key);
this._sources.set(key, [false, items]);
if ( had )
this._rebuild();
else
for(const i of items)
if ( ! this._cache.includes(i) )
this._cache.push(i);
}
set(key, val) {
if ( ! this._sources )
this._sources = new Map;
const had = this.has(key);
this._sources.set(key, [val]);
if ( had )
this._rebuild();
else if ( ! this._cache.includes(val) )
this._cache.push(val);
}
push(key, val) {
if ( ! this._sources )
return this.set(key, val);
const old_val = this._sources.get(key);
if ( old_val === undefined )
return this.set(key, val);
else if ( old_val.includes(val) )
return;
old_val.push(val);
if ( ! this._cache.includes(val) )
this._cache.push(val);
}
}