| Crates.io | yt-dlp |
| lib.rs | yt-dlp |
| version | 1.4.7 |
| created_at | 2024-10-31 16:21:30.959458+00 |
| updated_at | 2025-12-08 00:45:37.519467+00 |
| description | π¬οΈ A Rust library (with auto dependencies installation) for Youtube downloading |
| homepage | https://github.com/boul2gom/yt-dlp |
| repository | https://github.com/boul2gom/yt-dlp |
| max_upload_size | |
| id | 1430309 |
| size | 747,855 |
Originally, to download videos from YouTube, I used the rustube crate, written in pure Rust and without any external dependencies.
However, I quickly realized that due to frequent breaking changes on the YouTube website, the crate was outdated and no longer functional.
After few tests and researches, I concluded that the python app yt-dlp was the best compromise, thanks to its regular updates and massive community.
His standalone binaries and his ability to output the fetched data in JSON format make it a most imperfect candidate for a Rust wrapper.
Using an external program is not ideal, but it is the most reliable and maintained solution for now.
Add the following to your Cargo.toml file:
[dependencies]
yt-dlp = "1.4.7"
A new release is automatically published every two weeks, to keep up to date with dependencies and features. Make sure to check the releases page to see the latest version of the crate.
This library puts a lot of functionality behind optional features in order to optimize compile time for the most common use cases. The following features are available.
cache (enabled by default) - Enables video metadata, files and thumbnails cachingtracing (enabled by default) β tracing crate.
When this feature is enabled, the library will output span events at log levels trace and debug, depending on the importance of the called function.rustls - Enables the rustls-tls feature in the reqwest crate.
This enables building the application without openssl or other system sourced SSL libraries.tracing (enabled by default):The crate supports the tracing feature to enable profiling, which can be useful for debugging.
You can enable it by adding the following to your Cargo.toml file:
[dependencies]
yt-dlp = { version = "1.4.7", features = ["tracing"], default-features = false }
The documentation is available on docs.rs.
use yt_dlp::Youtube;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let executables_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let fetcher = Youtube::with_new_binaries(executables_dir, output_dir).await?;
Ok(())
}
yt-dlp binary only:use yt_dlp::client::deps::LibraryInstaller;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let destination = PathBuf::from("libs");
let installer = LibraryInstaller::new(destination);
let youtube = installer.install_youtube(None).await.unwrap();
Ok(())
}
ffmpeg binary only:use yt_dlp::client::deps::LibraryInstaller;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let destination = PathBuf::from("libs");
let installer = LibraryInstaller::new(destination);
let ffmpeg = installer.install_ffmpeg(None).await.unwrap();
Ok(())
}
yt-dlp binary:use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
fetcher.update_downloader().await?;
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video_path = fetcher.download_video_from_url(url, "my-video.mp4").await?;
Ok(())
}
use yt_dlp::Youtube;
use yt_dlp::model::selector::{VideoQuality, AudioQuality, VideoCodecPreference};
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
// Use the fluent download builder API
let video_path = fetcher.download(url, "my-video.mp4")
.video_quality(VideoQuality::Q1080p)
.video_codec(VideoCodecPreference::H264)
.audio_quality(AudioQuality::Best)
.execute()
.await?;
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
fetcher.download_video_stream_from_url(url, "video.mp4").await?;
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
fetcher.download_audio_stream_from_url(url, "audio.mp3").await?;
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
println!("Video title: {}", video.title);
let video_format = video.best_video_format().unwrap();
let format_path = fetcher.download_format(&video_format, "my-video-stream.mp4").await?;
let audio_format = video.worst_audio_format().unwrap();
let audio_path = fetcher.download_format(&audio_format, "my-audio-stream.mp3").await?;
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
let audio_format = video.best_audio_format().unwrap();
let audio_path = fetcher.download_format(&audio_format, "audio-stream.mp3").await?;
let video_format = video.worst_video_format().unwrap();
let video_path = fetcher.download_format(&video_format, "video-stream.mp4").await?;
let output_path = fetcher.combine_audio_and_video("audio-stream.mp3", "video-stream.mp4", "my-output.mp4").await?;
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let thumbnail_path = fetcher.download_thumbnail_from_url(url, "thumbnail.jpg").await?;
Ok(())
}
use yt_dlp::Youtube;
use yt_dlp::download::manager::{ManagerConfig, DownloadPriority};
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Custom download manager configuration using builder methods
let config = ManagerConfig::default()
.with_max_concurrent_downloads(5) // Maximum 5 concurrent downloads
.with_segment_size(1024 * 1024 * 10) // 10 MB per segment
.with_parallel_segments(8) // 8 parallel segments per download
.with_retry_attempts(5) // 5 retry attempts on failure
.with_max_buffer_size(1024 * 1024 * 20); // 20 MB maximum buffer
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
// Create a fetcher with custom configuration
let fetcher = Youtube::with_download_manager_config(libraries, output_dir, config)?;
// Download a video with high priority
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
let download_id = fetcher.download_video_with_priority(
&video,
"video-high-priority.mp4",
Some(DownloadPriority::High)
).await?;
// Wait for download completion
let status = fetcher.wait_for_download(download_id).await;
println!("Final download status: {:?}", status);
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Download with progress callback
let download_id = fetcher.download_video_with_progress(
&video,
"video-with-progress.mp4",
|downloaded, total| {
let percentage = if total > 0 {
(downloaded as f64 / total as f64 * 100.0) as u64
} else {
0
};
println!("Progress: {}/{} bytes ({}%)", downloaded, total, percentage);
}
).await?;
// Wait for download completion
fetcher.wait_for_download(download_id).await;
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Start a download
let download_id = fetcher.download_video_with_priority(
&video,
"video-to-cancel.mp4",
None
).await?;
// Check status
let status = fetcher.get_download_status(download_id).await;
println!("Download status: {:?}", status);
// Cancel the download
let canceled = fetcher.cancel_download(download_id).await;
println!("Download canceled: {}", canceled);
Ok(())
}
The library provides a powerful format selection system that allows you to download videos and audio with specific quality and codec preferences.
VideoQuality::Best - Selects the highest quality video format availableVideoQuality::High - Targets 1080p resolutionVideoQuality::Medium - Targets 720p resolutionVideoQuality::Low - Targets 480p resolutionVideoQuality::Worst - Selects the lowest quality video format availableVideoQuality::CustomHeight(u32) - Targets a specific height (e.g., CustomHeight(1440) for 1440p)VideoQuality::CustomWidth(u32) - Targets a specific width (e.g., CustomWidth(1920) for 1920px width)AudioQuality::Best - Selects the highest quality audio format availableAudioQuality::High - Targets 192kbps bitrateAudioQuality::Medium - Targets 128kbps bitrateAudioQuality::Low - Targets 96kbps bitrateAudioQuality::Worst - Selects the lowest quality audio format availableAudioQuality::CustomBitrate(u32) - Targets a specific bitrate in kbps (e.g., CustomBitrate(256) for 256kbps)VideoCodecPreference::VP9 - Prefer VP9 codecVideoCodecPreference::AVC1 - Prefer AVC1/H.264 codecVideoCodecPreference::AV1 - Prefer AV01/AV1 codecVideoCodecPreference::Custom(String) - Prefer a custom codecVideoCodecPreference::Any - No codec preferenceAudioCodecPreference::Opus - Prefer Opus codecAudioCodecPreference::AAC - Prefer AAC codecAudioCodecPreference::MP3 - Prefer MP3 codecAudioCodecPreference::Custom(String) - Prefer a custom codecAudioCodecPreference::Any - No codec preferenceuse yt_dlp::Youtube;
use yt_dlp::model::selector::{VideoQuality, VideoCodecPreference, AudioQuality, AudioCodecPreference};
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
// Download a high quality video with VP9 codec and high quality audio with Opus codec
let video_path = fetcher.download_video_with_quality(
url.clone(),
"complete-video.mp4",
VideoQuality::High,
VideoCodecPreference::VP9,
AudioQuality::High,
AudioCodecPreference::Opus
).await?;
// Download just the video stream with medium quality and AVC1 codec
let video_stream_path = fetcher.download_video_stream_with_quality(
url.clone(),
"video-only.mp4",
VideoQuality::Medium,
VideoCodecPreference::AVC1
).await?;
// Download just the audio stream with high quality and AAC codec
let audio_stream_path = fetcher.download_audio_stream_with_quality(
url,
"audio-only.m4a",
AudioQuality::High,
AudioCodecPreference::AAC
).await?;
println!("Downloaded files:");
println!("Complete video: {}", video_path.display());
println!("Video stream: {}", video_stream_path.display());
println!("Audio stream: {}", audio_stream_path.display());
Ok(())
}
The project supports automatic addition of metadata to downloaded files in several formats:
Metadata is added automatically during download, without requiring any additional action from the user.
The system intelligently manages the application of metadata based on the file type and intended use:
combine_audio_and_video(), complete metadata is applied to the final file, including information from both streams.This optimized approach ensures that metadata is always present in the final file, while avoiding unnecessary processing of temporary files.
Videos may contain chapters that divide the content into logical segments. The library provides easy access to chapter information and automatically embeds chapters into downloaded video files (MP4/MKV/WebM):
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Check if video has chapters
if video.has_chapters() {
println!("Video has {} chapters", video.get_chapters().len());
// Iterate over all chapters
for chapter in video.get_chapters() {
println!(
"Chapter: {} ({:.2}s - {:.2}s)",
chapter.title.as_deref().unwrap_or("Untitled"),
chapter.start_time,
chapter.end_time
);
}
}
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Find chapter at 120 seconds (2 minutes)
if let Some(chapter) = video.get_chapter_at_time(120.0) {
println!(
"At 2:00, you're in chapter: {}",
chapter.title.as_deref().unwrap_or("Untitled")
);
println!("Chapter duration: {:.2}s", chapter.duration());
}
Ok(())
}
Note: When downloading videos using download_video() or download_video_from_url(), chapters are automatically embedded into the video file metadata. Media players like VLC, MPV, and others will be able to navigate using the chapters!
Heatmap data (also known as "Most Replayed" segments) shows viewer engagement across different parts of a video. This feature allows you to identify which segments are most popular:
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Check if video has heatmap data
if video.has_heatmap() {
if let Some(heatmap) = video.get_heatmap() {
println!("Video has {} heatmap segments", heatmap.points.len());
// Find the most replayed segment
if let Some(most_replayed) = heatmap.most_engaged_segment() {
println!(
"Most replayed segment: {:.2}s - {:.2}s (engagement: {:.2})",
most_replayed.start_time,
most_replayed.end_time,
most_replayed.value
);
}
}
}
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
if let Some(heatmap) = video.get_heatmap() {
// Get segments with high engagement (> 0.7)
let highly_engaged = heatmap.get_highly_engaged_segments(0.7);
println!("Found {} highly engaged segments", highly_engaged.len());
for segment in highly_engaged {
println!(
"High engagement: {:.2}s - {:.2}s (value: {:.2})",
segment.start_time,
segment.end_time,
segment.value
);
}
// Get engagement at specific timestamp
if let Some(point) = heatmap.get_point_at_time(120.0) {
println!(
"Engagement at 2:00 is {:.2}",
point.value
);
}
}
Ok(())
}
The library provides comprehensive subtitle support, including downloading, language selection, and embedding subtitles into videos:
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// List all available subtitle languages
let languages = fetcher.list_subtitle_languages(&video);
println!("Available subtitle languages: {:?}", languages);
// Check if specific language is available
if fetcher.has_subtitle_language(&video, "en") {
println!("English subtitles are available");
}
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Download English subtitles
let subtitle_path = fetcher
.download_subtitle(&video, "en", "subtitle_en.srt")
.await?;
println!("Subtitle downloaded to: {:?}", subtitle_path);
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Download all available subtitles
let subtitle_paths = fetcher
.download_all_subtitles(&video, &output_dir)
.await?;
println!("Downloaded {} subtitle files", subtitle_paths.len());
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Download video
let video_path = fetcher.download_video(&video, "video.mp4").await?;
// Download subtitles
let en_subtitle = fetcher
.download_subtitle(&video, "en", "subtitle_en.srt")
.await?;
let fr_subtitle = fetcher
.download_subtitle(&video, "fr", "subtitle_fr.srt")
.await?;
// Embed subtitles into video
let video_with_subs = fetcher
.embed_subtitles_in_video(
&video_path,
&[en_subtitle, fr_subtitle],
"video_with_subtitles.mp4",
)
.await?;
println!("Video with embedded subtitles: {:?}", video_with_subs);
Ok(())
}
use yt_dlp::Youtube;
use yt_dlp::model::caption::Subtitle;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = fetcher.fetch_video_infos(url).await?;
// Iterate over subtitles and filter automatic ones
for (lang_code, subtitles) in &video.subtitles {
for subtitle in subtitles {
if subtitle.is_automatic {
println!(
"Auto-generated subtitle: {} ({})",
subtitle.language_name
.as_deref()
.unwrap_or(lang_code),
subtitle.file_extension()
);
}
}
}
// Convert automatic captions to Subtitle struct
for (lang_code, auto_captions) in &video.automatic_captions {
if let Some(caption) = auto_captions.first() {
let subtitle = Subtitle::from_automatic_caption(
caption,
lang_code.clone(),
);
println!("Converted: {}", subtitle);
}
}
Ok(())
}
The library provides full playlist support, including fetching playlist metadata and downloading videos with various selection options:
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let playlist_url = String::from("https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf");
let playlist = fetcher.fetch_playlist_infos(playlist_url).await?;
println!("Playlist: {}", playlist.title);
println!("Videos: {}", playlist.entry_count());
println!("Uploader: {}", playlist.uploader);
// List all videos in the playlist
for entry in &playlist.entries {
println!(
"[{}] {} ({})",
entry.index.unwrap_or(0),
entry.title,
entry.id
);
}
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let playlist_url = String::from("https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf");
let playlist = fetcher.fetch_playlist_infos(playlist_url).await?;
// Download all videos with a pattern
// Use %(playlist_index)s for index, %(title)s for title, %(id)s for video ID
let video_paths = fetcher
.download_playlist(&playlist, "%(playlist_index)s - %(title)s.mp4")
.await?;
println!("Downloaded {} videos", video_paths.len());
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let playlist_url = String::from("https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf");
let playlist = fetcher.fetch_playlist_infos(playlist_url).await?;
// Download specific videos by index (0-based)
let indices = vec![0, 2, 5, 10]; // Videos at positions 1, 3, 6, and 11
let video_paths = fetcher
.download_playlist_items(&playlist, &indices, "%(playlist_index)s - %(title)s.mp4")
.await?;
println!("Downloaded {} specific videos", video_paths.len());
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let playlist_url = String::from("https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf");
let playlist = fetcher.fetch_playlist_infos(playlist_url).await?;
// Download videos 5-15 (0-based, inclusive)
let video_paths = fetcher
.download_playlist_range(&playlist, 5, 15, "%(playlist_index)s - %(title)s.mp4")
.await?;
println!("Downloaded {} videos from range", video_paths.len());
Ok(())
}
use yt_dlp::Youtube;
use std::path::PathBuf;
use yt_dlp::client::deps::Libraries;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let youtube = libraries_dir.join("yt-dlp");
let ffmpeg = libraries_dir.join("ffmpeg");
let libraries = Libraries::new(youtube, ffmpeg);
let fetcher = Youtube::new(libraries, output_dir)?;
let playlist_url = String::from("https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf");
let playlist = fetcher.fetch_playlist_infos(playlist_url).await?;
// Check if playlist is complete
if playlist.is_complete() {
println!("All playlist videos have been fetched");
}
// Get only available videos
let available = playlist.available_entries();
println!("Available videos: {}/{}", available.len(), playlist.entry_count());
// Get specific entry
if let Some(first_video) = playlist.get_entry_by_index(0) {
println!("First video: {}", first_video.title);
if let Some(duration) = first_video.duration_minutes() {
println!("Duration: {:.2} minutes", duration);
}
}
// Get entries in a range
let range = playlist.get_entries_in_range(0, 10);
println!("First 11 videos: {}", range.len());
Ok(())
}
The library supports HTTP, HTTPS, and SOCKS5 proxies for both yt-dlp and reqwest downloads:
use yt_dlp::Youtube;
use yt_dlp::client::proxy::{ProxyConfig, ProxyType};
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
// Configure proxy with authentication
let proxy = ProxyConfig::new(ProxyType::Http, "http://proxy.example.com:8080")
.with_auth("username", "password")
.with_no_proxy(vec!["localhost".to_string(), "127.0.0.1".to_string()]);
// Build Youtube client with proxy
let youtube = Youtube::builder(libraries, output_dir)
.with_proxy(proxy)
.build()
.await?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = youtube.fetch_video_infos(url).await?;
// All downloads (video, audio, thumbnails) will use the proxy
youtube.download_video(&video, "video.mp4").await?;
Ok(())
}
Supported proxy types:
Download only specific parts of a video using time ranges or chapters:
use yt_dlp::Youtube;
use yt_dlp::download::partial::PartialRange;
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
let youtube = Youtube::builder(libraries, output_dir).build().await?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = youtube.fetch_video_infos(url).await?;
// Download from 1:30 to 5:00 (90 to 300 seconds)
let range = PartialRange::time_range(90.0, 300.0);
youtube.download_video_partial(&video, &range, "partial.mp4").await?;
Ok(())
}
use yt_dlp::Youtube;
use yt_dlp::download::partial::PartialRange;
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
let youtube = Youtube::builder(libraries, output_dir).build().await?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
let video = youtube.fetch_video_infos(url).await?;
// Download a single chapter (0-based index)
let single_chapter = PartialRange::single_chapter(2);
youtube.download_video_partial(&video, &single_chapter, "chapter2.mp4").await?;
// Download chapters 2 through 5
let chapter_range = PartialRange::chapter_range(2, 5);
youtube.download_video_partial(&video, &chapter_range, "chapters2-5.mp4").await?;
Ok(())
}
use yt_dlp::Youtube;
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
let youtube = Youtube::builder(libraries, output_dir).build().await?;
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
// Download with fluent API
youtube.download(url.clone(), "partial.mp4")
.time_range(90.0, 300.0) // Download from 1:30 to 5:00
.execute()
.await?;
Ok(())
}
Implementation details:
yt-dlp's --download-sections feature as primary methodyt-dlp failsApply advanced post-processing to videos using FFmpeg:
use yt_dlp::Youtube;
use yt_dlp::download::postprocess::{PostProcessConfig, VideoCodec, AudioCodec};
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
let youtube = Youtube::builder(libraries, output_dir).build().await?;
// Configure post-processing
let config = PostProcessConfig::new()
.with_video_codec(VideoCodec::H264)
.with_audio_codec(AudioCodec::AAC)
.with_video_bitrate("2M")
.with_audio_bitrate("192k");
// Apply to existing video
youtube.postprocess_video("input.mp4", "output.mp4", config).await?;
Ok(())
}
use yt_dlp::Youtube;
use yt_dlp::download::postprocess::{
PostProcessConfig, VideoCodec, Resolution, EncodingPreset,
FfmpegFilter, WatermarkPosition
};
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
let youtube = Youtube::builder(libraries, output_dir).build().await?;
// Advanced configuration with filters
let config = PostProcessConfig::new()
.with_video_codec(VideoCodec::H265)
.with_resolution(Resolution::HD)
.with_framerate(30)
.with_preset(EncodingPreset::Medium)
.add_filter(FfmpegFilter::Brightness { value: 0.1 })
.add_filter(FfmpegFilter::Contrast { value: 1.2 })
.add_filter(FfmpegFilter::Watermark {
path: "logo.png".to_string(),
position: WatermarkPosition::BottomRight,
});
youtube.postprocess_video("input.mp4", "processed.mp4", config).await?;
Ok(())
}
Video Codecs:
Audio Codecs:
Resolutions:
Encoding Presets:
Video Filters:
Crop { width, height, x, y }Rotate { angle } (in degrees)Watermark { path, position }Brightness { value } (-1.0 to 1.0)Contrast { value } (0.0 to 4.0)Saturation { value } (0.0 to 3.0)Blur { radius }Custom { filter } - Any FFmpeg filter stringThe library includes an intelligent speed optimization system that automatically configures download parameters based on your internet connection speed. This feature significantly improves download performance for both individual videos and playlists.
Three pre-configured profiles are available:
π’ Conservative (for connections < 50 Mbps)
βοΈ Balanced (for connections 50-500 Mbps) - Default
π Aggressive (for connections > 500 Mbps)
use yt_dlp::{Youtube, YoutubeBuilder};
use yt_dlp::download::SpeedProfile;
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
// Use the Aggressive profile for maximum speed
let youtube = YoutubeBuilder::new(libraries, output_dir)
.with_speed_profile(SpeedProfile::Aggressive)
.build()
.await?;
// All downloads will now use optimized settings
let url = String::from("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
youtube.download_video_from_url(url, "video.mp4").await?;
Ok(())
}
You can also manually configure download parameters if you need fine-grained control:
use yt_dlp::{Youtube, YoutubeBuilder};
use yt_dlp::download::ManagerConfig;
use yt_dlp::client::deps::Libraries;
use std::path::PathBuf;
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
let libraries_dir = PathBuf::from("libs");
let output_dir = PathBuf::from("output");
let libraries = Libraries::new(
libraries_dir.join("yt-dlp"),
libraries_dir.join("ffmpeg")
);
// Create a custom configuration
let config = ManagerConfig::default()
.with_max_concurrent_downloads(10) // 10 concurrent downloads
.with_segment_size(15 * 1024 * 1024) // 15 MB segments
.with_parallel_segments(16); // 16 parallel segments
let youtube = YoutubeBuilder::new(libraries, output_dir)
.with_download_manager_config(config)
.build()
.await?;
Ok(())
}
The speed optimization system includes several advanced features:
Expected Performance Gains:
For individual videos:
For playlists:
Note: Actual performance gains depend on your internet speed, server limitations, and network conditions.
ffmpeg or reqwest