Use Azure Functions and PowerShell to get smartphone notifications about streams on Twitch

Tue, May 14, 2019

Read in 5 minutes

Through PowerShell, Azure Functions and API's, I'm creating a solution to get notified on my smartphone when a stream on Twitch reaches a certain amount of viewers.

Use Azure Functions and PowerShell to get smartphone notifications about streams on Twitch

Introduction

I enjoy watching e-sports on Twitch from time to time, mostly Counter-Strike: Global Offensive (CS:GO). However, I’m usually not up-to-date about tournaments and schedules, which means I’m missing out on some great action. To prevent this, I thought it would be cool to see if I could create a solution to get notified on my smartphone when something unusual happens, and it turns out I could!

The components

To make this work, I need a couple of things.

The glue

When I’m creating something, I’ll go with PowerShell as much as I can, and that’s also the case here.

Check stream info periodically

Azure has a couple of ways to ensure that a PowerShell script is being regularly run. I’ve chosen to go with Azure Functions because it’s the cool new thing. Support for PowerShell is still in preview, and Functions v2 only recently added PowerShell support running on PowerShell Core 6.2, which means it’s even more preview!

Getting stream info from Twitch

It turns out Twitch has an entire development section and an API.

Generating notifications on a smartphone

This was the one thing I feared would be the most difficult, and that I’d need to rely on e-mails or texts. Luckily IFTTT made my worries go away, because they have an app that can do just that, and it can even be triggered by a webhook. Perfect.

Design overview

Design overview

Setting up Twitch and IFTTT

The process is straight forward, but there’s some time spent digging through the documentation. For more details, I wrote a blog post about creating a PowerShell function for Twitch to get stream information and IFTTT to send notifications.

Now I need to glue it together with Azure Functions.

Setting up Azure Functions

Inside my resource group, I click Add to create a new Function App. The process is pretty straightforward, and the only important things are to select the region you want in Location and PowerShell (Preview) in Runtime stack.






Great, I now have a Function App, but with no functions. To create a new function, I click the + sign next to Functions.


For now, I want to edit the function inside the portal by choosing In-portal.

If you’re using VS Code, it’s pretty cool debugging and deploying functions directly from it, and there’s a great guide for it on Microsoft Docs. However, because PowerShell in Azure Functions is still in preview, there’s a couple of gotchas along the way. Read the guide carefully.


I want this function to run every 10 minutes, and the Timer trigger is perfect for that. Easy choice.


My new function is done and has a default PowerShell script that’s ready to be modified.


However, before I modify the script, I want to change the timer from the default of every 5 minutes to every 10 minutes.

The schedule is a CRON expression, which you can read more about in the documentation. In short, it takes 6 values, and * is a wildcard that means any.

{second} {minute} {hour} {day} {month} {day-of-week}

The schedule then literally means every time the seconds are 0 and the minutes can be divided by 10, trigger the script. Which means it’ll run every 10 minutes, but you probably got that already.


Here’s the final script I’ll use inside my Azure Function.

# Input bindings are passed in via param block.
# The param block is required for the function to work.
param($Timer)

$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 2.0

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)
}

function Send-IftttAppNotification {
    [cmdletbinding()]
    param(
        [Parameter(Mandatory)]
        [string]$EventName,

        [Parameter(Mandatory)]
        [string]$Key,

        [string]$Value1,

        [string]$Value2,

        [string]$Value3
    )

    $webhookUrl = "https://maker.ifttt.com/trigger/{0}/with/key/{1}" -f $EventName, $Key

    $body = @{
        value1 = $Value1
        value2 = $Value2
        value3 = $Value3
    }

    Invoke-RestMethod -Method Get -Uri $webhookUrl -Body $body
}

$clientId    = 'ClientIdFromDevTwitch' # Client ID from Twitch
$gameId      = '32399' # CS:GO = 32399
$viewerCount = '10000' # Viewer count to trigger notification on
$eventName   = 'popular_stream' # Event name in IFTTT
$key         = 'KeyFromIFTTT' # Key from IFTTT
$lastRunPath = Join-Path $PSScriptRoot 'lastrun.json' # Store the results of the last run

# Load JSON file from the last run
$lastRun = Get-Content -Path $lastRunPath -ErrorAction SilentlyContinue | ConvertFrom-Json -ErrorAction Continue

# Get all Twitch streams and then filter based on viewer count
$streams = Get-TwitchStream -ClientID $clientId -GameID $gameId | Where-Object -FilterScript { $_.viewer_count -gt $viewerCount }

# Overwrite JSON file with filtered result
$streams | Sort-Object -Property 'viewer_count' -Descending | ConvertTo-Json | Out-File -FilePath $lastRunPath

# Iterate over all streams (if any), check if they were in the last run
# and notify if they were not.
foreach ($s in $streams) {
    if (-not $lastRun -or $lastRun.user_id -notcontains $s.user_id) {
        $params = @{
            EventName = $eventName
            Key       = $key
            Value1    = $s.user_name
            Value2    = $s.viewer_count
            Value3    = $s.title
        }
        Send-IftttAppNotification @params | Out-Null
    }
}

I paste the script into the function and click Save and run to check that it works.

It won’t trigger a notification unless the viewer count is above 10000 on a stream. If you want to test that notifications work, but there are no streams live with that many viewers, you can turn down the $viewerCount to something that you know will trigger it, 100 for example.

Save and run function

The logs pop up and, lucky me, execution succeeded.

Logs result

It works! I’m getting notifications when something exciting is happening.

Notifications showing up

Conclusion

That’s it, and now this simple solution will keep me updated. Azure Functions are truly powerful and versatile with PowerShell and proves that without too much hassle, it’s possible to accomplish something sensational.

Was this cool for you? Too much or too little information? Feedback is what makes me better, and you can either write in the comments below or hit me on Twitter at @Dennis_Rye.

Have you done anything awesome with Azure Functions? Please share it then!

  1. Tags: