/ app / back / twitch.mjs
twitch.mjs
  1  import { ASK_CLIENT_ID, ASK_APP_SECRET } from "./secrets.mjs"
  2  
  3  let ASK_APP_TOKEN
  4  
  5  export async function getOfflineStreams(openEndlessSessions) {
  6    if (ASK_APP_TOKEN == undefined) { await setAppAccessToken() } 
  7  
  8    const offlineStreams = new Map(openEndlessSessions)
  9  
 10    let channelIds = [...openEndlessSessions.keys()]
 11    ,   liveChannels = []
 12  
 13    try {    
 14      while (channelIds.length) {
 15        let range = Math.min(channelIds.length, 100)
 16        
 17        liveChannels = liveChannels.concat(await helixIsLive(channelIds.slice(0,range)))
 18        channelIds = channelIds.slice(range)
 19      }
 20    } catch (e) {
 21      console.log(`[TWITCH] Could not get status of streams with endless sessions, aborting check`)
 22      return new Map()
 23    }
 24  
 25    for (const id of liveChannels) {
 26      offlineStreams.delete(id)
 27    }
 28  
 29    return offlineStreams
 30  }
 31  
 32  export async function helixIsLive(channelIds) {
 33    if (!ASK_APP_TOKEN) throw new Error(`Invalid App Access Token, cannot fulfill request`)
 34      
 35    const options = { headers: { "Authorization": `Bearer ${ASK_APP_TOKEN}`, "Client-Id": ASK_CLIENT_ID } }
 36  
 37    let params = "first=100"
 38    ,   results = []
 39  
 40    channelIds.forEach((id, idx) => { params += `&user_id=${id}` })
 41  
 42    try {     
 43      let response = await fetch(`https://api.twitch.tv/helix/streams?${params}`, options)
 44  
 45      // 401 Unauthorized
 46      if (response.status === 401) {
 47        // App Access token has expired (it will expire every 90 mins)
 48        try {
 49          // request a new one and retry
 50          await setAppAccessToken()
 51          return helixIsLive(channelIds)
 52        } catch (e) {
 53          console.log(`[TWITCH] Failed to get App Access Token for ASK EBS (${e})`)
 54          return results
 55        }
 56      }
 57  
 58      response = await response.json()
 59  
 60      if (response.data.length > 0) {
 61        results = results.concat(response.data.map(d => +d.user_id))
 62      }
 63  
 64    } catch (e) {
 65      console.log(`[TWITCH] Failed to initialize App Access Token for ASK EBS (${e})`)
 66      return results
 67    }
 68  
 69    return results
 70  }
 71  
 72  // Get ASK APP TOKEN
 73  // https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#client-credentials-grant-flow
 74  async function setAppAccessToken() {
 75    try {
 76  
 77      let response = await fetch(`https://id.twitch.tv/oauth2/token`, {
 78        method: 'post',
 79        headers: {
 80          'Content-Type': 'application/x-www-form-urlencoded'
 81        },
 82        body: new URLSearchParams({
 83          client_id: ASK_CLIENT_ID,
 84          client_secret: ASK_APP_SECRET,
 85          grant_type: 'client_credentials'
 86        })
 87      })
 88  
 89      if (!response.ok) {
 90        throw new Error(`Request to get App Access Token for EBS failed! (${response.status}: ${response.statusText})`)
 91      }
 92  
 93      response = await response.json()
 94      const hasData = response.access_token && response.access_token.length > 0
 95  
 96      if (hasData) {
 97        ASK_APP_TOKEN = response.access_token
 98      } else {
 99        throw new Error("Did not receive access token after successful request")
100      }
101  
102    } catch (e) {
103      console.log("[TWITCH]",e)
104    }
105  }