Documentation
¶
Overview ¶
Package twitch is the library behind the twitch command line: an HTTP client for the public Twitch GraphQL API and the typed records every command emits.
Twitch's web app talks to one backend, a GraphQL endpoint at https://gql.twitch.tv/gql. It serves a logged-out reader with nothing but a public client id (kimne78kx3ncx6brgo4mv6wki5h1ko) and a browser user-agent, and it accepts full query strings rather than only persisted hashes. So this client POSTs JSON and decodes JSON: no cookie jar, no csrf handshake, no HTML parsing. Each surface (streams, channels, games, videos, clips, search) lives in its own file with its query builder and record mapping; this file holds the shared client.
Index ¶
- Constants
- Variables
- func Defaults(c *kit.Config)
- func Identity() kit.Identity
- func URLFor(kind, id string) string
- type Channel
- type Client
- func (c *Client) Channel(ctx context.Context, login string) (*Channel, error)
- func (c *Client) ChannelClips(ctx context.Context, login string, limit int) ([]*Clip, error)
- func (c *Client) ChannelSchedule(ctx context.Context, login string, limit int) ([]*Segment, error)
- func (c *Client) ChannelVideos(ctx context.Context, login string, limit int) ([]*Video, error)
- func (c *Client) ClearCache() error
- func (c *Client) Clip(ctx context.Context, slug string) (*Clip, error)
- func (c *Client) Directory(ctx context.Context, limit int) ([]*Game, error)
- func (c *Client) Game(ctx context.Context, slug string) (*Game, error)
- func (c *Client) GameClips(ctx context.Context, slug string, limit int) ([]*Clip, error)
- func (c *Client) GameStreams(ctx context.Context, slug string, limit int) ([]*Stream, error)
- func (c *Client) SearchChannels(ctx context.Context, query string, limit int) ([]*Channel, error)
- func (c *Client) SearchGames(ctx context.Context, query string, limit int) ([]*Game, error)
- func (c *Client) TopStreams(ctx context.Context, limit int) ([]*Stream, error)
- func (c *Client) Video(ctx context.Context, id string) (*Video, error)
- type Clip
- type Config
- type Domain
- type Game
- type Ref
- type Segment
- type Stream
- type Video
Constants ¶
const ( // DefaultDelay is the minimum gap between requests. The GraphQL endpoint is // an API rather than a page, so a half-second pace reads steadily without // leaning on it. DefaultDelay = 500 * time.Millisecond DefaultRetries = 3 DefaultTimeout = 30 * time.Second DefaultCacheTTL = 24 * time.Hour )
Defaults for the polite client.
const BaseURL = "https://" + Host
BaseURL is the root every channel, video, and category URL is built from.
const DefaultUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
DefaultUserAgent is sent with every request. Twitch serves its public GraphQL API to a normal browser; a browser User-Agent is what keeps a logged-out reader looking like one. Override it with --user-agent.
const Host = "www.twitch.tv"
Host is the Twitch hostname this client builds page URLs from and the host the URI driver in domain.go claims.
Variables ¶
var ( // ErrNotFound is a missing entity: an unknown login, a deleted video or // clip, or a bad category slug. Twitch reports these as a null top-level // field with no errors array. Exit code 6. ErrNotFound = errors.New("not found") // ErrRateLimited is a sustained HTTP 429 after the client's own retries. // Slow down with --rate. Exit code 5. ErrRateLimited = errors.New("rate limited") // ErrBlocked is a 401 or 403, or an integrity demand: Twitch declined to // serve the surface to an anonymous reader. The public read surface this CLI // uses does not normally hit this; if it does, the boundary is real and the // CLI reports it rather than trying to satisfy the demand. Exit code 4. ErrBlocked = errors.New("blocked") )
The library reports its outcomes as a few sentinel errors. domain.go's mapErr translates each into the kit error kind that carries the matching exit code, so the standalone binary and a host agree on what a wall, a throttle, and a miss mean.
Functions ¶
func Defaults ¶ added in v0.2.0
Defaults seeds the framework baseline with twitch's own values, so an unset --rate or --timeout uses the twitch default rather than the generic kit one. It is passed to kit.New via kit.WithDefaults.
Types ¶
type Channel ¶
type Channel struct {
ID string `json:"id" kit:"id"`
Login string `json:"login"`
DisplayName string `json:"display_name,omitempty"`
Description string `json:"description,omitempty" table:",truncate"`
Followers int64 `json:"followers,omitempty"`
Partner bool `json:"partner,omitempty"`
Affiliate bool `json:"affiliate,omitempty"`
Live bool `json:"live,omitempty"`
Game string `json:"game,omitempty"`
Viewers int `json:"viewers,omitempty"`
Created string `json:"created,omitempty"`
Avatar string `json:"avatar,omitempty" table:",truncate"`
URL string `json:"url"`
}
Channel is a user/channel profile.
type Client ¶
type Client struct {
HTTP *http.Client
Endpoint string
UserAgent string
ClientID string
Delay time.Duration
Retries int
// contains filtered or unexported fields
}
Client talks to the Twitch GraphQL endpoint. It paces requests, retries the transient failures, and caches response bodies on disk keyed by the query.
func ClientFromConfig ¶ added in v0.2.0
ClientFromConfig maps the framework config onto a twitch.Config and returns a client.
func (*Client) Channel ¶ added in v0.2.0
Channel returns one channel's metadata. A null user is reported as ErrNotFound.
func (*Client) ChannelClips ¶ added in v0.2.0
ChannelClips returns a channel's clips, most viewed first.
func (*Client) ChannelSchedule ¶ added in v0.2.0
ChannelSchedule returns a channel's upcoming schedule segments. The schedule connection takes no first argument, so the whole list is fetched and capped to limit. A channel with no schedule returns an empty list, not an error.
func (*Client) ChannelVideos ¶ added in v0.2.0
ChannelVideos returns a channel's past videos, most recent first.
func (*Client) ClearCache ¶ added in v0.2.0
ClearCache removes the on-disk cache.
func (*Client) Clip ¶ added in v0.2.0
Clip returns one clip by slug. A null clip is reported as ErrNotFound.
func (*Client) Directory ¶ added in v0.2.0
Directory returns the category directory, ordered by live viewers.
func (*Client) Game ¶ added in v0.2.0
Game returns one category's metadata by slug. A null game is reported as ErrNotFound.
func (*Client) GameClips ¶ added in v0.2.0
GameClips returns a category's top clips of the last week.
func (*Client) GameStreams ¶ added in v0.2.0
GameStreams returns the live streams in a category, sorted by viewers.
func (*Client) SearchChannels ¶
SearchChannels returns channels matching a query.
func (*Client) SearchGames ¶ added in v0.2.0
SearchGames returns categories matching a query.
func (*Client) TopStreams ¶ added in v0.2.0
TopStreams returns the top live streams across all categories, paginated to limit.
type Clip ¶ added in v0.2.0
type Clip struct {
Slug string `json:"slug" kit:"id"`
Title string `json:"title,omitempty" table:",truncate"`
Channel string `json:"channel,omitempty"`
Curator string `json:"curator,omitempty"`
Game string `json:"game,omitempty"`
Views int64 `json:"views,omitempty"`
Duration int `json:"duration_seconds,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
URL string `json:"url"`
}
Clip is a short user-cut highlight.
type Config ¶
type Config struct {
UserAgent string
ClientID string
// Delay is the minimum gap between requests. Zero means no pacing.
Delay time.Duration
Retries int
Timeout time.Duration
// BaseURL is the GraphQL endpoint. Empty uses the public endpoint; tests
// point it at an httptest server.
BaseURL string
// CacheDir is where GraphQL responses are cached. Empty disables the cache,
// as does NoCache.
CacheDir string
CacheTTL time.Duration
NoCache bool
// Refresh fetches fresh copies and rewrites the cache, ignoring any hit.
Refresh bool
}
Config carries the knobs the client reads. It is built from the kit framework config in ClientFromConfig, so a --rate or --timeout on the command line and the same value resolved by a host both land here.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns the baseline configuration: a browser User-Agent, the public client id, a half-second pace, three retries, a 30s timeout, and a one day cache.
type Domain ¶ added in v0.2.0
type Domain struct{}
Domain is the twitch driver. It carries no state; the per-run client is built by the factory Register hands kit.
func (Domain) Classify ¶ added in v0.2.0
Classify turns any accepted input into the canonical (type, id), so `ant resolve` and `ant url` touch no network.
func (Domain) Info ¶ added in v0.2.0
func (Domain) Info() kit.DomainInfo
Info describes the scheme, the hostnames a pasted link is matched against, and the identity reused for the binary's help and version.
type Game ¶ added in v0.2.0
type Game struct {
ID string `json:"id" kit:"id"`
Name string `json:"name"`
Slug string `json:"slug,omitempty"`
DisplayName string `json:"display_name,omitempty"`
Viewers int `json:"viewers,omitempty"`
URL string `json:"url"`
}
Game is a category (Twitch's GraphQL type is Game; the UI calls them categories).
type Ref ¶ added in v0.2.0
type Ref struct {
Input string `json:"input"`
Kind string `json:"kind"`
ID string `json:"id"`
URL string `json:"url"`
}
Ref is the result of `twitch ref id`: the canonical (kind, id) a reference resolves to, plus the live URL, all without touching the network.
type Segment ¶ added in v0.2.0
type Segment struct {
ID string `json:"id" kit:"id"`
Title string `json:"title,omitempty" table:",truncate"`
Category string `json:"category,omitempty"`
StartAt string `json:"start_at,omitempty"`
EndAt string `json:"end_at,omitempty"`
Canceled bool `json:"canceled,omitempty"`
}
Segment is one entry in a channel's stream schedule.
type Stream ¶
type Stream struct {
ID string `json:"id" kit:"id"`
Channel string `json:"channel"`
DisplayName string `json:"display_name,omitempty"`
Title string `json:"title,omitempty" table:",truncate"`
Game string `json:"game,omitempty"`
GameSlug string `json:"game_slug,omitempty"`
Viewers int `json:"viewers"`
Language string `json:"language,omitempty"`
Mature bool `json:"mature,omitempty"`
StartedAt string `json:"started_at,omitempty"`
URL string `json:"url"`
}
Stream is a live broadcast happening now.
type Video ¶ added in v0.2.0
type Video struct {
ID string `json:"id" kit:"id"`
Title string `json:"title,omitempty" table:",truncate"`
Channel string `json:"channel,omitempty"`
DisplayName string `json:"display_name,omitempty"`
Game string `json:"game,omitempty"`
Views int64 `json:"views,omitempty"`
Length int `json:"length_seconds,omitempty"`
PublishedAt string `json:"published_at,omitempty"`
URL string `json:"url"`
}
Video is a past broadcast or upload (a VOD).