youtube

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Bounded in-memory memo used by the long-lived MCP server.

The point is to stop the three-tools-three-player-fetches pattern, not to be a general-purpose cache: entries are byte-bounded and evicted oldest-expiry first.

Track selection and caption download/parsing.

Channel discovery: resolve a handle/URL to a channel id, then list recent uploads from the channel's RSS feed.

RSS is the backbone because it carries exact publish timestamps. The richer `browse` grid also has duration and views but only relative times ("1 hour ago"), which cannot serve as a watermark for "what changed since last check".

Chapters are authored structure that already travels inside the description. Parsing them costs one regex pass and turns a 50-minute talk into addressable sections, which is what reading and citation plans actually need.

Innertube (youtubei) access — the same internal API the YouTube apps use.

Since mid-2025, caption track URLs handed to WEB clients require a "proof of origin" token; ANDROID and IOS client contexts still receive directly-downloadable signed URLs. We therefore cascade through ANDROID → IOS → watch-page scrape so one blocked endpoint doesn't take the whole fetch down. Stdlib only.

Package youtube acquires video metadata, captions, and channel listings from YouTube's internal endpoints. It owns the cache and the typed failure model; rendering and search live in separate packages.

Index

Constants

View Source
const (
	DefaultChannelLimit = 10
	DefaultSummaryChars = 200
)
View Source
const DefaultDescriptionChars = 500

DefaultDescriptionChars is the description excerpt used by the CLI and MCP adapter when the caller does not specify one.

View Source
const OriginalLanguageValue = "original"

OriginalLanguageValue is the sentinel an agent passes to ask for the video's own track with no machine translation.

View Source
const TotalDeadline = 45 * time.Second

TotalDeadline bounds one acquisition operation: player fetch plus caption download share it instead of each getting a fresh budget.

Variables

This section is empty.

Functions

func ExtractVideoID

func ExtractVideoID(urlOrID string) (string, error)

ExtractVideoID accepts a YouTube URL or a bare 11-character video id.

func ParseLanguages

func ParseLanguages(csv string) []string

ParseLanguages parses a comma-separated language list and defaults to "en".

func ParseSince

func ParseSince(s string) (time.Time, error)

ParseSince accepts RFC3339 or a bare date (UTC midnight).

Types

type CaptionSummary

type CaptionSummary struct {
	HasCaptions      bool     `json:"has_captions"`
	Manual           []string `json:"manual"`
	Auto             []string `json:"auto"`
	OriginalLanguage string   `json:"original_language,omitempty"`
	Translatable     bool     `json:"translatable"`
	Count            int      `json:"count"`
}

type ChannelInfo

type ChannelInfo struct {
	ID     string `json:"id"`
	Title  string `json:"title"`
	Handle string `json:"handle,omitempty"`
	URL    string `json:"url"`
}

type ChannelListing

type ChannelListing struct {
	OK              bool           `json:"ok"`
	Channel         ChannelInfo    `json:"channel"`
	Videos          []ChannelVideo `json:"videos"`
	Count           int            `json:"count"`
	Available       int            `json:"available"`
	NewestPublished string         `json:"newest_published,omitempty"`
	Truncated       bool           `json:"truncated"`
	Notes           []string       `json:"notes,omitempty"`
}

type ChannelOptions

type ChannelOptions struct {
	Limit        int
	Since        time.Time
	SummaryChars int
}

ChannelOptions are resolved at the CLI/MCP boundary: Limit 0 means "all" (the feed cap), SummaryChars 0 means "omit the description excerpt".

type ChannelVideo

type ChannelVideo struct {
	VideoID   string `json:"video_id"`
	Title     string `json:"title"`
	Published string `json:"published"` // RFC3339, UTC
	URL       string `json:"url"`
	Summary   string `json:"summary,omitempty"`
}

type Chapter

type Chapter struct {
	StartSeconds int    `json:"start_seconds"`
	Timestamp    string `json:"timestamp"`
	Title        string `json:"title"`
}

Chapter is an author-supplied section marker.

type Client

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

Client is a cached YouTube acquisition session.

func NewClient

func NewClient() *Client

NewClient returns a client using the production endpoints.

func NewClientWithConfig

func NewClientWithConfig(cfg Config) *Client

NewClientWithConfig returns a client with any unset fields filled from DefaultConfig.

func (*Client) Channel

func (c *Client) Channel(ctx context.Context, input string, opts ChannelOptions) (*ChannelListing, error)

Channel lists a channel's recent uploads, newest first.

func (*Client) Doctor

func (c *Client) Doctor(ctx context.Context, probe string) DoctorReport

Doctor checks which Innertube clients and the watch page still work.

func (*Client) Info

func (c *Client) Info(ctx context.Context, videoID string, descriptionChars int) (*VideoInfo, error)

Info returns metadata without downloading a caption track.

func (*Client) Player

func (c *Client) Player(ctx context.Context, videoID string) (*playerResponse, string, error)

Player returns a player response, memoized per video. Negative results (private, not found, no captions) are cached briefly so a probing agent cannot turn the improved error path into a hot loop.

Concurrent misses for the same video are coalesced: every caller waits on one upstream fetch, but each still honors its own context deadline. The shared fetch is detached from the first caller's cancellation so an abandoned request cannot fail the others; it keeps its own TotalDeadline.

func (*Client) Tracks

func (c *Client) Tracks(ctx context.Context, videoID string) (via string, tracks []Track, err error)

Tracks lists caption tracks and the acquisition source that produced them.

func (*Client) Transcript

func (c *Client) Transcript(ctx context.Context, videoID string, opts TranscriptOptions) (*transcript.Transcript, error)

Transcript fetches and caches a caption track for a video.

type Config

type Config struct {
	InnertubeURL string
	WatchPageURL string
	ResolveURL   string
	FeedURL      string
	HTTPClient   *http.Client
}

Config lets tests and embedders point acquisition at another origin.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the production endpoints.

type DoctorClient

type DoctorClient struct {
	Client        string      `json:"client"`
	Version       string      `json:"version,omitempty"`
	OK            bool        `json:"ok"`
	Title         string      `json:"title,omitempty"`
	CaptionTracks int         `json:"caption_tracks,omitempty"`
	MS            int64       `json:"ms,omitempty"`
	Code          apperr.Code `json:"code,omitempty"`
	Error         string      `json:"error,omitempty"`
}

DoctorClient is one acquisition path's health result.

type DoctorReport

type DoctorReport struct {
	ProbeVideo string         `json:"probe_video"`
	OKClients  int            `json:"ok_clients"`
	TotalMS    int64          `json:"total_ms"`
	Results    []DoctorClient `json:"results"`
	Verdict    string         `json:"verdict"`
}

DoctorReport is the result of probing each acquisition path.

type Memo

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

func NewMemo

func NewMemo(maxBytes int) *Memo

func (*Memo) Delete

func (m *Memo) Delete(key string)

func (*Memo) Get

func (m *Memo) Get(key string) (any, bool)

func (*Memo) Len

func (m *Memo) Len() int

func (*Memo) Put

func (m *Memo) Put(key string, value any, ttl time.Duration, size int)

type Track

type Track struct {
	Language     string
	Kind         string // "asr" = auto-generated
	Translatable bool
	Name         string
}

Track is the public view of a caption track.

type TranscriptOptions

type TranscriptOptions struct {
	Languages        []string
	AllowTranslation bool
}

TranscriptOptions controls caption-track selection.

type VideoInfo

type VideoInfo struct {
	OK                        bool           `json:"ok"`
	VideoID                   string         `json:"video_id"`
	Title                     string         `json:"title"`
	Channel                   string         `json:"channel"`
	ChannelID                 string         `json:"channel_id"`
	DurationSeconds           int            `json:"duration_seconds"`
	ViewCount                 int64          `json:"view_count"`
	IsLive                    bool           `json:"is_live"`
	IsLiveContent             bool           `json:"is_live_content"`
	PublishedAt               string         `json:"published_at,omitempty"`
	Category                  string         `json:"category,omitempty"`
	Keywords                  []string       `json:"keywords,omitempty"`
	Description               string         `json:"description"`
	DescriptionTruncated      bool           `json:"description_truncated"`
	Chapters                  []Chapter      `json:"chapters,omitempty"`
	Captions                  CaptionSummary `json:"captions"`
	EstimatedTranscriptChars  int            `json:"estimated_transcript_chars"`
	EstimatedTranscriptTokens int            `json:"estimated_transcript_tokens"`
	URL                       string         `json:"url"`
	Via                       string         `json:"via"`
}

Jump to

Keyboard shortcuts

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