---
title: Handy script for a more zen twitch experience
date: 2025-08-13
tags:
  - bash
  - twitch
draft: false
---

I like to watch twitch streams.
Watching them in the browser at `twitch.tv` is generally not an experience which sparks joy though.
I'm buffering.
I'm declining cookies.
I'm getting spammed with notifications to claim a sick new overwatch skin.
There's a little channel point button twerking for me to click it.
You get the idea; it's a heavy noisy experience.
<!--more-->

As a result I set out to devise a solution which does spark joy.
I came up with a script which leans on DIY desktop staples (dunst, tofi, mpv) and the very nice cli utility [streamlink](https://github.com/streamlink/streamlink).
Here it is:

```bash
PLAYER="mpv"
LAUNCHER="tofi"
NOTIFY="dunstify"

# you need an api key, get them here
# https://dev.twitch.tv/docs/api/get-started/
CLIENT_ID="id-here"
CLIENT_SECRET="secret-here-please-sssshh"

# list of streams to check
STREAMS=(
  "limmy"
  "fl0m"
  "northernlion"
  "caedrel"
)

# reassure user that something is happening
"${NOTIFY}" "twitch -- checking who's live beep boop be patient"

# get auth token from twitch
ACCESS_TOKEN=$(curl -s -X POST \
  "https://id.twitch.tv/oauth2/token" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  | jq -r '.access_token')

# define empty list
LIVE=()

# loop through streams, check if live and append info to list
for STREAM in "${STREAMS[@]}"; do
    RESPONSE=$(curl -s -H "Client-ID: $CLIENT_ID" \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      "https://api.twitch.tv/helix/streams?user_login=$STREAM")

    LIVE_STATUS=$(echo "$RESPONSE" | jq '.data | length')

    if [ "$LIVE_STATUS" -gt 0 ]; then
      TITLE=$(echo "$RESPONSE" | jq -r '.data[0].title')
      GAME=$(echo "$RESPONSE" | jq -r '.data[0].game_name')
      LIVE+=("$STREAM | $GAME | $TITLE")
    fi
done

# pipe list items into tofi with new lines at the end
choice="$( printf "%s\n" "${LIVE[@]}" | "${LAUNCHER}")"

if [[ -n "$choice" ]]; then
  # get first column from selection aka stream name
  meat=$(echo "$choice" | awk '{print $1}')
  "${NOTIFY}" "twitch -- launching twitch.tv/$meat"
  streamlink twitch.tv/"$meat" 1080p60 --player "${PLAYER}"
fi

```

### What it does:

- talk to twitch api to get auth token
- loop trough list of streams to check if they're live (using auth token)
- grab some info about streams that are live and append it to a list
- pipe said list into tofi
- capture user's choice
- open choice in mpv using streamlink

### Dependencies

- curl
- jq
- tofi (would work with other launchers dmenu etc.)
- mpv (would work with other media players vlc etc.)
- dunst (would work with other notification daemons mako etc.)

### Positive :)

- no chat (you don't have to read the degenerates spamming LUL)
- you can customise the script to use your favourite desktop tools
- can rewind!

### Negative :(

- no chat (you might want to spam LUL)
- takes a second to talk to the internet so things don't launch immediately
- have to faff with getting api key - [how to get one btw](https://dev.twitch.tv/docs/api/get-started/)

Hope you enjoyed bye
