Skip to content

Commit

Permalink
TwitchBee now emits events for new followers
Browse files Browse the repository at this point in the history
  • Loading branch information
muesli committed Apr 12, 2020
1 parent 1bddeb5 commit ebc141c
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 16 deletions.
106 changes: 91 additions & 15 deletions bees/twitchbee/twitchbee.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"time"

twitch "github.com/gempir/go-twitch-irc/v2"
"github.com/nicklaw5/helix"

"github.com/muesli/beehive/bees"
)
Expand All @@ -38,11 +39,14 @@ type TwitchBee struct {
connectedState chan bool

// setup Twitch client:
client *twitch.Client
chat *twitch.Client
client *helix.Client
channels []string

username string
password string

clientId string
}

// Action triggers the action passed to it.
Expand All @@ -65,15 +69,15 @@ func (mod *TwitchBee) Action(action bees.Action) []bees.Placeholder {
if recv == "*" {
// special: send to all joined channels
for _, to := range mod.channels {
mod.client.Say(to, text)
mod.chat.Say(to, text)
}
} else {
// needs stripping hostname when sending to user!host
if strings.Index(recv, "!") > 0 {
recv = recv[0:strings.Index(recv, "!")]
}

mod.client.Say(recv, text)
mod.chat.Say(recv, text)
}
}

Expand All @@ -99,20 +103,20 @@ func (mod *TwitchBee) Action(action bees.Action) []bees.Placeholder {

func (mod *TwitchBee) rejoin() {
for _, channel := range mod.channels {
mod.client.Join(channel)
mod.chat.Join(channel)
}
}

func (mod *TwitchBee) join(channel string) {
channel = strings.TrimSpace(channel)
mod.client.Join(channel)
mod.chat.Join(channel)

mod.channels = append(mod.channels, channel)
}

func (mod *TwitchBee) part(channel string) {
channel = strings.TrimSpace(channel)
mod.client.Depart(channel)
mod.chat.Depart(channel)

for k, v := range mod.channels {
if v == channel {
Expand All @@ -122,19 +126,80 @@ func (mod *TwitchBee) part(channel string) {
}
}

func (mod *TwitchBee) monitorFollows(eventChan chan bees.Event) {
var twitchId string
{
resp, err := mod.client.GetUsers(&helix.UsersParams{
Logins: []string{mod.username},
})
if err != nil || len(resp.Data.Users) != 1 {
mod.LogErrorf("Failed retrieving user info from Twitch API: %v", err)
}
twitchId = resp.Data.Users[0].ID
}

follows := make(map[string]helix.UserFollow)
var seeded bool
for {
var pagination string
for {
resp, err := mod.client.GetUsersFollows(&helix.UsersFollowsParams{
After: pagination,
First: 40,
ToID: twitchId,
})
if err != nil {
mod.LogErrorf("Failed retrieving follows from Twitch API: %v", err)
break
}
pagination = resp.Data.Pagination.Cursor

for _, f := range resp.Data.Follows {
if _, ok := follows[f.FromID]; !ok {
follows[f.FromID] = f

if seeded {
ev := bees.Event{
Bee: mod.Name(),
Name: "follow",
Options: []bees.Placeholder{
{
Name: "user",
Type: "string",
Value: f.FromName,
},
},
}
eventChan <- ev
}
}
}

if len(resp.Data.Follows) == 0 || pagination == "" {
// end of paginated list
seeded = true
break
}
}

// poll once a minute
time.Sleep(30 * time.Second)
}
}

// Run executes the Bee's event loop.
func (mod *TwitchBee) Run(eventChan chan bees.Event) {
// channel signaling Twitch connection status
mod.connectedState = make(chan bool)

// setup Twitch client:
mod.client = twitch.NewClient(mod.username, mod.password)
// setup Twitch c:
mod.chat = twitch.NewClient(mod.username, mod.password)

mod.client.OnConnect(func() {
mod.chat.OnConnect(func() {
mod.connectedState <- true
})

mod.client.OnUserJoinMessage(func(msg twitch.UserJoinMessage) {
mod.chat.OnUserJoinMessage(func(msg twitch.UserJoinMessage) {
ev := bees.Event{
Bee: mod.Name(),
Name: "join",
Expand All @@ -153,7 +218,7 @@ func (mod *TwitchBee) Run(eventChan chan bees.Event) {
}
eventChan <- ev
})
mod.client.OnUserPartMessage(func(msg twitch.UserPartMessage) {
mod.chat.OnUserPartMessage(func(msg twitch.UserPartMessage) {
ev := bees.Event{
Bee: mod.Name(),
Name: "part",
Expand All @@ -173,7 +238,7 @@ func (mod *TwitchBee) Run(eventChan chan bees.Event) {
eventChan <- ev
})

mod.client.OnPrivateMessage(func(msg twitch.PrivateMessage) {
mod.chat.OnPrivateMessage(func(msg twitch.PrivateMessage) {
ev := bees.Event{
Bee: mod.Name(),
Name: "message",
Expand Down Expand Up @@ -201,10 +266,20 @@ func (mod *TwitchBee) Run(eventChan chan bees.Event) {
connected := false
mod.ContextSet("connected", &connected)

mod.rejoin()
var err error
mod.client, err = helix.NewClient(&helix.Options{
ClientID: mod.clientId,
})
if err != nil {
mod.LogErrorf("Failed connecting to Twitch API: %v", err)
return
}
go mod.monitorFollows(eventChan)

go func() {
mod.Logln("Connecting to Twitch")
err := mod.client.Connect()
mod.rejoin()
err := mod.chat.Connect()
if err != nil {
mod.LogErrorf("Failed to connect to Twitch: %v", err)
}
Expand All @@ -222,7 +297,7 @@ func (mod *TwitchBee) Run(eventChan chan bees.Event) {
}

case <-mod.SigChan:
mod.client.Disconnect()
mod.chat.Disconnect()
return

default:
Expand All @@ -235,6 +310,7 @@ func (mod *TwitchBee) Run(eventChan chan bees.Event) {
func (mod *TwitchBee) ReloadOptions(options bees.BeeOptions) {
mod.SetOptions(options)

options.Bind("client_id", &mod.clientId)
options.Bind("username", &mod.username)
options.Bind("password", &mod.password)
options.Bind("channels", &mod.channels)
Expand Down
18 changes: 18 additions & 0 deletions bees/twitchbee/twitchbeefactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ func (factory *TwitchBeeFactory) LogoColor() string {
// Options returns the options available to configure this Bee.
func (factory *TwitchBeeFactory) Options() []bees.BeeOptionDescriptor {
opts := []bees.BeeOptionDescriptor{
{
Name: "client_id",
Description: "Your Twitch Client ID",
Type: "string",
Mandatory: true,
},
{
Name: "username",
Description: "Your Twitch username",
Expand Down Expand Up @@ -130,6 +136,18 @@ func (factory *TwitchBeeFactory) Events() []bees.EventDescriptor {
},
},
},
{
Namespace: factory.Name(),
Name: "follow",
Description: "A user followed you",
Options: []bees.PlaceholderDescriptor{
{
Name: "user",
Description: "The user that followed you",
Type: "string",
},
},
},
{
Namespace: factory.Name(),
Name: "join",
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ require (
github.com/muesli/goefa v0.0.0-20180507204150-08d8ee2555d2
github.com/muesli/kmeans v0.0.0-20190917235210-80dfc71e6c5a // indirect
github.com/muesli/smolder v0.0.0-20190505085143-9c21fc7135ee
github.com/nicklaw5/helix v0.5.7
github.com/nlopes/slack v0.6.0
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d
github.com/odwrtw/transmission v0.0.0-20170515140915-08885b3058e7
Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 h1:GOfMz6cRgTJ9jWV0qAezv642OhPnKEG7gtUjJSdStHE=
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17/go.mod h1:HfkOCN6fkKKaPSAeNq/er3xObxTW4VLeY6UUK895gLQ=
github.com/gempir/go-twitch-irc v1.1.0 h1:Q9gQGI/3yJzYwlYDlFsGJzWfpaqubMExfmBXNpOC6W0=
github.com/gempir/go-twitch-irc/v2 v2.2.2 h1:uzinel2qApXL1UVfr3QcZ3dJsf+YU+PaUp0qJk03qNo=
github.com/gempir/go-twitch-irc/v2 v2.2.2/go.mod h1:0HXoEr9l7gNjwajosptV0w0xGpHeU6gsD7JDlfvjTYI=
github.com/gigawattio/window v0.0.0-20180317192513-0f5467e35573 h1:u8AQ9bPa9oC+8/A/jlWouakhIvkFfuxgIIRjiy8av7I=
Expand Down Expand Up @@ -170,6 +169,8 @@ github.com/muesli/kmeans v0.0.0-20190917235210-80dfc71e6c5a h1:TfqSfRTR/uTo2h3Af
github.com/muesli/kmeans v0.0.0-20190917235210-80dfc71e6c5a/go.mod h1:DchXqcxIXcInFMlUlAAcmjNYiDEPoIQQdDxlWlELyxM=
github.com/muesli/smolder v0.0.0-20190505085143-9c21fc7135ee h1:owp+45s+e2xN1fFUHIld1X+2ZtHSUjXKkgEr7iwq7u8=
github.com/muesli/smolder v0.0.0-20190505085143-9c21fc7135ee/go.mod h1:vBtOJlVGxLheofBQdKVQGaG40aJQUwr6Lh4PVliqebY=
github.com/nicklaw5/helix v0.5.7 h1:DvNyoKkuLYrqZv5/yugL18Ud99UeQoXzzAsg4OwU8uY=
github.com/nicklaw5/helix v0.5.7/go.mod h1:nRcok4VLg8ONQYW/iXBZ24wcfiJjTlDbhgk0ZatOrUY=
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
Expand Down

0 comments on commit ebc141c

Please sign in to comment.