package twitch import ( "context" "fmt" "net/http" "net/url" "strconv" "time" "github.com/mitchellh/hashstructure/v2" ) type ( // GetVideoOpts contain the query parameter for the GetVideos query // // See https://dev.twitch.tv/docs/api/reference/#get-videos for details GetVideoOpts struct { ID string // Required: Exactly one of ID, UserID, GameID UserID string // Required: Exactly one of ID, UserID, GameID GameID string // Required: Exactly one of ID, UserID, GameID Language string // Optional: Use only with GameID Period GetVideoOptsPeriod // Optional: Use only with GameID or UserID Sort GetVideoOptsSort // Optional: Use only with GameID or UserID Type GetVideoOptsType // Optional: Use only with GameID or UserID First int64 // Optional: Use only with GameID or UserID After string // Optional: Use only with UserID Before string // Optional: Use only with UserID } // GetVideoOptsPeriod represents a filter used to filter the list of // videos by when they were published GetVideoOptsPeriod string // GetVideoOptsSort represents the order to sort the returned videos in GetVideoOptsSort string // GetVideoOptsType represents a filter used to filter the list of // videos by the video's type GetVideoOptsType string // Video contains information about a published video Video struct { ID string `json:"id"` StreamID *string `json:"stream_id"` UserID string `json:"user_id"` UserLogin string `json:"user_login"` UserName string `json:"user_name"` Title string `json:"title"` Description string `json:"description"` CreatedAt time.Time `json:"created_at"` PublishedAt time.Time `json:"published_at"` URL string `json:"url"` ThumbnailURL string `json:"thumbnail_url"` Viewable string `json:"viewable"` ViewCount int64 `json:"view_count"` Language string `json:"language"` Type string `json:"type"` Duration string `json:"duration"` MutedSegments []struct { Duration int64 `json:"duration"` Offset int64 `json:"offset"` } `json:"muted_segments"` } ) // List of filters for GetVideoOpts.Period const ( GetVideoOptsPeriodAll GetVideoOptsPeriod = "all" GetVideoOptsPeriodDay GetVideoOptsPeriod = "day" GetVideoOptsPeriodMonth GetVideoOptsPeriod = "month" GetVideoOptsPeriodWeek GetVideoOptsPeriod = "week" ) // List of sort options for GetVideoOpts.Sort const ( GetVideoOptsSortTime GetVideoOptsSort = "time" GetVideoOptsSortTrending GetVideoOptsSort = "trending" GetVideoOptsSortViews GetVideoOptsSort = "views" ) // List of types for GetVideoOpts.Type const ( GetVideoOptsTypeAll GetVideoOptsType = "all" GetVideoOptsTypeArchive GetVideoOptsType = "archive" GetVideoOptsTypeHighlight GetVideoOptsType = "highlight" GetVideoOptsTypeUpload GetVideoOptsType = "upload" ) // GetVideos fetches information about one or more published videos func (c *Client) GetVideos(ctx context.Context, opts GetVideoOpts) (videos []Video, err error) { optsCacheKey, err := opts.cacheKey() if err != nil { return nil, fmt.Errorf("getting opts cache key: %w", err) } cacheKey := []string{"currentVideos", optsCacheKey} if vids := c.apiCache.Get(cacheKey); vids != nil { return vids.([]Video), nil } var payload struct { Data []Video `json:"data"` } if err := c.Request(ctx, ClientRequestOpts{ AuthType: AuthTypeAppAccessToken, Method: http.MethodGet, OKStatus: http.StatusOK, Out: &payload, URL: fmt.Sprintf("https://api.twitch.tv/helix/videos?%s", opts.queryParams()), }); err != nil { return nil, fmt.Errorf("requesting videos: %w", err) } // Videos can be changed at any moment, cache for a short period of time c.apiCache.Set(cacheKey, twitchMinCacheTime, payload.Data) return payload.Data, nil } func (g GetVideoOpts) cacheKey() (string, error) { h, err := hashstructure.Hash(g, hashstructure.FormatV2, nil) if err != nil { return "", fmt.Errorf("hashing opts: %w", err) } return strconv.FormatUint(h, 10), nil } func (g GetVideoOpts) queryParams() string { params := url.Values{} for k, v := range map[string]string{ "id": g.ID, "user_id": g.UserID, "game_id": g.GameID, "language": g.Language, "period": string(g.Period), "sort": string(g.Sort), "type": string(g.Type), "first": strconv.FormatInt(g.First, 10), "after": g.After, "before": g.Before, } { if v != "" && v != "0" { params.Set(k, v) } } return params.Encode() }