twitch

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 14, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

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

View Source
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.

View Source
const BaseURL = "https://" + Host

BaseURL is the root every channel, video, and category URL is built from.

View Source
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.

View Source
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

View Source
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

func Defaults(c *kit.Config)

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.

func Identity added in v0.2.0

func Identity() kit.Identity

Identity is the fixed description of the twitch CLI, shared by the domain and the standalone composition root so help and version read the same everywhere.

func URLFor added in v0.2.0

func URLFor(kind, id string) string

URLFor builds the canonical Twitch URL for a (kind, id) pair.

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

func ClientFromConfig(cfg kit.Config) *Client

ClientFromConfig maps the framework config onto a twitch.Config and returns a client.

func NewClient

func NewClient(cfg Config) *Client

NewClient builds a client from cfg.

func (*Client) Channel added in v0.2.0

func (c *Client) Channel(ctx context.Context, login string) (*Channel, error)

Channel returns one channel's metadata. A null user is reported as ErrNotFound.

func (*Client) ChannelClips added in v0.2.0

func (c *Client) ChannelClips(ctx context.Context, login string, limit int) ([]*Clip, error)

ChannelClips returns a channel's clips, most viewed first.

func (*Client) ChannelSchedule added in v0.2.0

func (c *Client) ChannelSchedule(ctx context.Context, login string, limit int) ([]*Segment, error)

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

func (c *Client) ChannelVideos(ctx context.Context, login string, limit int) ([]*Video, error)

ChannelVideos returns a channel's past videos, most recent first.

func (*Client) ClearCache added in v0.2.0

func (c *Client) ClearCache() error

ClearCache removes the on-disk cache.

func (*Client) Clip added in v0.2.0

func (c *Client) Clip(ctx context.Context, slug string) (*Clip, error)

Clip returns one clip by slug. A null clip is reported as ErrNotFound.

func (*Client) Directory added in v0.2.0

func (c *Client) Directory(ctx context.Context, limit int) ([]*Game, error)

Directory returns the category directory, ordered by live viewers.

func (*Client) Game added in v0.2.0

func (c *Client) Game(ctx context.Context, slug string) (*Game, error)

Game returns one category's metadata by slug. A null game is reported as ErrNotFound.

func (*Client) GameClips added in v0.2.0

func (c *Client) GameClips(ctx context.Context, slug string, limit int) ([]*Clip, error)

GameClips returns a category's top clips of the last week.

func (*Client) GameStreams added in v0.2.0

func (c *Client) GameStreams(ctx context.Context, slug string, limit int) ([]*Stream, error)

GameStreams returns the live streams in a category, sorted by viewers.

func (*Client) SearchChannels

func (c *Client) SearchChannels(ctx context.Context, query string, limit int) ([]*Channel, error)

SearchChannels returns channels matching a query.

func (*Client) SearchGames added in v0.2.0

func (c *Client) SearchGames(ctx context.Context, query string, limit int) ([]*Game, error)

SearchGames returns categories matching a query.

func (*Client) TopStreams added in v0.2.0

func (c *Client) TopStreams(ctx context.Context, limit int) ([]*Stream, error)

TopStreams returns the top live streams across all categories, paginated to limit.

func (*Client) Video added in v0.2.0

func (c *Client) Video(ctx context.Context, id string) (*Video, error)

Video returns one video by id. A null video is reported as ErrNotFound.

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

func (Domain) Classify(input string) (uriType, id string, err error)

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.

func (Domain) Locate added in v0.2.0

func (Domain) Locate(uriType, id string) (string, error)

Locate is the inverse: the live https URL for a (type, id).

func (Domain) Register added in v0.2.0

func (Domain) Register(app *kit.App)

Register installs the client factory and every operation onto app. A resolver op (Single) names its own record type and answers `ant get`; a List op enumerates a parent resource's members and answers `ant ls`.

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.

func Classify added in v0.2.0

func Classify(ref string) Ref

Classify reads a reference (a URL, a path, an @handle, or a bare id) and reports what it points at. Kind is one of channel, game, video, clip, or unknown.

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).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL