diff --git a/api/api.go b/api/api.go index 20b61ca..8358ade 100644 --- a/api/api.go +++ b/api/api.go @@ -19,6 +19,7 @@ import ( "go.fifitido.net/twitch/api/games" "go.fifitido.net/twitch/api/goals" "go.fifitido.net/twitch/api/gueststar" + "go.fifitido.net/twitch/api/hypetrain" ) const HelixBaseUrl = "https://api.twitch.tv/helix" @@ -42,6 +43,7 @@ type API struct { Games *games.Games Goals *goals.Goals GuestStar *gueststar.GuestStar + Hypetrain *hypetrain.Hypetrain } func New() *API { @@ -67,5 +69,6 @@ func New() *API { Games: games.New(client, baseUrl), Goals: goals.New(client, baseUrl), GuestStar: gueststar.New(client, baseUrl), + Hypetrain: hypetrain.New(client, baseUrl), } } diff --git a/api/hypetrain/get_hypetrain_events.go b/api/hypetrain/get_hypetrain_events.go new file mode 100644 index 0000000..929f886 --- /dev/null +++ b/api/hypetrain/get_hypetrain_events.go @@ -0,0 +1,140 @@ +package hypetrain + +import ( + "context" + "encoding/json" + "net/http" + "net/url" + "time" + + "github.com/google/go-querystring/query" + "go.fifitido.net/twitch/api/types" +) + +type GetHypeTrainEventsParams struct { + + // The ID of the broadcaster that’s running the Hype Train. This ID must match the User ID in the user access token. + BroadcasterID string `url:"broadcaster_id"` + + // The maximum number of items to return per page in the response. + // The minimum page size is 1 item per page and the maximum is 100 items per page. + // The default is 1. + First *int `url:"first"` + + // The cursor used to get the next page of results. The Pagination object in the response contains the cursor’s value. + // Read More: https://dev.twitch.tv/docs/api/guide#pagination + After *types.Cursor `url:"after"` +} + +type Event struct { + // An ID that identifies this event. + ID string `json:"id"` + + // The type of event. The string is in the form, hypetrain.{event_name}. + // The request returns only progress event types (i.e., hypetrain.progression). + EventType string `json:"event_type"` + + // The UTC date and time (in RFC3339 format) that the event occurred. + EventTimestamp time.Time `json:"event_timestamp"` + + // The version number of the definition of the event’s data. + // For example, the value is 1 if the data in event_data uses the first definition of the event’s data. + Version string `json:"version"` + + // The event’s data. + EventData EventData `json:"event_data"` +} + +type EventData struct { + // The ID of the broadcaster that’s running the Hype Train. + BroadcasterID string `json:"broadcaster_id"` + + // The UTC date and time (in RFC3339 format) that another Hype Train can start. + CooldownEndTime time.Time `json:"cooldown_end_time"` + + // The UTC date and time (in RFC3339 format) that the Hype Train ends. + ExpiresAt time.Time `json:"expires_at"` + + // The value needed to reach the next level. + Goal int `json:"goal"` + + // An ID that identifies this Hype Train. + ID string `json:"id"` + + // The most recent contribution towards the Hype Train’s goal. + LastContribution Contribution `json:"last_contribution"` + + // The highest level that the Hype Train reached (the levels are 1 through 5). + Level int `json:"level"` + + // The UTC date and time (in RFC3339 format) that this Hype Train started. + StartedAt time.Time `json:"started_at"` + + // The top contributors for each contribution type. + // For example, the top contributor using BITS (by aggregate) and the top contributor using SUBS (by count). + TopContributions []Contribution `json:"top_contributions"` + + // The total amount raised. + Total int `json:"total"` +} + +type Contribution struct { + // The total amount contributed. + // + // If type is BITS, total represents the amount of Bits used. + // + // If type is SUBS, total is 500, 1000, or 2500 to represent tier 1, 2, or 3 subscriptions, respectively. + Total int `json:"total"` + + // The contribution method used. + // + // Possible values are: + // + // BITS — Cheering with Bits. + // + // SUBS — Subscription activity like subscribing or gifting subscriptions. + // + // OTHER — Covers other contribution methods not listed. + Type string `json:"type"` + + // The ID of the user that made the contribution. + User string `json:"user"` +} + +type GetHypeTrainEventsResponse struct { + // The list of Hype Train events. + // The list is empty if the broadcaster hasn’t run a Hype Train within the last 5 days. + Data []Event `json:"data"` + + // Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. + // Read More: https://dev.twitch.tv/docs/api/guide#pagination + Pagination types.Pagination `json:"pagination"` +} + +// Gets information about the broadcaster’s current or most recent Hype Train event. +// +// Instead of polling for events, consider subscribing to Hype Train events (Begin, Progress, End). +// +// Requires a user access token that includes the channel:read:hype_train scope. +func (h *Hypetrain) GetHypeTrainEvents(ctx context.Context, params *GetHypeTrainEventsParams) (*GetHypeTrainEventsResponse, error) { + v, _ := query.Values(params) + endpoint := h.baseUrl.ResolveReference(&url.URL{Path: "hypetrain/events", RawQuery: v.Encode()}) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil) + if err != nil { + return nil, err + } + + res, err := h.client.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + + var data GetHypeTrainEventsResponse + if err := json.NewDecoder(res.Body).Decode(&data); err != nil { + return nil, err + } + + return &data, nil +} diff --git a/api/hypetrain/hypetrain.go b/api/hypetrain/hypetrain.go new file mode 100644 index 0000000..cfef8f4 --- /dev/null +++ b/api/hypetrain/hypetrain.go @@ -0,0 +1,18 @@ +package hypetrain + +import ( + "net/http" + "net/url" +) + +type Hypetrain struct { + client *http.Client + baseUrl *url.URL +} + +func New(client *http.Client, baseUrl *url.URL) *Hypetrain { + return &Hypetrain{ + client: client, + baseUrl: baseUrl, + } +}