flokati/modules/twitch.go

248 lines
7.6 KiB
Go

// vi:ts=4:sts=4:sw=4:noet:tw=72
//
// flokatirc twitch module
//
// Copyright (c) 2016 Daniel Aberger <da@ixab.de>
package modules
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
"flokatirc/util"
"github.com/sorcix/irc"
)
type TwitchChannelObject struct {
_id int `json:"_id"`
_links struct {
Chat string `json:"chat"`
Commercial string `json:"commercial"`
Editors string `json:"editors"`
Features string `json:"features"`
Follows string `json:"follows"`
Self string `json:"self"`
StreamKey string `json:"stream_key"`
Subscriptions string `json:"subscriptions"`
Teams string `json:"teams"`
Videos string `json:"videos"`
} `json:"_links"`
Background interface{} `json:"background"`
Banner string `json:"banner"`
BroadcasterLanguage string `json:"broadcaster_language"`
CreatedAt string `json:"created_at"`
Delay interface{} `json:"delay"`
DisplayName string `json:"display_name"`
Followers int `json:"followers"`
Game string `json:"game"`
Language string `json:"language"`
Logo string `json:"logo"`
Mature bool `json:"mature"`
Name string `json:"name"`
Partner bool `json:"partner"`
ProfileBanner string `json:"profile_banner"`
ProfileBannerBackgroundColor string `json:"profile_banner_background_color"`
Status string `json:"status"`
UpdatedAt string `json:"updated_at"`
URL string `json:"url"`
VideoBanner string `json:"video_banner"`
Views int `json:"views"`
}
type TwitchStreamObject struct {
_links struct {
Channel string `json:"channel"`
Self string `json:"self"`
} `json:"_links"`
Stream struct {
_id int `json:"_id"`
_links struct {
Self string `json:"self"`
} `json:"_links"`
AverageFps float64 `json:"average_fps"`
Channel struct {
_id int `json:"_id"`
_links struct {
Chat string `json:"chat"`
Commercial string `json:"commercial"`
Editors string `json:"editors"`
Features string `json:"features"`
Follows string `json:"follows"`
Self string `json:"self"`
StreamKey string `json:"stream_key"`
Subscriptions string `json:"subscriptions"`
Teams string `json:"teams"`
Videos string `json:"videos"`
} `json:"_links"`
Background interface{} `json:"background"`
Banner string `json:"banner"`
BroadcasterLanguage string `json:"broadcaster_language"`
CreatedAt string `json:"created_at"`
Delay interface{} `json:"delay"`
DisplayName string `json:"display_name"`
Followers int `json:"followers"`
Game string `json:"game"`
Language string `json:"language"`
Logo string `json:"logo"`
Mature bool `json:"mature"`
Name string `json:"name"`
Partner bool `json:"partner"`
ProfileBanner string `json:"profile_banner"`
ProfileBannerBackgroundColor string `json:"profile_banner_background_color"`
Status string `json:"status"`
UpdatedAt string `json:"updated_at"`
URL string `json:"url"`
VideoBanner string `json:"video_banner"`
Views int `json:"views"`
} `json:"channel"`
CreatedAt string `json:"created_at"`
Delay int `json:"delay"`
Game string `json:"game"`
IsPlaylist bool `json:"is_playlist"`
Preview struct {
Large string `json:"large"`
Medium string `json:"medium"`
Small string `json:"small"`
Template string `json:"template"`
} `json:"preview"`
VideoHeight int `json:"video_height"`
Viewers int `json:"viewers"`
} `json:"stream"`
}
var (
twitch = map[string]bool{
"rocketbeanstv": false,
"scnr_onair": false,
"starcitizen": false,
"crash_academy": false,
"cigcommunity": false,
"isfa_live": false,
"blizzard": false,
"ea": false,
"warcraft": false,
"starcraft": false,
"bobross": false,
}
twitchapiurlstreams = "https://api.twitch.tv/kraken/streams/"
twitchapiurlchannels = "https://api.twitch.tv/kraken/channels/"
)
func init() {
MsgHandlers["twitch"] = twitchHandleMessage
log.Println("Initializing twitch module")
go pollStreamData()
}
func twitchHandleMessage(m *irc.Message) {
tok := strings.Split(m.Trailing, " ")
if len(tok) < 1 {
return
}
switch strings.ToLower(tok[0]) {
case "!twitch":
switch len(tok) {
case 1:
onlinestreams := 0
for streamname, _ := range twitch {
var so TwitchStreamObject
var co TwitchChannelObject
so = getTwitchStreamObject(streamname)
if so.Stream.Game != "" {
onlinestreams++
co = getTwitchChannelObject(streamname)
twitchSendMsg(co, so)
twitch[streamname] = true
} else {
twitch[streamname] = false
}
}
if onlinestreams == 0 {
SayCh <- fmt.Sprintf("*\n%s", "[TWTCH] All streams offline")
}
case 2:
streamname := tok[1]
var so TwitchStreamObject
var co TwitchChannelObject
so = getTwitchStreamObject(streamname)
if so.Stream.Game != "" {
co = getTwitchChannelObject(streamname)
twitchSendMsg(co, so)
} else {
SayCh <- fmt.Sprintf("*\n%s", "[TWTCH] "+streamname+" not found or offline")
}
default:
}
default:
}
}
func pollStreamData() {
time.Sleep(10 * time.Second)
for {
for streamname, _ := range twitch {
var so TwitchStreamObject
var co TwitchChannelObject
so = getTwitchStreamObject(streamname)
if so.Stream.Game != "" && !twitch[streamname] {
co = getTwitchChannelObject(streamname)
twitchSendMsg(co, so)
twitch[streamname] = true
} else if so.Stream.Game == "" && twitch[streamname] {
twitch[streamname] = false
}
}
time.Sleep(180 * time.Second)
}
}
func getTwitchStreamObject(streamname string) TwitchStreamObject {
twsurl := twitchapiurlstreams + streamname
var tobj TwitchStreamObject
resp, err := http.Get(twsurl)
if err != nil {
log.Println(err)
} else {
reader, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
} else {
defer resp.Body.Close()
json.Unmarshal(reader, &tobj)
return tobj
}
}
return tobj
}
func getTwitchChannelObject(streamname string) TwitchChannelObject {
twcurl := twitchapiurlchannels + streamname
var tcobj TwitchChannelObject
resp2, err := http.Get(twcurl)
if err != nil {
log.Println(err)
} else {
reader2, err := ioutil.ReadAll(resp2.Body)
if err != nil {
log.Println(err)
} else {
defer resp2.Body.Close()
json.Unmarshal(reader2, &tcobj)
return tcobj
}
}
return tcobj
}
func twitchSendMsg(tcobj TwitchChannelObject, tso TwitchStreamObject) {
SayCh <- fmt.Sprintf("*\n%s", "[TWTCH] "+tso.Stream.Channel.DisplayName+", "+util.NumberToString(tso.Stream.Viewers, '.')+" viewers, playing: "+tso.Stream.Game+", "+tcobj.URL)
SayCh <- fmt.Sprintf("*\n%s", "[TWTCH] "+"Title: \""+tcobj.Status+"\"")
}