From ea90af705aab2579064437349c779dc1283e6738 Mon Sep 17 00:00:00 2001 From: Andreas Neue Date: Fri, 22 Jan 2016 23:14:28 +0100 Subject: [PATCH] sikks twitch module added. --- main.go | 5 + modules/twitch/twitch.go | 248 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 modules/twitch/twitch.go diff --git a/main.go b/main.go index fa9bb33..82e836d 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,7 @@ import ( modsaytime "flokatirc/modules/saytime" modsc "flokatirc/modules/sc" modstoll "flokatirc/modules/stoll" + modtwitch "flokatirc/modules/twitch" ) var ( @@ -73,6 +74,9 @@ func main() { if strings.Contains(*modules, "saytime") { go modsaytime.Init(sayCh) } + if strings.Contains(*modules, "twitch") { + go modtwitch.Init(sayCh) + } go func() { for { @@ -145,6 +149,7 @@ func PrivmsgHandler(s ircx.Sender, m *irc.Message) { modfortune.HandleMessage(m) modstoll.HandleMessage(m) modsaytime.HandleMessage(m) + modtwitch.HandleMessage(m) } func HandleMessage(m *irc.Message) { diff --git a/modules/twitch/twitch.go b/modules/twitch/twitch.go new file mode 100644 index 0000000..58d6c06 --- /dev/null +++ b/modules/twitch/twitch.go @@ -0,0 +1,248 @@ +// vi:ts=4:sts=4:sw=4:noet:tw=72 +// +// flokatirc twitch module +// +// Copyright (c) 2016 Daniel Aberger + +package twitch + +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 ( + sayCh chan string + 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(ch chan string) { + log.Println("Initializing twitch module") + sayCh = ch + go pollStreamData() +} + +func HandleMessage(m *irc.Message) { + tok := strings.Split(m.Trailing, " ") + if len(tok) < 1 { + return + } + switch 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+"\"") +}