2017-11-13 01:23:39 -05:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
// Emote Handling and Default Provider
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
import Module from 'utilities/module';
|
|
|
|
import {ManagedStyle} from 'utilities/dom';
|
2019-01-15 16:14:21 -05:00
|
|
|
import {get, has, timeout, SourcedSet} from 'utilities/object';
|
2019-10-28 14:56:55 -04:00
|
|
|
import {NEW_API, API_SERVER, IS_OSX, EmoteTypes, TWITCH_GLOBAL_SETS, TWITCH_POINTS_SETS, TWITCH_PRIME_SETS} from 'utilities/constants';
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-01-15 16:14:21 -05:00
|
|
|
import GET_EMOTE from './emote_info.gql';
|
2019-10-28 14:56:55 -04:00
|
|
|
import GET_EMOTE_SET from './emote_set_info.gql';
|
2019-01-15 16:14:21 -05:00
|
|
|
|
2018-04-09 19:57:05 -04:00
|
|
|
const MOD_KEY = IS_OSX ? 'metaKey' : 'ctrlKey';
|
2017-11-13 01:23:39 -05:00
|
|
|
|
|
|
|
const MODIFIERS = {
|
|
|
|
59847: {
|
|
|
|
modifier_offset: '0 15px 15px 0',
|
|
|
|
modifier: true
|
|
|
|
},
|
|
|
|
|
|
|
|
70852: {
|
|
|
|
modifier: true,
|
|
|
|
modifier_offset: '0 5px 20px 0',
|
|
|
|
extra_width: 5,
|
|
|
|
shrink_to_fit: true
|
|
|
|
},
|
|
|
|
|
|
|
|
70854: {
|
|
|
|
modifier: true,
|
|
|
|
modifier_offset: '30px 0 0'
|
|
|
|
},
|
|
|
|
|
|
|
|
147049: {
|
|
|
|
modifier: true,
|
|
|
|
modifier_offset: '4px 1px 0 3px'
|
|
|
|
},
|
|
|
|
|
|
|
|
147011: {
|
|
|
|
modifier: true,
|
|
|
|
modifier_offset: '0'
|
|
|
|
},
|
|
|
|
|
|
|
|
70864: {
|
|
|
|
modifier: true,
|
|
|
|
modifier_offset: '0'
|
|
|
|
},
|
|
|
|
|
|
|
|
147038: {
|
|
|
|
modifier: true,
|
|
|
|
modifier_offset: '0'
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default class Emotes extends Module {
|
|
|
|
constructor(...args) {
|
|
|
|
super(...args);
|
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
this.EmoteTypes = EmoteTypes;
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
this.inject('socket');
|
2017-12-13 20:22:11 -05:00
|
|
|
this.inject('settings');
|
2018-04-12 02:29:43 -04:00
|
|
|
this.inject('experiments');
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 01:06:02 -04:00
|
|
|
this.twitch_inventory_sets = new Set; //(EXTRA_INVENTORY);
|
2019-12-12 18:44:19 -05:00
|
|
|
this.__twitch_emote_to_set = {};
|
|
|
|
this.__twitch_set_to_channel = {};
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2017-11-15 21:59:13 -05:00
|
|
|
this.default_sets = new SourcedSet;
|
|
|
|
this.global_sets = new SourcedSet;
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
this.providers = new Map;
|
|
|
|
|
|
|
|
this.providers.set('featured', {
|
|
|
|
name: 'Featured',
|
|
|
|
i18n_key: 'emote-menu.featured',
|
|
|
|
sort_key: 75
|
|
|
|
})
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
this.emote_sets = {};
|
2017-11-22 20:21:01 -05:00
|
|
|
this._set_refs = {};
|
|
|
|
this._set_timers = {};
|
2017-12-13 20:22:11 -05:00
|
|
|
|
|
|
|
this.settings.add('chat.fix-bad-emotes', {
|
|
|
|
default: true,
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Appearance >> Emotes',
|
|
|
|
title: 'Fix Bad Twitch Global Emotes',
|
|
|
|
description: 'Clean up the images for bad Twitch global emotes, removing white borders and solid backgrounds.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
2018-04-09 19:57:05 -04:00
|
|
|
|
2019-01-18 19:07:57 -05:00
|
|
|
this.settings.add('chat.click-emotes', {
|
|
|
|
default: true,
|
|
|
|
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Behavior >> General',
|
|
|
|
title: 'Open emote information pages by Shift-Clicking them.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.settings.add('chat.sub-emotes', {
|
|
|
|
default: true,
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Behavior >> General',
|
|
|
|
title: 'Open Twitch subscription pages by Shift-Clicking emotes when relevant.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.settings.add('chat.emote-dialogs', {
|
|
|
|
default: true,
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Behavior >> General',
|
|
|
|
title: 'Open emote information cards for Twitch emotes by clicking them.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
2018-04-09 19:57:05 -04:00
|
|
|
|
|
|
|
// Because this may be used elsewhere.
|
|
|
|
this.handleClick = this.handleClick.bind(this);
|
2017-11-13 01:23:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
onEnable() {
|
|
|
|
this.style = new ManagedStyle('emotes');
|
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
// Fix numeric Twitch favorite IDs.
|
|
|
|
const favs = this.getFavorites('twitch');
|
|
|
|
let changed = false;
|
|
|
|
for(let i=0; i < favs.length; i++) {
|
|
|
|
if ( typeof favs[i] === 'number' ) {
|
|
|
|
changed = true;
|
|
|
|
favs[i] = `${favs[i]}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( changed )
|
|
|
|
this.setFavorites('twitch', favs);
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
if ( Object.keys(this.emote_sets).length ) {
|
|
|
|
this.log.info('Generating CSS for existing emote sets.');
|
|
|
|
for(const set_id in this.emote_sets)
|
|
|
|
if ( has(this.emote_sets, set_id) ) {
|
|
|
|
const emote_set = this.emote_sets[set_id];
|
|
|
|
if ( emote_set && emote_set.pending_css ) {
|
|
|
|
this.style.set(`es--${set_id}`, emote_set.pending_css + (emote_set.css || ''));
|
|
|
|
emote_set.pending_css = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
this.socket.on(':command:follow_sets', this.updateFollowSets, this);
|
|
|
|
|
2017-11-16 15:54:58 -05:00
|
|
|
this.loadGlobalSets();
|
2017-11-13 01:23:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
// ========================================================================
|
|
|
|
// Featured Sets
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
updateFollowSets(data) {
|
|
|
|
for(const room_login in data)
|
|
|
|
if ( has(data, room_login) ) {
|
2018-04-13 13:36:05 -04:00
|
|
|
const room = this.parent.getRoom(null, room_login, true);
|
|
|
|
if ( ! room || room.destroyed )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const new_sets = data[room_login] || [],
|
2018-04-06 21:12:12 -04:00
|
|
|
emote_sets = room.emote_sets,
|
2018-04-13 13:36:05 -04:00
|
|
|
providers = emote_sets && emote_sets._sources;
|
2018-04-06 21:12:12 -04:00
|
|
|
|
|
|
|
if ( providers && providers.has('featured') )
|
2018-04-12 02:29:43 -04:00
|
|
|
for(const item of providers.get('featured')) {
|
|
|
|
const idx = new_sets.indexOf(item);
|
|
|
|
if ( idx === -1 )
|
2018-04-06 21:12:12 -04:00
|
|
|
room.removeSet('featured', item);
|
2018-04-12 02:29:43 -04:00
|
|
|
else
|
|
|
|
new_sets.splice(idx, 1);
|
|
|
|
}
|
2018-04-06 21:12:12 -04:00
|
|
|
|
|
|
|
for(const set_id of new_sets) {
|
|
|
|
room.addSet('featured', set_id);
|
|
|
|
|
|
|
|
if ( ! this.emote_sets[set_id] )
|
|
|
|
this.loadSet(set_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-09 19:57:05 -04:00
|
|
|
// ========================================================================
|
|
|
|
// Favorite Checking
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
toggleFavorite(source, id, value = null) {
|
|
|
|
const key = `favorite-emotes.${source}`,
|
|
|
|
p = this.settings.provider,
|
|
|
|
favorites = p.get(key) || [],
|
|
|
|
|
|
|
|
idx = favorites.indexOf(id);
|
|
|
|
|
|
|
|
if ( value === null )
|
|
|
|
value = idx === -1;
|
|
|
|
|
|
|
|
if ( value && idx === -1 )
|
|
|
|
favorites.push(id);
|
|
|
|
else if ( ! value && idx !== -1 )
|
|
|
|
favorites.splice(idx, 1);
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( favorites.length )
|
|
|
|
p.set(key, favorites);
|
|
|
|
else
|
|
|
|
p.delete(key);
|
|
|
|
|
|
|
|
this.emit(':change-favorite', source, id, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
isFavorite(source, id) {
|
|
|
|
const favorites = this.settings.provider.get(`favorite-emotes.${source}`);
|
|
|
|
return favorites && favorites.includes(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
getFavorites(source) {
|
|
|
|
return this.settings.provider.get(`favorite-emotes.${source}`) || [];
|
|
|
|
}
|
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
setFavorites(source, favs) {
|
|
|
|
const key = `favorite-emotes.${source}`;
|
|
|
|
if ( ! Array.isArray(favs) || ! favs.length )
|
|
|
|
this.settings.provider.delete(key);
|
|
|
|
else
|
|
|
|
this.settings.provider.set(key, favs);
|
|
|
|
}
|
|
|
|
|
2018-04-09 19:57:05 -04:00
|
|
|
|
|
|
|
handleClick(event) {
|
|
|
|
const target = event.target,
|
|
|
|
ds = target && target.dataset;
|
|
|
|
|
|
|
|
if ( ! ds )
|
|
|
|
return;
|
|
|
|
|
2019-01-15 16:14:21 -05:00
|
|
|
const provider = ds.provider,
|
|
|
|
click_emote = this.parent.context.get('chat.click-emotes'),
|
|
|
|
click_sub = this.parent.context.get('chat.sub-emotes');
|
2018-04-09 19:57:05 -04:00
|
|
|
|
2019-01-15 16:14:21 -05:00
|
|
|
if ( event.shiftKey && (click_emote || click_sub) ) {
|
2018-04-11 17:05:31 -04:00
|
|
|
let url;
|
|
|
|
|
2019-01-15 16:14:21 -05:00
|
|
|
if ( provider === 'twitch' ) {
|
2018-04-11 17:05:31 -04:00
|
|
|
url = `https://twitchemotes.com/emotes/${ds.id}`;
|
|
|
|
|
2019-01-15 16:14:21 -05:00
|
|
|
if ( click_sub ) {
|
|
|
|
const apollo = this.resolve('site.apollo');
|
|
|
|
if ( apollo ) {
|
|
|
|
apollo.client.query({
|
|
|
|
query: GET_EMOTE,
|
|
|
|
variables: {
|
|
|
|
id: ds.id
|
|
|
|
}
|
|
|
|
}).then(result => {
|
|
|
|
const prod = get('data.emote.subscriptionProduct', result);
|
|
|
|
if ( prod && prod.state === 'ACTIVE' && prod.owner && prod.owner.login )
|
|
|
|
url = `https://www.twitch.tv/subs/${prod.owner.login}`;
|
|
|
|
else if ( ! click_emote )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( url ) {
|
|
|
|
const win = window.open();
|
|
|
|
if ( win ) {
|
|
|
|
win.opener = null;
|
|
|
|
win.location = url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if ( provider === 'ffz' ) {
|
2018-04-11 17:05:31 -04:00
|
|
|
const emote_set = this.emote_sets[ds.set],
|
|
|
|
emote = emote_set && emote_set.emotes[ds.id];
|
|
|
|
|
|
|
|
if ( ! emote )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( emote.click_url )
|
|
|
|
url = emote.click_url;
|
|
|
|
|
|
|
|
else if ( ! emote_set.source )
|
|
|
|
url = `https://www.frankerfacez.com/emoticons/${emote.id}`;
|
|
|
|
}
|
|
|
|
|
2019-01-15 16:14:21 -05:00
|
|
|
if ( ! click_emote )
|
|
|
|
return false;
|
|
|
|
|
2018-04-11 17:05:31 -04:00
|
|
|
if ( url ) {
|
|
|
|
const win = window.open();
|
2018-07-26 19:40:53 -04:00
|
|
|
if ( win ) {
|
|
|
|
win.opener = null;
|
|
|
|
win.location = url;
|
|
|
|
}
|
2018-04-11 17:05:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-04-09 19:57:05 -04:00
|
|
|
if ( event[MOD_KEY] ) {
|
|
|
|
// Favoriting Emotes
|
|
|
|
let source, id;
|
|
|
|
|
|
|
|
if ( provider === 'twitch' ) {
|
|
|
|
source = 'twitch';
|
2019-12-12 18:44:19 -05:00
|
|
|
id = ds.id;
|
2018-04-09 19:57:05 -04:00
|
|
|
|
|
|
|
} else if ( provider === 'ffz' ) {
|
|
|
|
const emote_set = this.emote_sets[ds.set],
|
|
|
|
emote = emote_set && emote_set.emotes[ds.id];
|
|
|
|
|
|
|
|
if ( ! emote )
|
|
|
|
return;
|
|
|
|
|
|
|
|
source = emote_set.source || 'ffz';
|
|
|
|
id = emote.id;
|
|
|
|
|
2018-04-12 20:30:00 -04:00
|
|
|
} else if ( provider === 'emoji' ) {
|
|
|
|
source = 'emoji';
|
|
|
|
id = ds.code;
|
|
|
|
|
2018-04-09 19:57:05 -04:00
|
|
|
} else
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.toggleFavorite(source, id);
|
|
|
|
const tt = target._ffz_tooltip$0;
|
|
|
|
if ( tt && tt.visible ) {
|
|
|
|
tt.hide();
|
|
|
|
setTimeout(() => document.contains(target) && tt.show(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2019-01-18 19:07:57 -05:00
|
|
|
|
|
|
|
if ( provider === 'twitch' && this.parent.context.get('chat.emote-dialogs') ) {
|
|
|
|
const fine = this.resolve('site.fine');
|
|
|
|
if ( ! fine )
|
|
|
|
return;
|
|
|
|
|
|
|
|
const chat = fine.searchParent(target, n => n.props && n.props.onEmoteClick);
|
|
|
|
if ( ! chat || ! chat.props || ! chat.props.message )
|
|
|
|
return;
|
|
|
|
|
|
|
|
const props = chat.props;
|
|
|
|
props.onEmoteClick({
|
|
|
|
channelID: props.channelID || '',
|
|
|
|
channelLogin: props.channelLogin || '',
|
|
|
|
emoteID: ds.id,
|
|
|
|
emoteCode: target.alt,
|
|
|
|
sourceID: 'chat',
|
|
|
|
referrerID: '',
|
|
|
|
initialTopOffset: target.getBoundingClientRect().bottom
|
|
|
|
});
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2018-04-09 19:57:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
// ========================================================================
|
|
|
|
// Access
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
getSetIDs(user_id, user_login, room_id, room_login) {
|
|
|
|
const room = this.parent.getRoom(room_id, room_login, true),
|
2017-12-13 17:35:20 -05:00
|
|
|
room_user = room && room.getUser(user_id, user_login, true),
|
2017-11-13 01:23:39 -05:00
|
|
|
user = this.parent.getUser(user_id, user_login, true);
|
|
|
|
|
2017-11-15 21:59:13 -05:00
|
|
|
return (user ? user.emote_sets._cache : []).concat(
|
2018-02-02 18:11:37 -05:00
|
|
|
room_user ? room_user.emote_sets._cache : [],
|
2017-11-15 21:59:13 -05:00
|
|
|
room ? room.emote_sets._cache : [],
|
|
|
|
this.default_sets._cache
|
2017-11-13 01:23:39 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
getSets(user_id, user_login, room_id, room_login) {
|
|
|
|
return this.getSetIDs(user_id, user_login, room_id, room_login)
|
|
|
|
.map(set_id => this.emote_sets[set_id]);
|
|
|
|
}
|
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
_withSources(out, seen, emote_sets) { // eslint-disable-line class-methods-use-this
|
|
|
|
if ( ! emote_sets._sources )
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(const [provider, data] of emote_sets._sources)
|
|
|
|
for(const item of data)
|
|
|
|
if ( ! seen.has(item) ) {
|
|
|
|
out.push([item, provider]);
|
|
|
|
seen.add(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
getRoomSetIDsWithSources(user_id, user_login, room_id, room_login) {
|
|
|
|
const room = this.parent.getRoom(room_id, room_login, true),
|
|
|
|
room_user = room && room.getUser(user_id, user_login, true);
|
|
|
|
|
|
|
|
if ( ! room )
|
|
|
|
return [];
|
|
|
|
|
|
|
|
const out = [], seen = new Set;
|
|
|
|
|
|
|
|
this._withSources(out, seen, room.emote_sets);
|
|
|
|
if ( room_user )
|
|
|
|
this._withSources(out, seen, room_user);
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
getRoomSetsWithSources(user_id, user_login, room_id, room_login) {
|
|
|
|
return this.getRoomSetIDsWithSources(user_id, user_login, room_id, room_login)
|
|
|
|
.map(([set_id, source]) => [this.emote_sets[set_id], source]);
|
|
|
|
}
|
|
|
|
|
2017-12-13 17:35:20 -05:00
|
|
|
getRoomSetIDs(user_id, user_login, room_id, room_login) {
|
|
|
|
const room = this.parent.getRoom(room_id, room_login, true),
|
|
|
|
room_user = room && room.getUser(user_id, user_login, true);
|
|
|
|
|
|
|
|
if ( ! room )
|
|
|
|
return [];
|
|
|
|
|
|
|
|
if ( ! room_user )
|
|
|
|
return room.emote_sets._cache;
|
|
|
|
|
|
|
|
return room_user.emote_sets._cache.concat(room.emote_sets._cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
getRoomSets(user_id, user_login, room_id, room_login) {
|
|
|
|
return this.getRoomSetIDs(user_id, user_login, room_id, room_login)
|
|
|
|
.map(set_id => this.emote_sets[set_id]);
|
|
|
|
}
|
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
getGlobalSetIDsWithSources(user_id, user_login) {
|
|
|
|
const user = this.parent.getUser(user_id, user_login, true),
|
|
|
|
out = [], seen = new Set;
|
|
|
|
|
|
|
|
this._withSources(out, seen, this.default_sets);
|
|
|
|
if ( user )
|
|
|
|
this._withSources(out, seen, user.emote_sets);
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
getGlobalSetsWithSources(user_id, user_login) {
|
|
|
|
return this.getGlobalSetIDsWithSources(user_id, user_login)
|
|
|
|
.map(([set_id, source]) => [this.emote_sets[set_id], source]);
|
|
|
|
}
|
|
|
|
|
2017-12-13 17:35:20 -05:00
|
|
|
getGlobalSetIDs(user_id, user_login) {
|
|
|
|
const user = this.parent.getUser(user_id, user_login, true);
|
|
|
|
if ( ! user )
|
|
|
|
return this.default_sets._cache;
|
|
|
|
|
|
|
|
return user.emote_sets._cache.concat(this.default_sets._cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
getGlobalSets(user_id, user_login) {
|
|
|
|
return this.getGlobalSetIDs(user_id, user_login)
|
|
|
|
.map(set_id => this.emote_sets[set_id]);
|
|
|
|
}
|
|
|
|
|
2017-11-22 15:39:38 -05:00
|
|
|
getEmotes(user_id, user_login, room_id, room_login) {
|
|
|
|
const emotes = {};
|
|
|
|
for(const emote_set of this.getSets(user_id, user_login, room_id, room_login))
|
|
|
|
if ( emote_set && emote_set.emotes )
|
|
|
|
for(const emote of Object.values(emote_set.emotes) )
|
|
|
|
if ( emote && ! has(emotes, emote.name) )
|
|
|
|
emotes[emote.name] = emote;
|
|
|
|
|
|
|
|
return emotes;
|
|
|
|
}
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
// ========================================================================
|
2017-11-22 20:21:01 -05:00
|
|
|
// Emote Set Ref Counting
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
addDefaultSet(provider, set_id, data) {
|
2018-04-06 21:12:12 -04:00
|
|
|
let changed = false;
|
2017-11-22 20:21:01 -05:00
|
|
|
if ( ! this.default_sets.sourceIncludes(provider, set_id) ) {
|
|
|
|
this.default_sets.push(provider, set_id);
|
|
|
|
this.refSet(set_id);
|
2018-04-06 21:12:12 -04:00
|
|
|
changed = true;
|
2017-11-22 20:21:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( data )
|
|
|
|
this.loadSetData(set_id, data);
|
2018-04-01 18:24:08 -04:00
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
if ( changed )
|
|
|
|
this.emit(':update-default-sets', provider, set_id, true);
|
2017-11-22 20:21:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
removeDefaultSet(provider, set_id) {
|
2018-04-06 21:12:12 -04:00
|
|
|
let changed = false;
|
2017-11-22 20:21:01 -05:00
|
|
|
if ( this.default_sets.sourceIncludes(provider, set_id) ) {
|
|
|
|
this.default_sets.remove(provider, set_id);
|
|
|
|
this.unrefSet(set_id);
|
2018-04-06 21:12:12 -04:00
|
|
|
changed = true;
|
2017-11-22 20:21:01 -05:00
|
|
|
}
|
2018-04-01 18:24:08 -04:00
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
if ( changed )
|
|
|
|
this.emit(':update-default-sets', provider, set_id, false);
|
2017-11-22 20:21:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
refSet(set_id) {
|
|
|
|
this._set_refs[set_id] = (this._set_refs[set_id] || 0) + 1;
|
|
|
|
if ( this._set_timers[set_id] ) {
|
|
|
|
clearTimeout(this._set_timers[set_id]);
|
|
|
|
this._set_timers[set_id] = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
unrefSet(set_id) {
|
|
|
|
const c = this._set_refs[set_id] = (this._set_refs[set_id] || 1) - 1;
|
|
|
|
if ( c <= 0 && ! this._set_timers[set_id] )
|
|
|
|
this._set_timers[set_id] = setTimeout(() => this.unloadSet(set_id), 5000);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========================================================================
|
|
|
|
// Emote Set Loading
|
2017-11-13 01:23:39 -05:00
|
|
|
// ========================================================================
|
|
|
|
|
2017-11-16 15:54:58 -05:00
|
|
|
async loadGlobalSets(tries = 0) {
|
2017-11-13 01:23:39 -05:00
|
|
|
let response, data;
|
2018-04-12 02:29:43 -04:00
|
|
|
|
|
|
|
if ( this.experiments.getAssignment('api_load') )
|
|
|
|
try {
|
|
|
|
fetch(`${NEW_API}/v1/set/global`).catch(() => {});
|
|
|
|
} catch(err) { /* do nothing */ }
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
try {
|
|
|
|
response = await fetch(`${API_SERVER}/v1/set/global`)
|
|
|
|
} catch(err) {
|
|
|
|
tries++;
|
|
|
|
if ( tries < 10 )
|
2017-11-16 15:54:58 -05:00
|
|
|
return setTimeout(() => this.loadGlobalSets(tries), 500 * tries);
|
2017-11-13 01:23:39 -05:00
|
|
|
|
|
|
|
this.log.error('Error loading global emote sets.', err);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! response.ok )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
data = await response.json();
|
|
|
|
} catch(err) {
|
|
|
|
this.log.error('Error parsing global emote data.', err);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const sets = data.sets || {};
|
|
|
|
|
2017-11-22 20:21:01 -05:00
|
|
|
for(const set_id of data.default_sets)
|
|
|
|
this.addDefaultSet('ffz-global', set_id);
|
2017-11-13 01:23:39 -05:00
|
|
|
|
|
|
|
for(const set_id in sets)
|
2017-11-22 20:21:01 -05:00
|
|
|
if ( has(sets, set_id) )
|
2017-11-16 15:54:58 -05:00
|
|
|
this.loadSetData(set_id, sets[set_id]);
|
2017-11-13 01:23:39 -05:00
|
|
|
|
|
|
|
if ( data.users )
|
2017-11-16 15:54:58 -05:00
|
|
|
this.loadSetUsers(data.users);
|
2018-04-12 20:30:00 -04:00
|
|
|
|
|
|
|
return true;
|
2017-11-13 01:23:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
async loadSet(set_id, suppress_log = false, tries = 0) {
|
|
|
|
let response, data;
|
2018-04-12 02:29:43 -04:00
|
|
|
|
|
|
|
if ( this.experiments.getAssignment('api_load') )
|
|
|
|
try {
|
|
|
|
fetch(`${NEW_API}/v1/set/${set_id}`).catch(() => {});
|
|
|
|
} catch(err) { /* do nothing */ }
|
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
try {
|
|
|
|
response = await fetch(`${API_SERVER}/v1/set/${set_id}`)
|
|
|
|
} catch(err) {
|
|
|
|
tries++;
|
|
|
|
if ( tries < 10 )
|
|
|
|
return setTimeout(() => this.loadGlobalSets(tries), 500 * tries);
|
|
|
|
|
|
|
|
this.log.error(`Error loading data for set "${set_id}".`, err);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! response.ok )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
data = await response.json();
|
|
|
|
} catch(err) {
|
|
|
|
this.log.error(`Error parsing data for set "${set_id}".`, err);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const set = data.set;
|
|
|
|
if ( set )
|
|
|
|
this.loadSetData(set.id, set, suppress_log);
|
|
|
|
|
|
|
|
if ( data.users )
|
|
|
|
this.loadSetUsers(data.users);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
loadSetUsers(data, suppress_log = false) {
|
2017-11-13 01:23:39 -05:00
|
|
|
for(const set_id in data)
|
|
|
|
if ( has(data, set_id) ) {
|
|
|
|
const emote_set = this.emote_sets[set_id],
|
|
|
|
users = data[set_id];
|
|
|
|
|
2017-11-22 20:21:01 -05:00
|
|
|
for(const login of users)
|
|
|
|
this.parent.getUser(undefined, login)
|
|
|
|
.addSet('ffz-global', set_id);
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
if ( ! suppress_log )
|
|
|
|
this.log.info(`Added "${emote_set ? emote_set.title : set_id}" emote set to ${users.length} users.`);
|
2017-11-13 01:23:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-02 18:11:37 -05:00
|
|
|
loadSetData(set_id, data, suppress_log = false) {
|
2017-11-13 01:23:39 -05:00
|
|
|
const old_set = this.emote_sets[set_id];
|
|
|
|
if ( ! data ) {
|
|
|
|
if ( old_set )
|
|
|
|
this.emote_sets[set_id] = null;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.emote_sets[set_id] = data;
|
|
|
|
|
|
|
|
let count = 0;
|
|
|
|
const ems = data.emotes || data.emoticons,
|
|
|
|
new_ems = data.emotes = {},
|
|
|
|
css = [];
|
|
|
|
|
2018-04-06 21:12:12 -04:00
|
|
|
data.id = set_id;
|
2017-11-13 01:23:39 -05:00
|
|
|
data.emoticons = undefined;
|
|
|
|
|
2018-04-09 19:57:05 -04:00
|
|
|
const bad_emotes = [];
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
for(const emote of ems) {
|
2018-04-09 19:57:05 -04:00
|
|
|
if ( ! emote.id || ! emote.name || ! emote.urls ) {
|
|
|
|
bad_emotes.push(emote);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
emote.set_id = set_id;
|
|
|
|
emote.srcSet = `${emote.urls[1]} 1x`;
|
|
|
|
if ( emote.urls[2] )
|
|
|
|
emote.srcSet += `, ${emote.urls[2]} 2x`;
|
|
|
|
if ( emote.urls[4] )
|
|
|
|
emote.srcSet += `, ${emote.urls[4]} 4x`;
|
|
|
|
|
|
|
|
emote.token = {
|
|
|
|
type: 'emote',
|
|
|
|
id: emote.id,
|
|
|
|
set: set_id,
|
|
|
|
provider: 'ffz',
|
|
|
|
src: emote.urls[1],
|
|
|
|
srcSet: emote.srcSet,
|
|
|
|
text: emote.hidden ? '???' : emote.name,
|
|
|
|
length: emote.name.length
|
|
|
|
};
|
|
|
|
|
|
|
|
if ( has(MODIFIERS, emote.id) )
|
|
|
|
Object.assign(emote, MODIFIERS[emote.id]);
|
|
|
|
|
|
|
|
const emote_css = this.generateEmoteCSS(emote);
|
|
|
|
if ( emote_css )
|
|
|
|
css.push(emote_css);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
new_ems[emote.id] = emote;
|
|
|
|
}
|
|
|
|
|
2018-04-09 19:57:05 -04:00
|
|
|
if ( bad_emotes.length )
|
|
|
|
this.log.warn(`Bad Emote Data for Set #${set_id}`, bad_emotes);
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
data.count = count;
|
|
|
|
|
|
|
|
if ( this.style && (css.length || data.css) )
|
|
|
|
this.style.set(`es--${set_id}`, css.join('') + (data.css || ''));
|
|
|
|
else if ( css.length )
|
|
|
|
data.pending_css = css.join('');
|
|
|
|
|
2018-02-02 18:11:37 -05:00
|
|
|
if ( ! suppress_log )
|
|
|
|
this.log.info(`Loaded emote set #${set_id}: ${data.title} (${count} emotes)`);
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
this.emit(':loaded', set_id, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-02 18:11:37 -05:00
|
|
|
unloadSet(set_id, force = false, suppress_log = false) {
|
2017-11-22 20:21:01 -05:00
|
|
|
const old_set = this.emote_sets[set_id],
|
|
|
|
count = this._set_refs[set_id] || 0;
|
|
|
|
|
|
|
|
if ( ! old_set )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( count > 0 ) {
|
|
|
|
if ( ! force )
|
|
|
|
return this.log.warn(`Attempted to unload emote set #${set_id} with ${count} users.`);
|
|
|
|
this.log.warn(`Unloading emote set ${set_id} with ${count} users.`);
|
|
|
|
}
|
|
|
|
|
2018-02-02 18:11:37 -05:00
|
|
|
if ( ! suppress_log )
|
|
|
|
this.log.info(`Unloaded emote set #${set_id}: ${old_set.title}`);
|
|
|
|
|
2017-11-22 20:21:01 -05:00
|
|
|
this.emit(':unloaded', set_id, old_set);
|
|
|
|
this.emote_sets[set_id] = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
// ========================================================================
|
|
|
|
// Emote CSS
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
generateEmoteCSS(emote) { // eslint-disable-line class-methods-use-this
|
|
|
|
if ( ! emote.margins && ( ! emote.modifier || ( ! emote.modifier_offset && ! emote.extra_width && ! emote.shrink_to_fit ) ) && ! emote.css )
|
|
|
|
return '';
|
|
|
|
|
|
|
|
let output = '';
|
|
|
|
if ( emote.modifier && (emote.modifier_offset || emote.margins || emote.extra_width || emote.shrink_to_fit) ) {
|
|
|
|
let margins = emote.modifier_offset || emote.margins || '0';
|
|
|
|
margins = margins.split(/\s+/).map(x => parseInt(x, 10));
|
|
|
|
if ( margins.length === 3 )
|
|
|
|
margins.push(margins[1]);
|
|
|
|
|
|
|
|
const l = margins.length,
|
|
|
|
m_top = margins[0 % l],
|
|
|
|
m_right = margins[1 % l],
|
|
|
|
m_bottom = margins[2 % l],
|
|
|
|
m_left = margins[3 % l];
|
|
|
|
|
|
|
|
output = `.modified-emote span .ffz-emote[data-id="${emote.id}"] {
|
|
|
|
padding: ${m_top}px ${m_right}px ${m_bottom}px ${m_left}px;
|
|
|
|
${emote.shrink_to_fit ? `max-width: calc(100% - ${40 - m_left - m_right - (emote.extra_width||0)}px);` : ''}
|
|
|
|
margin: 0 !important;
|
|
|
|
}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return `${output}.ffz-emote[data-id="${emote.id}"] {
|
|
|
|
${(emote.margins && ! emote.modifier) ? `margin: ${emote.margins} !important;` : ''}
|
|
|
|
${emote.css||''}
|
|
|
|
}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ========================================================================
|
|
|
|
// Twitch Data Lookup
|
|
|
|
// ========================================================================
|
|
|
|
|
2019-10-28 01:06:02 -04:00
|
|
|
setTwitchEmoteSet(emote_id, set_id) {
|
2019-12-12 18:44:19 -05:00
|
|
|
if ( typeof emote_id === 'number' ) {
|
|
|
|
if ( isNaN(emote_id) || ! isFinite(emote_id) )
|
|
|
|
return;
|
|
|
|
emote_id = `${emote_id}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( typeof set_id === 'number' ) {
|
|
|
|
if ( isNaN(set_id) || ! isFinite(set_id) )
|
|
|
|
return;
|
|
|
|
set_id = `${set_id}`;
|
|
|
|
}
|
2019-10-28 01:06:02 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
this.__twitch_emote_to_set[emote_id] = set_id;
|
2019-10-28 01:06:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
setTwitchSetChannel(set_id, channel) {
|
2019-12-12 18:44:19 -05:00
|
|
|
if ( typeof set_id === 'number' ) {
|
|
|
|
if ( isNaN(set_id) || ! isFinite(set_id) )
|
|
|
|
return;
|
2019-10-28 01:06:02 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
set_id = `${set_id}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.__twitch_set_to_channel[set_id] = channel;
|
2019-10-28 01:06:02 -04:00
|
|
|
}
|
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
_getTwitchEmoteSet(emote_id) {
|
|
|
|
const tes = this.__twitch_emote_to_set,
|
|
|
|
tsc = this.__twitch_set_to_channel;
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
if ( typeof emote_id === 'number' ) {
|
|
|
|
if ( isNaN(emote_id) || ! isFinite(emote_id) )
|
|
|
|
return Promise.resolve(null);
|
|
|
|
|
|
|
|
emote_id = `${emote_id}`;
|
|
|
|
}
|
2019-10-28 14:56:55 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
if ( has(tes, emote_id) ) {
|
|
|
|
const val = tes[emote_id];
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( Array.isArray(val) )
|
|
|
|
return new Promise(s => val.push(s));
|
|
|
|
else
|
|
|
|
return Promise.resolve(val);
|
|
|
|
}
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
const apollo = this.resolve('site.apollo');
|
|
|
|
if ( ! apollo?.client )
|
|
|
|
return Promise.resolve(null);
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
return new Promise(s => {
|
|
|
|
const promises = [s];
|
2019-12-12 18:44:19 -05:00
|
|
|
tes[emote_id] = promises;
|
2019-08-12 22:52:57 -04:00
|
|
|
|
|
|
|
timeout(apollo.client.query({
|
|
|
|
query: GET_EMOTE,
|
|
|
|
variables: {
|
|
|
|
id: `${emote_id}`
|
|
|
|
}
|
2019-10-28 14:56:55 -04:00
|
|
|
}), 2000).then(data => {
|
|
|
|
const emote = data?.data?.emote;
|
|
|
|
let set_id = null;
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( emote ) {
|
2019-12-12 18:44:19 -05:00
|
|
|
set_id = emote.setID;
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
if ( set_id && ! has(tsc, set_id) ) {
|
2019-10-28 14:56:55 -04:00
|
|
|
const type = determineEmoteType(emote);
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
tsc[set_id] = {
|
2019-10-28 14:56:55 -04:00
|
|
|
id: set_id,
|
|
|
|
type,
|
2019-12-12 18:44:19 -05:00
|
|
|
owner: emote?.subscriptionProduct?.owner || emote?.owner
|
|
|
|
};
|
2019-10-28 14:56:55 -04:00
|
|
|
}
|
|
|
|
}
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
tes[emote_id] = set_id;
|
2019-10-28 14:56:55 -04:00
|
|
|
for(const fn of promises)
|
|
|
|
fn(set_id);
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
}).catch(() => {
|
2019-12-12 18:44:19 -05:00
|
|
|
tes[emote_id] = null;
|
2019-10-28 14:56:55 -04:00
|
|
|
for(const fn of promises)
|
|
|
|
fn(null);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
getTwitchEmoteSet(emote_id, callback) {
|
|
|
|
const promise = this._getTwitchEmoteSet(emote_id);
|
|
|
|
if ( callback )
|
|
|
|
promise.then(callback);
|
|
|
|
else
|
|
|
|
return promise;
|
|
|
|
}
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
_getTwitchSetChannel(set_id) {
|
|
|
|
const tsc = this.__twitch_set_to_channel;
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
if ( typeof set_id === 'number' ) {
|
|
|
|
if ( isNaN(set_id) || ! isFinite(set_id) )
|
|
|
|
return Promise.resolve(null);
|
2019-10-28 14:56:55 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
set_id = `${set_id}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( has(tsc, set_id) ) {
|
|
|
|
const val = tsc[set_id];
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( Array.isArray(val) )
|
|
|
|
return new Promise(s => val.push(s));
|
|
|
|
else
|
|
|
|
return Promise.resolve(val);
|
|
|
|
}
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
const apollo = this.resolve('site.apollo');
|
|
|
|
if ( ! apollo?.client )
|
|
|
|
return Promise.resolve(null);
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
return new Promise(s => {
|
|
|
|
const promises = [s];
|
2019-12-12 18:44:19 -05:00
|
|
|
tsc[set_id] = promises;
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
timeout(apollo.client.query({
|
|
|
|
query: GET_EMOTE_SET,
|
|
|
|
variables: {
|
|
|
|
id: `${set_id}`
|
|
|
|
}
|
|
|
|
}), 2000).then(data => {
|
|
|
|
const set = data?.data?.emoteSet;
|
|
|
|
let result = null;
|
|
|
|
|
|
|
|
if ( set ) {
|
|
|
|
result = {
|
|
|
|
id: set_id,
|
|
|
|
type: determineSetType(set),
|
|
|
|
owner: set.owner ? {
|
|
|
|
id: set.owner.id,
|
|
|
|
login: set.owner.login,
|
|
|
|
displayName: set.owner.displayName
|
|
|
|
} : null
|
|
|
|
};
|
|
|
|
}
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
tsc[set_id] = result;
|
2019-10-28 14:56:55 -04:00
|
|
|
for(const fn of promises)
|
|
|
|
fn(result);
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
}).catch(() => {
|
2019-12-12 18:44:19 -05:00
|
|
|
tsc[set_id] = null;
|
2019-10-28 14:56:55 -04:00
|
|
|
for(const fn of promises)
|
|
|
|
fn(null);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2018-07-26 19:40:53 -04:00
|
|
|
|
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
getTwitchSetChannel(set_id, callback) {
|
|
|
|
const promise = this._getTwitchSetChannel(set_id);
|
|
|
|
if ( callback )
|
|
|
|
promise.then(callback);
|
|
|
|
else
|
|
|
|
return promise;
|
|
|
|
}
|
|
|
|
}
|
2019-08-12 22:52:57 -04:00
|
|
|
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
function determineEmoteType(emote) {
|
|
|
|
const product = emote.subscriptionProduct;
|
|
|
|
if ( product ) {
|
|
|
|
if ( product.id == 12658 )
|
|
|
|
return EmoteTypes.Prime;
|
|
|
|
else if ( product.id == 324 )
|
|
|
|
return EmoteTypes.Turbo;
|
2019-10-28 01:06:02 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
// TODO: Care about Overwatch League
|
|
|
|
|
|
|
|
const owner = product.owner;
|
|
|
|
if ( owner ) {
|
|
|
|
if ( owner.id == 139075904 || product.state === 'INACTIVE' )
|
|
|
|
return EmoteTypes.LimitedTime;
|
|
|
|
|
|
|
|
return EmoteTypes.Subscription;
|
2018-07-26 19:40:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( emote.setID == 300238151 )
|
|
|
|
return EmoteTypes.ChannelPoints;
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
const id = parseInt(emote.setID, 10);
|
|
|
|
if ( ! isNaN(id) && isFinite(id) && id >= 5e8 )
|
|
|
|
return EmoteTypes.BitsTier;
|
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
return EmoteTypes.Global;
|
|
|
|
}
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
function determineSetType(set) {
|
|
|
|
const id = parseInt(set.id, 10);
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( TWITCH_GLOBAL_SETS.includes(id) )
|
|
|
|
return EmoteTypes.Global;
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( TWITCH_POINTS_SETS.includes(id) )
|
|
|
|
return EmoteTypes.ChannelPoints;
|
2018-07-26 19:40:53 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( TWITCH_PRIME_SETS.includes(id) )
|
|
|
|
return EmoteTypes.Prime;
|
2017-11-13 01:23:39 -05:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
const owner = set.owner;
|
|
|
|
if ( owner ) {
|
|
|
|
if ( owner.id == 139075904 )
|
|
|
|
return EmoteTypes.LimitedTime;
|
2019-10-28 01:06:02 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
let product;
|
|
|
|
if ( Array.isArray(owner.subscriptionProducts) )
|
|
|
|
for(const prod of owner.subscriptionProducts)
|
|
|
|
if ( set.id == prod.emoteSetID ) {
|
|
|
|
product = prod;
|
|
|
|
break;
|
|
|
|
}
|
2019-10-28 01:06:02 -04:00
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
if ( product ) {
|
|
|
|
if ( product.id == 12658 )
|
|
|
|
return EmoteTypes.Prime;
|
|
|
|
else if ( product.id == 324 )
|
|
|
|
return EmoteTypes.Turbo;
|
|
|
|
else if ( product.state === 'INACTIVE' )
|
|
|
|
return EmoteTypes.LimitedTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EmoteTypes.Subscription;
|
2017-11-13 01:23:39 -05:00
|
|
|
}
|
2019-10-28 14:56:55 -04:00
|
|
|
|
2019-12-12 18:44:19 -05:00
|
|
|
if ( id >= 5e8 )
|
|
|
|
return EmoteTypes.BitsTier;
|
|
|
|
|
2019-10-28 14:56:55 -04:00
|
|
|
return EmoteTypes.Global;
|
2017-11-13 01:23:39 -05:00
|
|
|
}
|