diff --git a/cmd/nourybot/commands.go b/cmd/nourybot/commands.go index 839a858..8c884de 100644 --- a/cmd/nourybot/commands.go +++ b/cmd/nourybot/commands.go @@ -130,7 +130,7 @@ func (app *application) handleCommand(message twitch.PrivateMessage) { } case "offline": if userLevel >= 100 { - //reply = app.createFollowSubscription(target, cmdParams[2]) + reply = app.createOfflineSubscription(target, cmdParams[2]) } } case "unnotify": @@ -139,6 +139,10 @@ func (app *application) handleCommand(message twitch.PrivateMessage) { if userLevel >= 100 { reply = app.deleteLiveSubscription(target, cmdParams[2]) } + case "offline": + if userLevel >= 100 { + reply = app.deleteOfflineSubscription(target, cmdParams[2]) + } } case "ddg": diff --git a/cmd/nourybot/eventsub.go b/cmd/nourybot/eventsub.go index 6fbdcdc..ced2744 100644 --- a/cmd/nourybot/eventsub.go +++ b/cmd/nourybot/eventsub.go @@ -90,7 +90,122 @@ func (app *application) deleteLiveSubscription(target, channel string) string { if len(resp.Data.EventSubSubscriptions) == 0 { return "No such subscription found" } - eventSubID := resp.Data.EventSubSubscriptions[0].ID + + // Since we can't pass more than one variable to the api call we loop + // over all the resp.Data.EventSubSubscriptions we get back and check + // which one has the type we want for this event. Then use this ones ID. + var eventSubID string + for i := 0; i < len(resp.Data.EventSubSubscriptions); i++ { + if resp.Data.EventSubSubscriptions[i].Type == "stream.online" { + eventSubID = resp.Data.EventSubSubscriptions[i].ID + } + } + //eventSubID := resp.Data.EventSubSubscriptions[0].ID + //app.SendNoContext("nouryxd", eventSubID) + + resp2, err := client.RemoveEventSubSubscription(eventSubID) + if err != nil { + app.Log.Errorw("Error getting EventSub subscriptions", + "resp", resp, + "err", err, + ) + return "Something went wrong FeelsBadMan" + } + + if resp2.StatusCode != eventSubResponseNoContent { + return "Subscription was not found FeelsBadMan" + } + + app.Log.Infof("%+v\n", resp2) + return fmt.Sprintf("Successfully deleted live notification for channel %s; id=%v", channel, uid) +} + +func (app *application) createOfflineSubscription(target, channel string) string { + // client, err := helix.NewClient(&helix.Options{ + // ClientID: app.Config.twitchClientId, + // AppAccessToken: app.HelixClient.GetAppAccessToken(), + // }) + // if err != nil { + // app.Log.Errorw("Error creating new helix client", + // "err", err, + // ) + // } + + uid := ivr.IDByUsername(channel) + if uid == "xd" { + return fmt.Sprintf("Could not find user with name %v", channel) + } + + resp, err := app.HelixClient.CreateEventSubSubscription(&helix.EventSubSubscription{ + Type: helix.EventSubTypeStreamOffline, + Version: "1", + Condition: helix.EventSubCondition{ + BroadcasterUserID: uid, + }, + Transport: helix.EventSubTransport{ + Method: "webhook", + Callback: "https://bot.noury.li/eventsub", + Secret: app.Config.eventSubSecret, + }, + }) + if err != nil { + app.Log.Errorw("Error creating EventSub subscription", + "resp", resp, + "err", err, + ) + } + + app.Log.Infof("%+v\n", resp) + return fmt.Sprintf("Created offline subscription for channel %v; uid=%v", channel, uid) +} + +func (app *application) deleteOfflineSubscription(target, channel string) string { + client, err := helix.NewClient(&helix.Options{ + ClientID: app.Config.twitchClientId, + AppAccessToken: app.HelixClient.GetAppAccessToken(), + }) + if err != nil { + app.Log.Errorw("Error creating new helix client", + "err", err, + ) + } + + uid := ivr.IDByUsername(channel) + if uid == "xd" { + return fmt.Sprintf("Could not find user with name %v", channel) + } + + resp, err := client.GetEventSubSubscriptions(&helix.EventSubSubscriptionsParams{ + UserID: uid, + }) + if err != nil { + app.Log.Errorw("Error getting EventSub subscriptions", + "resp", resp, + "err", err, + ) + return "Something went wrong FeelsBadMan" + } + + app.Log.Infof("%+v\n", resp) + + if resp.StatusCode != eventSubResponseOK { + return "Subscription was not found FeelsBadMan" + } + if len(resp.Data.EventSubSubscriptions) == 0 { + return "No such subscription found" + } + + // Since we can't pass more than one variable to the api call we loop + // over all the resp.Data.EventSubSubscriptions we get back and check + // which one has the type we want for this event. Then use this ones ID. + var eventSubID string + for i := 0; i < len(resp.Data.EventSubSubscriptions); i++ { + if resp.Data.EventSubSubscriptions[i].Type == "stream.offline" { + eventSubID = resp.Data.EventSubSubscriptions[i].ID + } + } + //eventSubID = resp.Data.EventSubSubscriptions[0].ID + //app.SendNoContext("nouryxd", eventSubID) resp2, err := client.RemoveEventSubSubscription(eventSubID) if err != nil { diff --git a/cmd/nourybot/router.go b/cmd/nourybot/router.go index e051ca0..e5b5cd4 100644 --- a/cmd/nourybot/router.go +++ b/cmd/nourybot/router.go @@ -55,6 +55,7 @@ func (app *application) eventsubFollow(w http.ResponseWriter, r *http.Request, _ } else { log.Println("verified signature for subscription") } + var vals eventSubNotification err = json.NewDecoder(bytes.NewReader(body)).Decode(&vals) if err != nil { @@ -66,13 +67,24 @@ func (app *application) eventsubFollow(w http.ResponseWriter, r *http.Request, _ w.Write([]byte(vals.Challenge)) return } - var liveEvent helix.EventSubStreamOnlineEvent - err = json.NewDecoder(bytes.NewReader(vals.Event)).Decode(&liveEvent) - log.Printf("got stream online event webhook: %s is live\n", liveEvent.BroadcasterUserName) - w.WriteHeader(200) - w.Write([]byte("ok")) - app.SendNoContext("nouryxd", fmt.Sprintf("%s is now live!", liveEvent.BroadcasterUserName)) + switch vals.Subscription.Type { + case helix.EventSubTypeStreamOnline: + var liveEvent helix.EventSubStreamOnlineEvent + err = json.NewDecoder(bytes.NewReader(vals.Event)).Decode(&liveEvent) + log.Printf("got stream online event webhook: %s is live\n", liveEvent.BroadcasterUserName) + w.WriteHeader(200) + w.Write([]byte("ok")) + app.SendNoContext("nouryxd", fmt.Sprintf("%s went live FeelsGoodMan", liveEvent.BroadcasterUserName)) + + case helix.EventSubTypeStreamOffline: + var offlineEvent helix.EventSubStreamOfflineEvent + err = json.NewDecoder(bytes.NewReader(vals.Event)).Decode(&offlineEvent) + log.Printf("got stream online event webhook: %s is live\n", offlineEvent.BroadcasterUserName) + w.WriteHeader(200) + w.Write([]byte("ok")) + app.SendNoContext("nouryxd", fmt.Sprintf("%s went offline FeelsBadMan", offlineEvent.BroadcasterUserName)) + } } type timersRouteData struct {