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 }