2019-06-14 21:24:48 -04:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
// Twitch Data
|
|
|
|
// Get data, from Twitch.
|
|
|
|
// ============================================================================
|
|
|
|
|
2023-11-16 18:41:50 -05:00
|
|
|
import Module, { GenericModule } from 'utilities/module';
|
2023-11-14 13:33:29 -05:00
|
|
|
import {get, debounce, TranslatableError} from 'utilities/object';
|
2023-11-16 18:41:50 -05:00
|
|
|
import type Apollo from './compat/apollo';
|
|
|
|
import type { DocumentNode } from 'graphql';
|
2019-06-14 21:24:48 -04:00
|
|
|
|
2023-11-16 18:41:50 -05:00
|
|
|
declare module 'utilities/types' {
|
|
|
|
interface ModuleEventMap {
|
|
|
|
|
|
|
|
}
|
|
|
|
interface ModuleMap {
|
|
|
|
'site.twitch_data': TwitchData;
|
|
|
|
}
|
|
|
|
}
|
2019-06-14 21:24:48 -04:00
|
|
|
|
2021-05-13 15:54:21 -04:00
|
|
|
/**
|
|
|
|
* PaginatedResult
|
|
|
|
*
|
|
|
|
* @typedef {Object} PaginatedResult
|
|
|
|
* @property {String} cursor A cursor usable to fetch the next page of results
|
|
|
|
* @property {Object[]} items This page of results
|
|
|
|
* @property {Boolean} finished Whether or not we have reached the end of results.
|
|
|
|
*/
|
|
|
|
|
2020-05-28 03:53:15 +08:00
|
|
|
/**
|
|
|
|
* TwitchData is a container for getting different types of Twitch data
|
|
|
|
* @class TwitchData
|
|
|
|
* @extends Module
|
|
|
|
*/
|
2019-06-14 21:24:48 -04:00
|
|
|
export default class TwitchData extends Module {
|
|
|
|
|
2023-11-16 18:41:50 -05:00
|
|
|
apollo: Apollo = null as any;
|
|
|
|
site: GenericModule = null as any;
|
|
|
|
|
|
|
|
|
|
|
|
private _waiting_user_ids: Map<string, unknown>;
|
|
|
|
private _waiting_user_logins: Map<string, unknown>;
|
|
|
|
private _waiting_stream_ids: Map<string, unknown>;
|
|
|
|
private _waiting_stream_logins: Map<string, unknown>;
|
2023-12-14 17:52:35 -05:00
|
|
|
private _waiting_flag_ids: Map<string, unknown>;
|
|
|
|
private _waiting_flag_logins: Map<string, unknown>;
|
|
|
|
|
|
|
|
private _loading_streams?: boolean;
|
|
|
|
private _loading_flags?: boolean;
|
2023-11-16 18:41:50 -05:00
|
|
|
|
|
|
|
private tag_cache: Map<string, unknown>;
|
|
|
|
private _waiting_tags: Map<string, unknown>;
|
|
|
|
|
|
|
|
constructor(name?: string, parent?: GenericModule) {
|
|
|
|
super(name, parent);
|
|
|
|
|
|
|
|
this.site = this.parent as GenericModule;
|
2019-08-09 14:24:26 -04:00
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
this.inject('site.apollo');
|
|
|
|
|
2021-05-07 18:22:55 -04:00
|
|
|
this._waiting_user_ids = new Map;
|
|
|
|
this._waiting_user_logins = new Map;
|
|
|
|
|
2019-06-15 03:58:06 -04:00
|
|
|
this._waiting_stream_ids = new Map;
|
|
|
|
this._waiting_stream_logins = new Map;
|
|
|
|
|
2023-12-14 17:52:35 -05:00
|
|
|
this._waiting_flag_ids = new Map;
|
|
|
|
this._waiting_flag_logins = new Map;
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
this.tag_cache = new Map;
|
|
|
|
this._waiting_tags = new Map;
|
|
|
|
|
2023-11-16 18:41:50 -05:00
|
|
|
// The return type doesn't match, because this method returns
|
|
|
|
// a void and not a Promise. We don't care.
|
|
|
|
this._loadStreams = debounce(this._loadStreams, 50) as any;
|
2019-06-14 21:24:48 -04:00
|
|
|
}
|
|
|
|
|
2023-11-16 18:41:50 -05:00
|
|
|
queryApollo(
|
|
|
|
query: DocumentNode | {query: DocumentNode, variables: any},
|
|
|
|
variables?: any,
|
|
|
|
options?: any
|
|
|
|
) {
|
|
|
|
let thing: {query: DocumentNode, variables: any};
|
|
|
|
if ( ! variables && ! options && 'query' in query && query.query )
|
2019-06-14 21:24:48 -04:00
|
|
|
thing = query;
|
|
|
|
else {
|
|
|
|
thing = {
|
2023-11-16 18:41:50 -05:00
|
|
|
query: query as DocumentNode,
|
2019-06-14 21:24:48 -04:00
|
|
|
variables
|
|
|
|
};
|
|
|
|
|
|
|
|
if ( options )
|
|
|
|
thing = Object.assign(thing, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.apollo.client.query(thing);
|
|
|
|
}
|
|
|
|
|
2023-11-16 18:41:50 -05:00
|
|
|
mutate(
|
|
|
|
mutation: DocumentNode | {mutation: DocumentNode, variables: any},
|
|
|
|
variables?: any,
|
|
|
|
options?: any
|
|
|
|
) {
|
|
|
|
let thing: {mutation: DocumentNode, variables: any};
|
|
|
|
if ( ! variables && ! options && 'mutation' in mutation && mutation.mutation )
|
2019-12-31 17:44:36 -05:00
|
|
|
thing = mutation;
|
|
|
|
else {
|
|
|
|
thing = {
|
2023-11-16 18:41:50 -05:00
|
|
|
mutation: mutation as DocumentNode,
|
2019-12-31 17:44:36 -05:00
|
|
|
variables
|
|
|
|
};
|
|
|
|
|
|
|
|
if ( options )
|
|
|
|
thing = Object.assign(thing, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.apollo.client.mutate(thing);
|
|
|
|
}
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
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'
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-02-22 20:11:35 -05:00
|
|
|
// ========================================================================
|
|
|
|
// Badges
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
async getBadges() {
|
2023-11-16 18:41:50 -05:00
|
|
|
|
2021-02-22 20:11:35 -05:00
|
|
|
const data = await this.queryApollo(
|
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/global-badges.gql')
|
|
|
|
);
|
|
|
|
|
|
|
|
return get('data.badges', data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
// ========================================================================
|
|
|
|
// Categories
|
|
|
|
// ========================================================================
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
2021-05-13 15:54:21 -04:00
|
|
|
* Find categories matching the search query
|
2020-06-23 17:17:00 -04:00
|
|
|
*
|
2021-05-13 15:54:21 -04:00
|
|
|
* @param {String} query The category name to match
|
|
|
|
* @param {Number} [first=15] How many results to return
|
|
|
|
* @param {String} [cursor=null] A cursor, to be used in fetching the
|
|
|
|
* next page of results.
|
|
|
|
* @returns {PaginatedResult} The results
|
2020-06-23 17:17:00 -04:00
|
|
|
*/
|
2023-11-16 18:41:50 -05:00
|
|
|
async getMatchingCategories(
|
|
|
|
query: string,
|
|
|
|
first: number = 15,
|
|
|
|
cursor: string | null = null
|
|
|
|
) {
|
2019-06-14 21:24:48 -04:00
|
|
|
const data = await this.queryApollo(
|
2019-12-31 17:44:36 -05:00
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/search-category.gql'),
|
2021-05-13 15:54:21 -04:00
|
|
|
{
|
|
|
|
query,
|
|
|
|
first,
|
|
|
|
cursor
|
|
|
|
}
|
2019-06-14 21:24:48 -04:00
|
|
|
);
|
|
|
|
|
2021-05-13 15:54:21 -04:00
|
|
|
const items = get('data.searchCategories.edges.@each.node', data) ?? [],
|
|
|
|
needle = query.toLowerCase();
|
|
|
|
|
|
|
|
if ( Array.isArray(items) )
|
|
|
|
items.sort((a,b) => {
|
|
|
|
const a_match = a && (a.name?.toLowerCase?.() === needle || a?.displayName?.toLowerCase?.() === needle),
|
|
|
|
b_match = a && (b.name?.toLowerCase?.() === needle || b?.displayName?.toLowerCase?.() === needle);
|
|
|
|
|
|
|
|
if ( a_match && ! b_match ) return -1;
|
|
|
|
if ( ! a_match && b_match ) return 1;
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
return {
|
2021-05-13 15:54:21 -04:00
|
|
|
cursor: get('data.searchCategories.edges.@last.cursor', data),
|
|
|
|
items,
|
|
|
|
finished: ! get('data.searchCategories.pageInfo.hasNextPage', data),
|
|
|
|
count: get('data.searchCategories.totalCount', data) || 0
|
2019-06-14 21:24:48 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Queries Apollo for category details given the id or name. One of (id, name) MUST be specified
|
|
|
|
* @function getCategory
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} id - the category id number (can be an integer string)
|
|
|
|
* @param {string|null|undefined} name - the category name
|
|
|
|
* @returns {Object} information about the requested stream
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.getCategory(null, 'Just Chatting'));
|
|
|
|
*/
|
2019-10-22 18:32:56 -04:00
|
|
|
async getCategory(id, name) {
|
|
|
|
const data = await this.queryApollo(
|
2019-12-31 17:44:36 -05:00
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/category-fetch.gql'),
|
2019-10-22 18:32:56 -04:00
|
|
|
{ id, name }
|
|
|
|
);
|
|
|
|
|
|
|
|
return get('data.game', data);
|
|
|
|
}
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
|
2023-11-14 13:33:29 -05:00
|
|
|
// ========================================================================
|
|
|
|
// Chat
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
async deleteChatMessage(
|
|
|
|
channel_id/* :string*/,
|
|
|
|
message_id/* :string*/
|
|
|
|
) {
|
|
|
|
channel_id = String(channel_id);
|
|
|
|
|
|
|
|
const data = await this.mutate({
|
|
|
|
mutation: await import(/* webpackChunkName: 'queries' */ './mutations/delete-chat-message.gql'),
|
|
|
|
variables: {
|
|
|
|
input: {
|
|
|
|
channelID: channel_id,
|
|
|
|
messageID: message_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
const code = get('data.deleteChatMessage.responseCode', data);
|
|
|
|
|
|
|
|
if ( code === 'TARGET_IS_BROADCASTER' )
|
|
|
|
throw new TranslatableError(
|
|
|
|
"You cannot delete the broadcaster's messages.",
|
|
|
|
"chat.delete.forbidden.broadcaster"
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( code === 'TARGET_IS_MODERATOR' )
|
|
|
|
throw new TranslatableError(
|
|
|
|
"You cannot delete messages from moderator {displayName}.",
|
|
|
|
"chat.delete.forbidden.moderator",
|
|
|
|
get('data.deleteChatMessage.message.sender', data)
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( code !== 'SUCCESS' )
|
|
|
|
throw new TranslatableError(
|
|
|
|
"You don't have permission to delete messages.",
|
|
|
|
"chat.delete.forbidden"
|
|
|
|
);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
// ========================================================================
|
|
|
|
// Users
|
|
|
|
// ========================================================================
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
2021-05-13 15:54:21 -04:00
|
|
|
* Find users matching the search query.
|
2020-06-23 17:17:00 -04:00
|
|
|
*
|
2021-05-13 15:54:21 -04:00
|
|
|
* @param {String} query Text to match in the login or display name
|
|
|
|
* @param {Number} [first=15] How many results to return
|
|
|
|
* @param {String} [cursor=null] A cursor, to be used in fetching the next
|
|
|
|
* page of results.
|
|
|
|
* @returns {PaginatedResult} The results
|
2020-06-23 17:17:00 -04:00
|
|
|
*/
|
2021-05-13 15:54:21 -04:00
|
|
|
async getMatchingUsers(query, first = 15, cursor = null) {
|
2019-06-14 21:24:48 -04:00
|
|
|
const data = await this.queryApollo(
|
2019-12-31 17:44:36 -05:00
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/search-user.gql'),
|
2021-05-13 15:54:21 -04:00
|
|
|
{
|
|
|
|
query,
|
|
|
|
first,
|
|
|
|
cursor
|
|
|
|
}
|
2019-06-14 21:24:48 -04:00
|
|
|
);
|
|
|
|
|
2021-05-13 15:54:21 -04:00
|
|
|
const items = get('data.searchUsers.edges.@each.node', data) ?? [],
|
|
|
|
needle = query.toLowerCase();
|
|
|
|
|
|
|
|
if ( Array.isArray(items) )
|
|
|
|
items.sort((a,b) => {
|
|
|
|
const a_match = a && (a.login?.toLowerCase?.() === needle || a?.displayName?.toLowerCase?.() === needle),
|
|
|
|
b_match = a && (b.login?.toLowerCase?.() === needle || b?.displayName?.toLowerCase?.() === needle);
|
|
|
|
|
|
|
|
if ( a_match && ! b_match ) return -1;
|
|
|
|
if ( ! a_match && b_match ) return 1;
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
return {
|
2021-05-13 15:54:21 -04:00
|
|
|
cursor: get('data.searchUsers.edges.@last.cursor', data),
|
|
|
|
items,
|
|
|
|
finished: ! get('data.searchUsers.pageInfo.hasNextPage', data),
|
|
|
|
count: get('data.searchUsers.totalCount', data) || 0
|
2019-06-14 21:24:48 -04:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Queries Apollo for user details given the id or name. One of (id, login) MUST be specified
|
|
|
|
* @function getUser
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} id - the user id number (can be an integer string)
|
|
|
|
* @param {string|null|undefined} login - the username
|
|
|
|
* @returns {Object} information about the requested user
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.getUser(19571641, null));
|
|
|
|
*/
|
2019-06-14 21:24:48 -04:00
|
|
|
async getUser(id, login) {
|
|
|
|
const data = await this.queryApollo(
|
2019-12-31 17:44:36 -05:00
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/user-fetch.gql'),
|
2019-06-14 21:24:48 -04:00
|
|
|
{ id, login }
|
|
|
|
);
|
|
|
|
|
|
|
|
return get('data.user', data);
|
|
|
|
}
|
|
|
|
|
2020-09-15 19:17:29 -04:00
|
|
|
/**
|
|
|
|
* Queries Apollo for the user's current game, details given the user id or name. One of (id, login) MUST be specified
|
|
|
|
* @function getUserGame
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} id - the user id number (can be an integer string)
|
|
|
|
* @param {string|null|undefined} login - the username
|
|
|
|
* @returns {Object} information about the requested user
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.getUserGame(19571641, null));
|
|
|
|
*/
|
|
|
|
async getUserGame(id, login) {
|
|
|
|
const data = await this.queryApollo(
|
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/user-game.gql'),
|
|
|
|
{ id, login }
|
|
|
|
);
|
|
|
|
|
|
|
|
return get('data.user.broadcastSettings.game', data);
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Queries Apollo for the logged in user's relationship to the channel with given the id or name. One of (id, login) MUST be specified
|
|
|
|
* @function getUserSelf
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} id - the channel id number (can be an integer string)
|
|
|
|
* @param {string|null|undefined} login - the channel username
|
|
|
|
* @returns {Object} information about your status in the channel
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.getUserSelf(null, "ninja"));
|
|
|
|
*/
|
2020-01-11 17:13:56 -05:00
|
|
|
async getUserSelf(id, login) {
|
|
|
|
const data = await this.queryApollo(
|
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/user-self.gql'),
|
|
|
|
{ id, login }
|
|
|
|
);
|
|
|
|
|
|
|
|
return get('data.user.self', data);
|
|
|
|
}
|
|
|
|
|
2023-03-30 14:54:33 -04:00
|
|
|
|
|
|
|
async getUserFollowed(id, login) {
|
|
|
|
const data = await this.queryApollo(
|
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/user-followed.gql'),
|
|
|
|
{ id, login }
|
|
|
|
);
|
|
|
|
|
|
|
|
return get('data.user.self.follower', data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async followUser(channel_id, disable_notifications = false) {
|
|
|
|
channel_id = String(channel_id);
|
|
|
|
disable_notifications = !! disable_notifications;
|
|
|
|
|
|
|
|
const data = await this.mutate({
|
|
|
|
mutation: await import(/* webpackChunkName: 'queries' */ './data/follow-user.gql'),
|
|
|
|
variables: {
|
|
|
|
input: {
|
|
|
|
targetID: channel_id,
|
|
|
|
disableNotifications: disable_notifications
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log('result', data);
|
|
|
|
const err = get('data.followUser.error', data);
|
|
|
|
if ( err?.code )
|
|
|
|
throw new Error(err.code);
|
|
|
|
|
|
|
|
return get('data.followUser.follow', data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async unfollowUser(channel_id, disable_notifications = false) {
|
|
|
|
channel_id = String(channel_id);
|
|
|
|
disable_notifications = !! disable_notifications;
|
|
|
|
|
|
|
|
const data = await this.mutate({
|
|
|
|
mutation: await import(/* webpackChunkName: 'queries' */ './data/unfollow-user.gql'),
|
|
|
|
variables: {
|
|
|
|
input: {
|
|
|
|
targetID: channel_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log('result', data);
|
|
|
|
return get('data.unfollowUser.follow', data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Queries Apollo for the requested user's latest broadcast. One of (id, login) MUST be specified
|
|
|
|
* @function getLastBroadcast
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} id - the channel id number (can be an integer string)
|
|
|
|
* @param {string|null|undefined} login - the channel username
|
|
|
|
* @returns {Object} information about the requested user's latest broadcast
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.getLastBroadcast(19571641, null));
|
|
|
|
*/
|
2019-12-05 23:13:27 -05:00
|
|
|
async getLastBroadcast(id, login) {
|
|
|
|
const data = await this.queryApollo(
|
2019-12-31 17:44:36 -05:00
|
|
|
await import(/* webpackChunkName: 'queries' */ './data/last-broadcast.gql'),
|
2019-12-05 23:13:27 -05:00
|
|
|
{ id, login }
|
|
|
|
);
|
|
|
|
|
|
|
|
return get('data.user.lastBroadcast', data);
|
|
|
|
}
|
2019-06-14 21:24:48 -04:00
|
|
|
|
2021-04-01 12:05:29 -04:00
|
|
|
|
2021-05-07 18:22:55 -04:00
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-18 20:56:33 -04:00
|
|
|
// ========================================================================
|
|
|
|
// Broadcast ID
|
|
|
|
// ========================================================================
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Queries Apollo for the ID of the specified user's current broadcast. This ID will become the VOD ID. One of (id, login) MUST be specified
|
|
|
|
* @function getBroadcastID
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} id - the channel id number (can be an integer string)
|
|
|
|
* @param {string|null|undefined} login - the channel username
|
|
|
|
* @returns {Object} information about the current broadcast
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.getBroadcastID(null, "ninja"));
|
|
|
|
*/
|
2019-10-18 20:56:33 -04:00
|
|
|
async getBroadcastID(id, login) {
|
|
|
|
const data = await this.queryApollo({
|
2019-12-31 17:44:36 -05:00
|
|
|
query: await import(/* webpackChunkName: 'queries' */ './data/broadcast-id.gql'),
|
2019-10-18 20:56:33 -04:00
|
|
|
variables: {
|
|
|
|
id,
|
|
|
|
login
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return get('data.user.stream.archiveVideo.id', data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
async getChannelColor(id, login) {
|
|
|
|
const data = await this.queryApollo({
|
|
|
|
query: await import(/* webpackChunkName: 'queries' */ './data/user-color.gql'),
|
|
|
|
variables: {
|
|
|
|
id,
|
|
|
|
login
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return get('data.user.primaryColorHex', data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-31 17:44:36 -05:00
|
|
|
// ========================================================================
|
|
|
|
// Polls
|
|
|
|
// ========================================================================
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Queries Apollo for information about the specified poll.
|
|
|
|
* @function getPoll
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string} poll_id - the poll id number (can be an integer string)
|
|
|
|
* @returns {Object} information about the specified poll
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.getPoll(1337));
|
|
|
|
*/
|
2019-12-31 17:44:36 -05:00
|
|
|
async getPoll(poll_id) {
|
|
|
|
const data = await this.queryApollo({
|
|
|
|
query: await import(/* webpackChunkName: 'queries' */ './data/poll-get.gql'),
|
|
|
|
variables: {
|
|
|
|
id: poll_id
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return get('data.poll', data);
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Create a new poll
|
|
|
|
* @function createPoll
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string} channel_id - the channel id number (can be an integer string)
|
|
|
|
* @param {string} title - the poll title
|
|
|
|
* @param {string[]} choices - an array of poll choices
|
|
|
|
* @param {Object} [options] - an object containing poll options
|
|
|
|
* @param {int} [options.bits=0] - how many bits it costs to vote
|
|
|
|
* @param {int} [options.duration=60] - how long the poll will be held for, in seconds
|
|
|
|
* @param {bool} [options.subscriberMultiplier=false] - whether to activate subsriber 2x multiplier
|
|
|
|
* @param {bool} [options.subscriberOnly=false] - whether only subscribers may vote
|
|
|
|
* @returns {Object} poll data
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.createPoll(19571641, "Pick an option:", ["One", "Two", "Three"], {bits: 10, duration: 120, subscriberMultiplier: false, subscriberOnly: true}));
|
|
|
|
*/
|
2019-12-31 17:44:36 -05:00
|
|
|
async createPoll(channel_id, title, choices, options = {}) {
|
|
|
|
if ( typeof title !== 'string' )
|
|
|
|
throw new TypeError('title must be string');
|
|
|
|
|
|
|
|
if ( ! Array.isArray(choices) || choices.some(x => typeof x !== 'string') )
|
|
|
|
throw new TypeError('choices must be array of strings');
|
|
|
|
|
|
|
|
let bits = options.bits || 0,
|
|
|
|
duration = options.duration || 60;
|
|
|
|
if ( typeof bits !== 'number' || bits < 0 )
|
|
|
|
bits = 0;
|
|
|
|
if ( typeof duration !== 'number' || duration < 0 )
|
|
|
|
duration = 60;
|
|
|
|
|
|
|
|
const data = await this.mutate({
|
|
|
|
mutation: await import(/* webpackChunkName: 'queries' */ './data/poll-create.gql'),
|
|
|
|
variables: {
|
|
|
|
input: {
|
|
|
|
bitsCost: bits,
|
|
|
|
bitsVoting: bits > 0,
|
|
|
|
choices: choices.map(x => ({title: x})),
|
|
|
|
durationSeconds: duration,
|
|
|
|
ownedBy: `${channel_id}`,
|
|
|
|
subscriberMultiplier: options.subscriberMultiplier || false,
|
|
|
|
subscriberOnly: options.subscriberOnly || false,
|
|
|
|
title
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return get('data.createPoll.poll', data);
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Place specified poll into archive
|
|
|
|
* @function archivePoll
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} poll_id - the poll id number (can be an integer string)
|
|
|
|
* @returns {Object} information about the specified poll
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.archivePoll(1337));
|
|
|
|
*/
|
2019-12-31 17:44:36 -05:00
|
|
|
async archivePoll(poll_id) {
|
|
|
|
const data = await this.mutate({
|
|
|
|
mutation: await import(/* webpackChunkName: 'queries' */ './data/poll-archive.gql'),
|
|
|
|
variables: {
|
|
|
|
id: poll_id
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return get('data.archivePoll.poll', data);
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Terminate specified poll
|
|
|
|
* @function terminatePoll
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} poll_id - the poll id number (can be an integer string)
|
|
|
|
* @returns {Object} information about the specified poll
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* console.log(this.twitch_data.archivePoll(1337));
|
|
|
|
*/
|
2019-12-31 17:44:36 -05:00
|
|
|
async terminatePoll(poll_id) {
|
|
|
|
const data = await this.mutate({
|
|
|
|
mutation: await import(/* webpackChunkName: 'queries' */ './data/poll-terminate.gql'),
|
|
|
|
variables: {
|
|
|
|
id: poll_id
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return get('data.terminatePoll.poll', data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-15 03:58:06 -04:00
|
|
|
// ========================================================================
|
|
|
|
// Stream Up-Type (Uptime and Type, for Directory Purposes)
|
|
|
|
// ========================================================================
|
|
|
|
|
2020-05-28 03:53:15 +08:00
|
|
|
/**
|
|
|
|
* Queries Apollo for stream metadata. One of (id, login) MUST be specified
|
|
|
|
* @function getStreamMeta
|
|
|
|
* @memberof TwitchData
|
|
|
|
*
|
|
|
|
* @param {int|string|null|undefined} id - the channel id number (can be an integer string)
|
|
|
|
* @param {string|null|undefined} login - the channel name
|
|
|
|
* @returns {Promise} information about the requested stream
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
|
|
|
* this.twitch_data.getStreamMeta(19571641, null).then(function(returnObj){console.log(returnObj);});
|
|
|
|
*/
|
2019-06-15 03:58:06 -04:00
|
|
|
getStreamMeta(id, login) {
|
2019-06-19 20:57:14 -04:00
|
|
|
return new Promise((s, f) => {
|
2019-06-15 03:58:06 -04:00
|
|
|
if ( id ) {
|
|
|
|
if ( this._waiting_stream_ids.has(id) )
|
|
|
|
this._waiting_stream_ids.get(id).push([s, f]);
|
|
|
|
else
|
|
|
|
this._waiting_stream_ids.set(id, [[s, f]]);
|
|
|
|
} else if ( login ) {
|
|
|
|
if ( this._waiting_stream_logins.has(login) )
|
|
|
|
this._waiting_stream_logins.get(login).push([s, f]);
|
|
|
|
else
|
|
|
|
this._waiting_stream_logins.set(login, [[s, f]]);
|
|
|
|
} else
|
|
|
|
f('id and login cannot both be null');
|
|
|
|
|
|
|
|
if ( ! this._loading_streams )
|
|
|
|
this._loadStreams();
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async _loadStreams() {
|
|
|
|
if ( this._loading_streams )
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._loading_streams = true;
|
|
|
|
|
|
|
|
// Get the first 50... things.
|
|
|
|
const ids = [...this._waiting_stream_ids.keys()].slice(0, 50),
|
|
|
|
remaining = 50 - ids.length,
|
|
|
|
logins = remaining > 0 ? [...this._waiting_stream_logins.keys()].slice(0, remaining) : [];
|
|
|
|
|
|
|
|
let nodes;
|
|
|
|
|
|
|
|
try {
|
|
|
|
const data = await this.queryApollo({
|
2019-12-31 17:44:36 -05:00
|
|
|
query: await import(/* webpackChunkName: 'queries' */ './data/stream-fetch.gql'),
|
2019-06-15 03:58:06 -04:00
|
|
|
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_stream_ids.get(id);
|
|
|
|
this._waiting_stream_ids.delete(id);
|
|
|
|
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[1](err);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const login of logins) {
|
|
|
|
const promises = this._waiting_stream_logins.get(login);
|
|
|
|
this._waiting_stream_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_stream_ids.get(node.id);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_stream_ids.delete(node.id);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](node.stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
promises = this._waiting_stream_logins.get(node.login);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_stream_logins.delete(node.login);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](node.stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const id of id_set) {
|
|
|
|
const promises = this._waiting_stream_ids.get(id);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_stream_ids.delete(id);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const login of login_set) {
|
|
|
|
const promises = this._waiting_stream_logins.get(login);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_stream_logins.delete(login);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this._loading_streams = false;
|
|
|
|
|
|
|
|
if ( this._waiting_stream_ids.size || this._waiting_stream_logins.size )
|
|
|
|
this._loadStreams();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-12-14 17:52:35 -05:00
|
|
|
// ========================================================================
|
|
|
|
// Stream Content Flags (for Directory Purposes)
|
|
|
|
// ========================================================================
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Queries Apollo for stream content flags. One of (id, login) MUST be specified
|
|
|
|
*
|
|
|
|
* @param id - the channel id number (can be an integer string)
|
|
|
|
* @param login - the channel name
|
|
|
|
*/
|
|
|
|
getStreamFlags(id: string | number): Promise<any>;
|
|
|
|
getStreamFlags(id: null, login: string): Promise<any>;
|
|
|
|
getStreamFlags(id: string | number | null, login?: string | null) {
|
|
|
|
return new Promise((s, f) => {
|
|
|
|
if ( typeof id === 'number' )
|
|
|
|
id = `${id}`;
|
|
|
|
|
|
|
|
if ( id ) {
|
|
|
|
const existing = this._waiting_flag_ids.get(id);
|
|
|
|
if ( existing )
|
|
|
|
existing.push([s,f]);
|
|
|
|
else
|
|
|
|
this._waiting_flag_ids.set(id, [[s,f]]);
|
|
|
|
|
|
|
|
} else if ( login ) {
|
|
|
|
const existing = this._waiting_flag_logins.get(login);
|
|
|
|
if ( existing )
|
|
|
|
existing.push([s,f]);
|
|
|
|
else
|
|
|
|
this._waiting_flag_logins.set(login, [[s,f]]);
|
|
|
|
|
|
|
|
} else
|
|
|
|
f('id and login cannot both be null');
|
|
|
|
|
|
|
|
if ( ! this._loading_flags )
|
2023-12-18 17:11:44 -05:00
|
|
|
this._loadStreamFlags();
|
2023-12-14 17:52:35 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-12-18 17:11:44 -05:00
|
|
|
async _loadStreamFlags() {
|
2023-12-14 17:52:35 -05:00
|
|
|
if ( this._loading_flags )
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._loading_flags = true;
|
|
|
|
|
|
|
|
// Get the first 50... things.
|
|
|
|
const ids = [...this._waiting_flag_ids.keys()].slice(0, 50),
|
|
|
|
remaining = 50 - ids.length,
|
|
|
|
logins = remaining > 0 ? [...this._waiting_flag_logins.keys()].slice(0, remaining) : [];
|
|
|
|
|
|
|
|
let nodes;
|
|
|
|
|
|
|
|
try {
|
|
|
|
const data = await this.queryApollo({
|
|
|
|
query: await import(/* webpackChunkName: 'queries' */ './data/stream-flags.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_flag_ids.get(id);
|
|
|
|
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_flag_ids.delete(id);
|
|
|
|
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[1](err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const login of logins) {
|
|
|
|
const promises = this._waiting_flag_logins.get(login);
|
|
|
|
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_flag_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_flag_ids.get(node.id);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_flag_ids.delete(node.id);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](node.stream?.contentClassificationLabels);
|
|
|
|
}
|
|
|
|
|
|
|
|
promises = this._waiting_flag_logins.get(node.login);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_flag_logins.delete(node.login);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](node.stream?.contentClassificationLabels);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const id of id_set) {
|
|
|
|
const promises = this._waiting_flag_ids.get(id);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_flag_ids.delete(id);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const login of login_set) {
|
|
|
|
const promises = this._waiting_flag_logins.get(login);
|
|
|
|
if ( promises ) {
|
|
|
|
this._waiting_flag_logins.delete(login);
|
|
|
|
for(const pair of promises)
|
|
|
|
pair[0](null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this._loading_flags = false;
|
|
|
|
|
|
|
|
if ( this._waiting_flag_ids.size || this._waiting_flag_logins.size )
|
2023-12-18 17:11:44 -05:00
|
|
|
this._loadStreamFlags();
|
2023-12-14 17:52:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-14 21:24:48 -04:00
|
|
|
// ========================================================================
|
|
|
|
// Tags
|
|
|
|
// ========================================================================
|
|
|
|
|
2020-06-23 17:17:00 -04:00
|
|
|
/**
|
|
|
|
* Search tags
|
|
|
|
* @function getMatchingTags
|
|
|
|
* @memberof TwitchData
|
|
|
|
* @async
|
|
|
|
*
|
|
|
|
* @param {string} query - the search string
|
|
|
|
* @returns {string[]} an array containing tags that match the query string
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
*
|
2021-04-01 12:05:29 -04:00
|
|
|
* console.log(await this.twitch_data.getMatchingTags("Rainbo"));
|
2020-06-23 17:17:00 -04:00
|
|
|
*/
|
2023-11-16 18:41:50 -05:00
|
|
|
async getMatchingTags(query: string) {
|
2021-04-01 12:05:29 -04:00
|
|
|
const data = await this.queryApollo({
|
2023-09-13 16:08:10 -04:00
|
|
|
query: await import(/* webpackChunkName: 'queries' */ './data/tag-search.gql'),
|
2021-04-01 12:05:29 -04:00
|
|
|
variables: {
|
|
|
|
query,
|
2023-09-13 16:08:10 -04:00
|
|
|
first: 100
|
2021-04-01 12:05:29 -04:00
|
|
|
}
|
|
|
|
});
|
2019-06-14 21:24:48 -04:00
|
|
|
|
2023-09-13 16:08:10 -04:00
|
|
|
const edges = data?.data?.searchFreeformTags?.edges;
|
|
|
|
if ( ! Array.isArray(edges) || ! edges.length )
|
2019-06-14 21:24:48 -04:00
|
|
|
return [];
|
|
|
|
|
2021-04-01 12:05:29 -04:00
|
|
|
const out = [];
|
2023-09-13 16:08:10 -04:00
|
|
|
for(const edge of edges) {
|
|
|
|
const tag = edge?.node?.tagName;
|
2021-04-01 12:05:29 -04:00
|
|
|
if ( tag )
|
2019-06-15 03:58:06 -04:00
|
|
|
out.push(tag);
|
2019-06-14 21:24:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
2020-05-28 03:53:15 +08:00
|
|
|
}
|