downloader

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package downloader wraps YouTube stream extraction, format selection and file writing for the chunder CLI.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CaptionLanguages

func CaptionLanguages(video *youtube.Video) []string

CaptionLanguages lists the language codes a video has captions for, auto-generated ones marked with "(auto)".

func ConvertToMP3

func ConvertToMP3(ctx context.Context, in, out string) error

ConvertToMP3 re-encodes an audio file to mp3 with ffmpeg. -q:a 2 is LAME VBR at roughly 190 kbps — transparent for YouTube-quality sources.

func EmbedSubtitles

func EmbedSubtitles(ctx context.Context, videoPath, srtPath, lang string) error

EmbedSubtitles muxes an SRT file into an mp4 as a soft subtitle track (mov_text), replacing the file in place. Streams are copied, not re-encoded.

func Extension

func Extension(format *youtube.Format) string

Extension returns the file extension for a format based on its MIME type.

func FFmpegAvailable

func FFmpegAvailable() bool

FFmpegAvailable reports whether ffmpeg is on PATH (needed to mux 1080p+).

func FFplayAvailable

func FFplayAvailable() bool

FFplayAvailable reports whether ffplay is on PATH (used for watch audio).

func HumanBytes

func HumanBytes(n int64) string

HumanBytes formats a byte count like "12.4 MiB".

func IsPlaylistURL

func IsPlaylistURL(raw string) bool

IsPlaylistURL reports whether a URL points at a whole playlist rather than a single video. Watch links that merely carry playlist context (watch?v=…&list=…) count as single videos.

func Mux

func Mux(ctx context.Context, videoPath, audioPath, out string) error

Mux combines a video-only and audio-only file into out using stream copy (no re-encoding), so it is fast and lossless.

func ParseTimestamp

func ParseTimestamp(s string) (time.Duration, error)

ParseTimestamp reads clip positions in any of the common shapes: "1:23" (m:ss), "1:02:03" (h:mm:ss), "83" (seconds), "1m23s" (Go duration).

func SanitizeFilename

func SanitizeFilename(name string) string

SanitizeFilename makes a video title safe to use as a filename.

func SelectPlayback

func SelectPlayback(video *youtube.Video) (vf, af *youtube.Format, muxed bool, err error)

SelectPlayback picks a lightweight format pair for terminal playback. Terminal "screens" are ~200×112 pixels, so 360p is plenty; muxed formats are preferred because one URL then carries both video and audio.

func UniquePath

func UniquePath(path string) string

UniquePath returns path, or path with " (n)" inserted before the extension if a file already exists there, so downloads never overwrite silently.

Types

type Client

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

Client fetches video metadata and streams from YouTube.

func New

func New() *Client

New returns a ready-to-use Client.

func (*Client) DownloadSubtitles

func (c *Client) DownloadSubtitles(ctx context.Context, video *youtube.Video, lang, dir, basename string) (string, error)

DownloadSubtitles fetches the lang caption track and writes it as an SRT file named "<basename>.<lang>.srt" in dir, returning the file path.

func (*Client) GetVideo

func (c *Client) GetVideo(ctx context.Context, url string) (*youtube.Video, error)

GetVideo resolves a YouTube URL or bare video ID into its metadata.

func (*Client) Run

func (c *Client) Run(ctx context.Context, opts Options, ev Events) (string, error)

Run executes a full download: resolve metadata, pick formats, fetch the stream(s), and mux if needed. It returns the final file path.

func (*Client) RunClip

func (c *Client) RunClip(ctx context.Context, opts Options, ev Events) (string, error)

RunClip downloads just the [From, To] segment of a video by letting ffmpeg seek into the stream URL(s) with HTTP range requests — only the clip's bytes are transferred. Cutting is stream-copy, so it lands on keyframes: the clip may start up to a couple of seconds before the requested time.

func (*Client) RunPlaylist

func (c *Client) RunPlaylist(ctx context.Context, opts Options, plOpts PlaylistOptions, ev PlaylistEvents) (done, failed int, err error)

RunPlaylist downloads every selected entry of a playlist sequentially into a folder named after the playlist. It returns counts of succeeded and failed items; err is only non-nil when the whole run couldn't proceed.

func (*Client) StreamURL

func (c *Client) StreamURL(ctx context.Context, video *youtube.Video, format *youtube.Format) (string, error)

StreamURL resolves the direct, deciphered media URL for a format, playable by external tools like ffmpeg.

type Events

type Events interface {
	// Info fires once metadata is resolved and formats are chosen.
	Info(video *youtube.Video, sel *Selection)
	// StreamStart fires before each stream download. label is "video" or
	// "audio"; size is the expected byte count (0 if unknown).
	StreamStart(label string, size int64)
	// StreamProgress reports newly downloaded bytes for the active stream.
	StreamProgress(label string, delta int64)
	// StreamDone fires when a stream finishes.
	StreamDone(label string)
	// MuxStart fires before ffmpeg combines video and audio.
	MuxStart()
	// ConvertStart fires before ffmpeg re-encodes audio (e.g. to mp3).
	ConvertStart(format string)
	// ClipStart fires before ffmpeg extracts a clip segment.
	ClipStart(from, to time.Duration)
	// SubsStart fires before subtitles are fetched (only when requested).
	SubsStart(lang string)
	// SubsDone fires after the subtitle attempt: path on success, err on
	// failure. Subtitle failures never fail the download itself.
	SubsDone(path string, err error)
}

Events receives progress callbacks while Run executes. Implementations drive the UI — the fancy TUI and the plain fallback both implement this.

type Options

type Options struct {
	URL       string
	Quality   string
	OutputDir string
	Filename  string
	AudioOnly bool
	// AudioFormat converts audio downloads: "" or "m4a" keeps the native
	// stream, "mp3" re-encodes with ffmpeg.
	AudioFormat string
	SubsLang    string // e.g. "en": also download subtitles as .srt
	EmbedSubs   bool   // mux subtitles into the mp4 (needs ffmpeg)
	// ClipFrom/ClipTo select a segment instead of the whole video (ClipTo
	// zero means "until the end"). Requires ffmpeg.
	ClipFrom time.Duration
	ClipTo   time.Duration
}

Options describes a single download request.

func (Options) Clipped

func (o Options) Clipped() bool

Clipped reports whether this request asks for a segment.

type PlaylistEvents

type PlaylistEvents interface {
	Events
	// PlaylistInfo fires once the playlist is resolved. items is the queue
	// after applying Limit/Reverse; dest is the folder files land in.
	PlaylistInfo(pl *youtube.Playlist, items []*youtube.PlaylistEntry, dest string)
	// ItemStart fires before each queue item is fetched.
	ItemStart(index int, entry *youtube.PlaylistEntry)
	// ItemDone fires after each queue item: path on success, err on failure.
	// One bad video does not stop the queue.
	ItemDone(index int, path string, err error)
}

PlaylistEvents extends Events with playlist-level lifecycle callbacks. The embedded Events fire for whichever item is currently downloading.

type PlaylistOptions

type PlaylistOptions struct {
	Limit   int  // 0 = every video
	Reverse bool // download oldest-first on playlists sorted newest-first
}

PlaylistOptions controls how much of a playlist is downloaded.

type Selection

type Selection struct {
	Video *youtube.Format // nil for audio-only downloads
	Audio *youtube.Format // set when muxing or audio-only; nil when Video is already muxed
	// NeedsMux is true when Video and Audio are separate streams that must
	// be combined with ffmpeg.
	NeedsMux bool
	// FellBack is a human-readable note set when the requested quality was
	// unavailable and a lower one was chosen instead.
	FellBack string
}

Selection describes which stream(s) will be downloaded for a request.

func SelectFormats

func SelectFormats(video *youtube.Video, quality string, audioOnly bool) (*Selection, error)

SelectFormats picks the streams to download for the requested quality.

YouTube serves low resolutions (usually ≤720p) as single "muxed" files with audio included, and higher resolutions as separate video-only and audio-only streams. When the target quality only exists as a separate stream, ffmpeg is required to mux; without it we fall back to the best muxed format.

func (*Selection) Label

func (s *Selection) Label() string

Label returns the quality label of the selection, e.g. "1080p" or "audio".

Jump to

Keyboard shortcuts

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