1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-03 16:38:31 +00:00
FrankerFaceZ/src/utilities/twitch-data.js

306 lines
6.9 KiB
JavaScript
Raw Normal View History

'use strict';
// ============================================================================
// Twitch Data
// Get data, from Twitch.
// ============================================================================
import Module from 'utilities/module';
import {get, debounce, generateUUID} from 'utilities/object';
const LANGUAGE_MATCHER = /^auto___lang_(\w+)$/;
export default class TwitchData extends Module {
constructor(...args) {
super(...args);
this.inject('site');
this.inject('site.apollo');
this.inject('site.web_munch');
this.tag_cache = new Map;
this._waiting_tags = new Map;
this._loadTags = debounce(this._loadTags.bind(this), 50);
}
queryApollo(query, variables, options) {
let thing;
if ( ! variables && ! options && query.query )
thing = query;
else {
thing = {
query,
variables
};
if ( options )
thing = Object.assign(thing, options);
}
return this.apollo.client.query(thing);
}
get languageCode() {
const session = this.site.getSession();
return session && session.languageCode || 'en'
}
get locale() {
const session = this.site.getSession();
return session && session.locale || 'en-US'
}
get searchClient() {
if ( this._search )
return this._search;
const apollo = this.apollo.client,
core = this.listeners.getCore(),
search_module = this.web_munch.getModule('algolia-search'),
SearchClient = search_module && search_module.a;
if ( ! SearchClient || ! apollo || ! core )
return null;
this._search = new SearchClient({
appId: core.config.algoliaApplicationID,
apiKey: core.config.algoliaAPIKey,
apolloClient: apollo,
logger: core.logger,
config: core.config,
stats: core.stats
});
return this._search;
}
// ========================================================================
// Categories
// ========================================================================
async getMatchingCategories(query) {
const data = await this.queryApollo(
require('./data/search-category.gql'),
{ query }
);
return {
cursor: get('data.searchFor.games.cursor', data),
items: get('data.searchFor.games.items', data) || [],
finished: ! get('data.searchFor.games.pageInfo.hasNextPage', data)
};
}
// ========================================================================
// Users
// ========================================================================
async getMatchingUsers(query) {
const data = await this.queryApollo(
require('./data/search-user.gql'),
{ query }
);
return {
cursor: get('data.searchFor.users.cursor', data),
items: get('data.searchFor.users.items', data) || [],
finished: ! get('data.searchFor.users.pageInfo.hasNextPage', data)
};
}
async getUser(id, login) {
const data = await this.queryApollo(
require('./data/user-fetch.gql'),
{ id, login }
);
return get('data.user', data);
}
// ========================================================================
// Tags
// ========================================================================
async _loadTags() {
if ( this._loading_tags )
return;
this._loading_tags = true;
const processing = this._waiting_tags;
this._waiting_tags = new Map;
try {
const data = await this.queryApollo(
require('./data/tags-fetch.gql'),
{
ids: [...processing.keys()]
}
);
const nodes = get('data.contentTags', data);
if ( Array.isArray(nodes) )
for(const node of nodes) {
const tag = {
id: node.id,
value: node.id,
is_language: node.isLanguageTag,
name: node.tagName,
label: node.localizedName,
description: node.localizedDescription
};
this.tag_cache.set(tag.id, tag);
const promises = processing.get(tag.id);
if ( promises )
for(const pair of promises)
pair[0](tag);
promises.delete(tag.id);
}
for(const promises of processing.values())
for(const pair of promises)
pair[0](null);
} catch(err) {
for(const promises of processing.values())
for(const pair of promises)
pair[1](err);
}
this._loading_tags = false;
if ( this._waiting_tags.size )
this._loadTags();
}
getTag(id, want_description = false) {
if ( this.tag_cache.has(id) ) {
const out = this.tag_cache.get(id);
if ( out && (out.description || ! want_description) )
return Promise.resolve(out);
}
return new Promise((s, f) => {
if ( this._waiting_tags.has(id) )
this._waiting_tags.get(id).push([s, f]);
else {
this._waiting_tags.set(id, [[s, f]]);
if ( ! this._loading_tags )
this._loadTags();
}
});
}
getTagImmediate(id, callback, want_description = false) {
let out = null;
if ( this.tag_cache.has(id) )
out = this.tag_cache.get(id);
if ( ! out || (want_description && ! out.description) )
this.getTag(id, want_description).then(tag => callback(id, tag)).catch(err => callback(id, null, err));
return out;
}
async getTopTags(limit = 50) {
const data = await this.queryApollo(
require('./data/tags-top.gql'),
{limit}
);
const nodes = get('data.topTags', data);
if ( ! Array.isArray(nodes) )
return [];
const out = [], seen = new Set;
for(const node of nodes) {
if ( ! node || seen.has(node.id) )
continue;
seen.add(node.id);
const tag = {
id: node.id,
value: node.id,
is_language: node.isLanguageTag,
name: node.tagName,
label: node.localizedName,
description: node.localizedDescription
};
this.tag_cache.set(tag.id, tag);
out.push(tag);
}
return out;
}
getLanguagesFromTags(tags, callback) {
const out = [],
fn = callback ? debounce(() => {
this.getLanguagesFromTags(tags, callback);
}, 16) : null
if ( Array.isArray(tags) )
for(const tag_id of tags) {
const tag = this.getTagImmediate(tag_id, fn);
if ( tag && tag.is_language ) {
const match = LANGUAGE_MATCHER.exec(tag.name);
if ( match )
out.push(match[1]);
}
}
return out;
}
async getMatchingTags(query, locale) {
if ( ! locale )
locale = this.locale;
const data = await this.searchClient.queryForType(
'tag', query, generateUUID(), {
hitsPerPage: 100,
facetFilters: [
],
restrictSearchableAttributes: [
`localizations.${locale}`,
'tag_name'
]
}
);
const nodes = get('streamTags.hits', data);
if ( ! Array.isArray(nodes) )
return [];
const out = [], seen = new Set;
for(const node of nodes) {
if ( ! node || seen.has(node.tag_id) )
continue;
seen.add(node.tag_id);
if ( ! this.tag_cache.has(node.tag_id) ) {
const tag = {
id: node.tag_id,
value: node.tag_id,
is_language: node.tag_name && LANGUAGE_MATCHER.test(node.tag_name),
label: node.localizations && (node.localizations[locale] || node.localizations['en-us']) || node.tag_name
};
this.tag_cache.set(tag.id);
out.push(tag);
} else {
out.push(this.tag_cache.get(node.tag_id));
}
}
return out;
}
}