Fri, May 10, 2019
Read in 4 minutes
PowerShell, the Twitch API and a sprinkle of magic, and a PowerShell function to get information about streams are born.
I love watching streams on Twitch, especially matches in Counter-Strike Global Offensive (CS:GO). One time, when I was waiting for a game to start, and I got a little bored, I wondered how difficult it would be to query Twitch for stream information using PowerShell.
It turns out it’s not too bad at all!
PS C:\> Invoke-RestMethod -Uri 'https://api.twitch.tv/helix/streams'
Invoke-RestMethod : {"error":"Unauthorized","status":401,"message":"Must provide a valid Client-ID or OAuth token"}
At line:1 char:1
+ Invoke-RestMethod -Uri 'https://api.twitch.tv/helix/streams'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
eption
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
It looks like I can’t just directly query the API, I need some authorization. Let’s see how that’s done.
First things first, I need an account on Twitch. I already have that, so far so good.
Next step is to sign up on https://dev.twitch.tv/ and get a key to access their API. Login is just my Twitch account, which I’ll then be asked to link to their development site.
I then need to generate an API key, which I can do in the dashboard by registering a new application.
The name needs to be unique across all of Twitch. The OAuth Redirect URL is for more advanced scenarios, for example, if I want to authenticate my users through Twitch. It’s not relevant here, and localhost is fine. There are multiple options in Category, and I think Application Integration fits what I’m doing best.
Now that the application is registered, I need to hit Manage to go back and see my Client ID.
Now I have access to Twitch’s API, then what? First I’ll check that I can query the Twitch API. Scanning through the documentation, I can see they have an example for getting streams. Even though it says “None” in Authentication, I need to pass my client ID in the header for every request. Here goes:
$headers = @{ 'client-id'='ClientIdFromDevTwitch' }
$result = Invoke-RestMethod -Uri 'https://api.twitch.tv/helix/streams' -Headers $headers
PS C:\> $result.data.Count
20
PS C:\> $result.data[0]
id : 34070510592
user_id : 36029255
user_name : Riot Games
game_id : 21779
community_ids : {ad14d4fc-1a7c-413f-aa32-4906ef3669ae}
type : live
title : MSI Groups Day 2: Team Liquid vs. Invictus Gaming
viewer_count : 98403
started_at : 2019-05-11T05:30:02Z
language : en
thumbnail_url : https://static-cdn.jtvnw.net/previews-ttv/live_user_riotgames-{width}x{height}.jpg
tag_ids : {6ea6bca4-4712-4ab9-a906-e3336a9d8039}
Great, I’m getting data! But, only 20 streams returned for all Twitch streams? Turns out they won’t return more than 20 streams by default, and max 100. But there’s a trick, because I get a “cursor” with each response that I can use to get the next 20 (or 100) results for my query.
PS C:\> $result.pagination
cursor
------
eyJiIjpudWxsLCJhIjp7Ik9mZnNldCI6MjB9fQ
I’ll limit my query to only CS:GO streams in English and then try to iterate through them all.
$headers = @{"client-id" = 'ClientIdFromDevTwitch'}
$result = $null
$streams = @()
do {
$cursor = ""
if ($result) {
$cursor = $result.pagination.cursor
}
$uri = "https://api.twitch.tv/helix/streams?game_id=32399&first=100&language=en&after={0}" -f $cursor
$result = Invoke-RestMethod -Method Get -Headers $headers -Uri $uri
$streams += $result.data
Write-Host "$($result.data.Count) streams found in page"
} while ($result.data.Count -eq 100)
100 streams found in page
100 streams found in page
46 streams found in page
PS C:\> $streams.Count
246
The script works like a charm. In the $uri variable, I added a few query parameters, where ‘game_id’ is the specific game, and I happen to know that CS:GO is 32399. Then I’m using ‘first’ with a value of 100, which increases the results returned to 100, the maximum supported by their API, and ‘language=en’ simply means only English streams.
The last one, ‘after,’ is the interesting one, that’s the one I need to pass my cursor to, to get the next page of results. If it’s empty, I get the very first page. I then wrap it in a do/while loop, because as soon as the results returned from the API is less than 100, I know I’ve reached the end, and I can break out of the loop.
I’ll wrap all that in a sweet and simple function I can use later.
function Get-TwitchStream {
[cmdletbinding()]
param (
[Parameter(Mandatory)]
[string]$ClientID,
[Parameter(Mandatory)]
[int]$GameID,
[string]$Language = 'en'
)
$headers = @{
"client-id" = $ClientID
}
$result = $null
$uriTemplate = "https://api.twitch.tv/helix/streams?game_id={0}&first=100&language={1}&after={2}"
do {
$cursor = ""
if ($result) {
$cursor = $result.pagination.cursor
}
$uri = $uriTemplate -f $GameID, $Language, $cursor
$result = Invoke-RestMethod -Method Get -Headers $headers -Uri $uri
$result.data
} while ($result.data.Count -eq 100)
}
Now I have a simple PowerShell function that can easily query information about a stream on Twitch. And it feels great using PowerShell to solve a… well, not a problem… a curiosity?
Happy hacking.