youtube

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 6, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

Package youtube performs YouTube extraction: it turns a URL into video metadata and candidate audio formats, and resolves those formats into playable, signed stream URLs.

Stability: this package and everything beneath it, notably the internal resolver, are YouTube-specific implementation surfaces. They are exported for the facade where needed but may change between releases. External users should prefer the top-level waxtap package.

Concurrency and identity: a ClientProfile is immutable, with headers cloned on read. Mutable per-attempt state lives in an unexported session, so concurrent extractions do not share writable client identity.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractPlaylistID

func ExtractPlaylistID(input string) (string, error)

ExtractPlaylistID extracts a playlist ID from a bare ID or a URL carrying a list= parameter.

func ExtractVideoID

func ExtractVideoID(input string) (string, error)

ExtractVideoID extracts an 11-character video ID from a bare ID or any common YouTube URL form (watch?v=, youtu.be/, /embed/, /shorts/, /v/, /live/), including scheme-less inputs.

A playlist-only URL (a list= parameter or /playlist path with no video) returns ErrIsPlaylist so the caller can route it to Enumerate. Inputs that carry a candidate of the wrong shape return ErrInvalidVideoID; inputs too short to contain an ID return ErrVideoIDTooShort.

Types

type Chapter

type Chapter struct {
	Title string
	Start time.Duration
}

Chapter marks a titled section start within the video.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client performs YouTube extraction. It holds configuration and injected dependencies, while mutable per-attempt identity lives in session. It is safe for concurrent use after construction.

func New

func New(cfg Config) *Client

New returns a Client, applying defaults for unset Config fields.

func (*Client) Enumerate

func (c *Client) Enumerate(ctx context.Context, playlistID string, maxItems int) (*Playlist, error)

Enumerate expands a playlist into lightweight entries without downloading. It pages through continuations until exhausted or maxItems (<= 0 means all) is reached. Per-page failures after the first page are collected in Playlist.Errors rather than discarding the entries already gathered.

func (*Client) Extract

func (c *Client) Extract(ctx context.Context, videoID string) (*Extraction, error)

Extract fetches metadata and candidate audio formats for videoID, trying the client strategy chain in order until one succeeds. Each attempt uses an immutable profile and a shared per-extraction session; the winning profile and session are carried in the returned Extraction so stream resolution uses the same identity.

func (*Client) Info

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

Info returns just the video metadata and candidate formats.

func (*Client) Resolve

func (c *Client) Resolve(ctx context.Context, ext *Extraction, formatIndex int) (ResolvedStream, error)

Resolve turns the candidate at formatIndex, an index into Extraction.Video().Formats, into a playable signed stream. It reuses the client profile and session that won extraction so the media URL is resolved under the same YouTube identity.

Resolution is index-based rather than itag-based because itags can repeat across languages and DRC variants. rawAudio[i] is kept parallel to Video.Formats[i] so the selected public format maps to the right raw format.

func (*Client) ResolveWithFailure

func (c *Client) ResolveWithFailure(ctx context.Context, ext *Extraction, formatIndex int, failure *potoken.HTTPFailure) (ResolvedStream, error)

ResolveWithFailure resolves the selected format like Resolve and passes the HTTP failure that caused a refresh to the PO-token provider. Initial resolution passes nil. When refreshing an expired signed URL, call this with a fresh Extraction; the old player response still contains the old URL.

type ClientProfile

type ClientProfile struct {
	Name          string // internal name, e.g. "ANDROID_VR"
	InnerTubeName string // InnerTube context clientName, e.g. "ANDROID_VR"
	InnerTubeID   int    // drives X-Youtube-Client-Name (never hardcoded)
	Version       string
	APIKey        string
	UserAgent     string

	// Device and OS fields sent in the InnerTube client context. Mobile and VR
	// clients need these populated; sparse identities are more likely to hit the
	// bot-check path. Zero values are omitted from the request.
	DeviceMake        string
	DeviceModel       string
	OSName            string
	OSVersion         string
	AndroidSDKVersion int

	// RequiresPOTokens lists the PO-token scopes this client must supply: a
	// player-scope token in the /player body, a GVS token on the stream URL,
	// or both. Empty means none. NewClientProfile clones and canonicalizes
	// the slice.
	RequiresPOTokens  []potoken.Scope
	SupportsCookies   bool
	SupportsPlaylists bool
	// contains filtered or unexported fields
}

ClientProfile identifies an InnerTube client such as ANDROID_VR, iOS, or WEB. The header map is unexported and every accessor returns a clone, so callers cannot mutate a profile after construction.

func BuildProfile

func BuildProfile(base ClientProfile) ClientProfile

BuildProfile derives the static InnerTube request headers from base and returns an isolated profile. Use it for configured profiles so headers such as X-Youtube-Client-Name stay tied to the scalar client identity.

func DefaultProfiles

func DefaultProfiles() []ClientProfile

DefaultProfiles returns the ordered client strategy chain using the default built-in Chrome identity. ANDROID_VR leads because it usually returns direct URLs without a PO token; the embedded and WEB clients cover fallback cases.

func NewClientProfile

func NewClientProfile(base ClientProfile, headers map[string]string) ClientProfile

NewClientProfile returns base with headers deep-copied in, yielding a profile that owns an isolated header map callers cannot mutate.

func (ClientProfile) Header

func (p ClientProfile) Header(key string) string

Header returns a single header value.

func (ClientProfile) Headers

func (p ClientProfile) Headers() map[string]string

Headers returns a copy of the profile's headers; mutating the result does not affect the profile.

func (ClientProfile) WithHeader

func (p ClientProfile) WithHeader(key, value string) ClientProfile

WithHeader returns a copy of the profile with key set to value; the receiver is unchanged.

type Config

type Config struct {
	// HTTP is the retrying HTTP client. If nil, a default httpx.Client is used.
	HTTP *httpx.Client
	// Logger receives debug logs. If nil, logging is discarded.
	Logger *slog.Logger
	// Profiles overrides the client strategy chain. If empty, DefaultProfiles().
	Profiles []ClientProfile
	// ChromeMajor overrides the emulated Chrome major for built-in WEB-family
	// identities. It applies to the default profile chain and to built-in WEB
	// requests used for discovery and fallbacks. Zero selects the built-in
	// default. Caller-supplied Profiles are unchanged.
	ChromeMajor int
	// Resolver resolves candidate formats into playable URLs. If nil, New builds
	// a default base.js/goja resolver over the same HTTP client. Metadata
	// extraction does not need one; stream resolution (Resolve) does.
	Resolver resolver.Resolver
	// POTokenProvider supplies PO tokens when a profile requires one. WaxTap may
	// call it during extraction for a player-scope token and during resolution for
	// a GVS-scope stream token. Nil means no provider is configured.
	POTokenProvider potoken.Provider
	// ResolveTimeout bounds each cipher JS execution during resolution. Zero
	// uses the resolver default.
	ResolveTimeout time.Duration
	// CacheDir is the base directory for on-disk caches. When set, and when
	// DisableDiskCache is false, the default resolver stores base.js source under
	// CacheDir/players. Empty leaves the resolver memory-only. Ignored when a
	// Resolver is injected.
	CacheDir string
	// DisableDiskCache turns off the on-disk base.js source cache even when
	// CacheDir is set.
	DisableDiskCache bool
	// HL (host language, e.g. "en") and GL (content region, e.g. "US") set the
	// InnerTube locale. Empty defaults to en / US. These are localization hints:
	// geo-restricted availability is still governed by the request IP.
	HL string
	GL string
}

Config configures a Client.

type Extraction

type Extraction struct {
	// contains filtered or unexported fields
}

Extraction is the result of a successful extract: the video plus the opaque context (which client profile and session won) needed to resolve and download in the same identity. Its internals are unexported, so the facade holds it as an opaque handle and passes it back into resolve/download without reaching in.

func (*Extraction) Video

func (e *Extraction) Video() *Video

Video returns the extracted metadata and candidate formats.

type Playlist

type Playlist struct {
	ID           string
	Title        string
	Author       string
	Entries      []PlaylistEntry
	Errors       []error // per-entry failures (partial enumeration is not fatal)
	Continuation string  // opaque token for the next page; "" when exhausted
}

Playlist is the result of enumerating a playlist URL. Enumeration is tolerant: one bad entry is collected in Errors rather than failing the list.

type PlaylistEntry

type PlaylistEntry struct {
	VideoID  string
	Title    string
	Author   string
	Duration time.Duration
	Index    int // 0-based position within the playlist
}

PlaylistEntry is a lightweight playlist item. Enumeration does not download media, and full per-video metadata enrichment is opt-in.

type ResolvedStream

type ResolvedStream struct {
	URL           string
	ExpiresAt     time.Time
	ContentLength int64
	Headers       http.Header
}

ResolvedStream is a resolved, playable stream URL with the metadata needed to fetch it. youtube owns this type: resolver.Stream is mapped into it by the youtube package, and download.Source is mapped from it by the facade.

type Thumbnail

type Thumbnail struct {
	URL    string
	Width  int
	Height int
}

Thumbnail is one cover-art candidate.

type Video

type Video struct {
	ID          string
	Title       string
	Author      string // channel / uploader name
	ChannelID   string
	Duration    time.Duration
	PublishDate time.Time
	Description string

	Thumbnails []Thumbnail // candidates for cover art
	Chapters   []Chapter

	Formats []format.Format // candidate audio (and incidental video) formats

	IsLive     bool // currently live
	IsUpcoming bool // scheduled premiere / upcoming
}

Video is the extracted metadata model. YouTube exposes channel metadata rather than authoritative artist tags, so WaxTap returns the raw fields and leaves tagging policy to the caller.

Directories

Path Synopsis
internal
resolver
Package resolver isolates YouTube's most volatile surface: discovering the player JS (base.js), solving the signature and n-parameter transforms, and building a playable, signed stream URL.
Package resolver isolates YouTube's most volatile surface: discovering the player JS (base.js), solving the signature and n-parameter transforms, and building a playable, signed stream URL.

Jump to

Keyboard shortcuts

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