2019-06-14 21:24:48 -04:00
'use strict' ;
// ============================================================================
// Twitch Data
// Get data, from Twitch.
// ============================================================================
import Module from 'utilities/module' ;
2021-04-01 12:05:29 -04:00
import { get , debounce } from 'utilities/object' ;
2019-06-14 21:24:48 -04:00
const LANGUAGE _MATCHER = /^auto___lang_(\w+)$/ ;
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 {
constructor ( ... args ) {
super ( ... args ) ;
2019-08-09 14:24:26 -04:00
this . site = this . parent ;
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 ;
2019-06-14 21:24:48 -04:00
this . tag _cache = new Map ;
this . _waiting _tags = new Map ;
2019-06-15 03:58:06 -04:00
this . _loadTags = debounce ( this . _loadTags , 50 ) ;
this . _loadStreams = debounce ( this . _loadStreams , 50 ) ;
2019-06-14 21:24:48 -04:00
}
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 ) ;
}
2019-12-31 17:44:36 -05:00
mutate ( mutation , variables , options ) {
let thing ;
if ( ! variables && ! options && mutation . mutation )
thing = mutation ;
else {
thing = {
mutation ,
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 ( ) {
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
* /
2021-05-13 15:54:21 -04:00
async getMatchingCategories ( 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-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
// ========================================================================
// 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 2 x 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 ( ) ;
}
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-09-13 16:08:10 -04:00
async getMatchingTags ( query ) {
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
}