Skip to content

Instantly share code, notes, and snippets.

@baines
Last active November 9, 2019 12:08
Show Gist options
  • Save baines/344d0483810ad518c4d4 to your computer and use it in GitHub Desktop.
Save baines/344d0483810ad518c4d4 to your computer and use it in GitHub Desktop.
Twitch.tv desktop notification bash script
#!/bin/bash
# twitch-notify.sh by Alex Baines
# Desktop notifications about twitch.tv streams.
# dependencies:
# curl
# underscore-cli
# notify-send
# md5sum
# user-agent sent to twitch.
ua="twitch-notify.sh"
# put lowercase channel names, one per line, in this file.
infile="twitch-channels.txt"
# this file will be kept up-to-date with a list of online streams.
outfile="twitch-status.txt"
# directories for temporary files.
tmpbase="/tmp/twitch"
tmpimgdir="$tmpbase/imgs"
# sounds to play when the status of a stream changes.
new_stream_snd=""
upd_stream_snd=""
del_stream_snd=""
# command to play sounds.
play_snd_cmd="paplay"
# read new stream notifications out loud with espeak or not.
use_espeak=1
# update rate in seconds.
interval=300
declare -A online
function get_img_path {
echo ${tmpimgdir}"/"$(md5sum <<<"$1" | cut -d\ -f 1)
}
function add_stream {
local img=$(get_img_path "$1")
if [ "$4" == "null" ]; then
img="video-x-generic"
else
curl -s -A "$ua" "$4" -o "$img"
fi
notify-send -i "$img" "$1 is streaming now." "$2 [$3]"
if [ -n "$play_snd_cmd" -a -n "$new_stream_snd" ]; then
$play_snd_cmd "$new_stream_snd" &
fi
if [ $use_espeak ]; then
echo "$1 - $3" | espeak 2>/dev/null
fi
online[$1]="\"$2\"\n\t[$3]"
}
function del_stream {
local img=$(get_img_path "$1")
notify-send -i "$img" "$1 is no longer streaming."
if [ -n "$play_snd_cmd" -a -n "$del_stream_snd" ]; then
$play_snd_cmd "$del_stream_snd" &
fi
rm "$img"
unset online[$1]
}
function upd_stream {
local img=$(get_img_path "$1")
notify-send -i "$img" "$1 changed game." "Now streaming $2. [$3]"
if [ -n "$play_snd_cmd" -a -n "$upd_stream_snd" ]; then
$play_snd_cmd "$upd_stream_snd" &
fi
online[$1]="\"$2\"\n\t[$3]"
}
function writefile {
echo -e "Last Update: $(date)\n------------\n">"$outfile"
for i in "${!online[@]}" ; do
echo -e "$i:\n\t${online[$i]}\n" >> "$outfile"
done
}
function contains {
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && echo "true"; done
echo "false"
}
function dl {
curl -A "$ua" -s -w "%{http_code}" -o /dev/stderr "https://api.twitch.tv/kraken/streams?channel=$chans"
}
[ -d "$tmpbase" ] || mkdir "$tmpbase"
[ -d "$tmpimgdir" ] || mkdir "$tmpimgdir"
while true; do
t=$(date +%s)
chans=$(tr "\n" "," <"$infile")
unset t_out t_err
#ugly hack to get both stdout and stderr from curl
eval "$( (dl) 2> >(readarray -t t_err; typeset -p t_err) > >(readarray -t t_out; typeset -p t_out) )"
js="$t_err"
if [[ "$t_out" == "200" ]]; then
js2=$(underscore --coffee process "data.streams.map (x) -> {"`
`"n: x.channel.name,"`
`"g: x.channel.game || x.game || 'null',"`
`"s: x.channel.status || 'null',"`
`"l: x.channel.logo || 'null' }" <<<"$js")
underscore pretty <<< "$js2"
# the Twitch API likes to lie and return 0 results sometimes, try to filter them out.
if [[ "$js2" == "[ ]" && "${#online[@]}" > 1 && -z "$twitch_lies" ]]; then
echo "Skipping potentially erroneous update..."
twitch_lies=1
d=$(($(date +%s)-$t))
if [ "$d" -lt "$interval" ] ; then
sleep $(($interval-$d))
fi
continue
fi
unset twitch_lies
IFS=$'\n'
names=($(underscore select '.n' --outfmt text <<< "$js2"))
games=($(underscore select '.g' --outfmt text <<< "$js2"))
logos=($(underscore select '.l' --outfmt text <<< "$js2"))
statuses=($(underscore select '.s' --outfmt text <<< "$js2"))
unset $IFS
for x in "${!online[@]}"; do
if [ "$(contains $x ${names[@]})" == "false" ]; then
del_stream "$x"
fi
done
for ((x=0; x<${#names[@]}; x++)); do
n="${names[$x]}"
g="${games[$x]}"
l="${logos[$x]}"
s="${statuses[$x]}"
if [[ -z "${online[$n]}" ]]; then
add_stream "$n" "$s" "$g" "$l"
elif [[ "$s" != "null" && "${online[$n]}" != "\"$s\"\n\t[$g]" ]]; then
upd_stream "$n" "$s" "$g"
fi
done
writefile
else
echo "$0: HTTP error: $t_out."
fi
d=$(($(date +%s)-$t))
if [ "$d" -lt "$interval" ] ; then
sleep $(($interval-$d))
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment