A high-performance, memory-safe Rust library for YouTube video uploading with OAuth 2.0 authentication, featuring both programmatic API and command-line interface.
- OAuth 2.0 Authentication: Secure authentication with YouTube API using OAuth 2.0 flow with PKCE support
- Dual Configuration Formats: Support for both individual and batch YAML configuration formats
- Concurrent Uploads: Async upload mode with configurable concurrency (default: 3)
- Resumable Uploads: Robust upload handling with automatic retry and resumption
- Progress Tracking: Real-time upload progress bars for sequential uploads
- MTS File Support: Special handling for MTS files with correct MIME type
- Comprehensive Validation: Input validation for all configuration parameters
- Retry Logic: Exponential backoff with jitter for handling transient failures
- Memory Safety: Zero-cost abstractions with compile-time safety guarantees
Add to your Cargo.toml:
[dependencies]
rust-yt-uploader = "0.2.8"- A Google Cloud project with YouTube Data API v3 enabled
- OAuth 2.0 client credentials
- Go to the Google Cloud Console
- Create a new project or select an existing one
- Enable the YouTube Data API v3
- Create OAuth 2.0 credentials (Desktop application)
- Download the credentials and save as
client_secret-{profile}.json(e.g.,client_secret-work.json) - Place the file in the working directory
The first time you run the uploader with a profile, it will:
- Load credentials from
client_secret-{profile}.json - Display an authorization URL
- Open your browser for authentication
- Ask you to paste the authorization code
- Save the tokens to
youtube-oauth2-{profile}.json
git clone https://github.com/leafyoung/rust-yt-uploader
cd rust-yt-uploader
cargo build --release --bin yt-upload
cargo build --release --bin yt-list
cargo build --release --bin yt-update-langThe binaries will be available after building.
use rust_yt_uploader::{YouTubeClient, ConfigFormat, BatchConfigRoot};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load configuration
let config = BatchConfigRoot::from_file("config.yaml")?;
// Create authenticated client with profile
// Credentials: client_secret-work.json
// Token: youtube-oauth2-work.json
let client = YouTubeClient::new("work").await?;
// Upload videos
client.upload_batch(&config).await?;
Ok(())
}For more advanced use cases requiring direct API access:
use rust_yt_uploader::google_oauth::{GoogleOAuth, Credentials};
use rust_yt_uploader::{youtube_client, credentials_path_for_profile, token_path_for_profile};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create OAuth client with profile-based paths
let profile = "work";
let oauth_client = GoogleOAuth::new(
credentials_path_for_profile(profile)?, // client_secret-work.json
token_path_for_profile(profile)?, // youtube-oauth2-work.json
youtube_client::default_youtube_scopes(),
youtube_client::build_youtube_base_url(),
).await?;
// Use the authenticated client for custom API calls
// The client handles token refresh automatically
let response = oauth_client
.http_client
.get("https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true")
.bearer_auth(&oauth_client.access_token)
.send()
.await?;
println!("API Response: {:?}", response.json::<serde_json::Value>().await?);
Ok(())
}common:
prefix: "My Video Series"
keywords: "rust,youtube,programming"
category: ScienceTechnology
privacyStatus: "private"
playlistId: "PL1234567890123456"
titles:
- "Episode 1: Introduction"
- "Episode 2: Getting Started"
files:
- "/path/to/video1.mp4"
- "/path/to/video2.mp4"
# Each entry can also contain multiple files separated by comma, semicolon, or space:
# - "/path/to/part1.mp4;/path/to/part2.mp4"
# - "/path/to/video3.mp4, /path/to/video3_extra.mp4"videos:
- title: "My First Video"
description: "This is my first video"
keywords: "rust,youtube"
file: "/path/to/video1.mp4"
category: ScienceTechnology
privacyStatus: "private"
playlistId: "PL1234567890123456"| ID | Category |
|---|---|
| 1 | Film & Animation |
| 2 | Autos & Vehicles |
| 10 | Music |
| 15 | Pets & Animals |
| 17 | Sports |
| 20 | Gaming |
| 22 | People & Blogs |
| 23 | Comedy |
| 24 | Entertainment |
| 25 | News & Politics |
| 26 | Howto & Style |
| 27 | Education |
| 28 | Science & Technology |
public: Video is visible to everyoneprivate: Video is only visible to youunlisted: Video is visible to anyone with the link
Playlist IDs must match the pattern: ^PL[a-zA-Z0-9_-]{16,33}$
Example: PL1234567890123456
# Sequential upload with profile (required)
yt-upload --file config.yaml --profile work
# Sequential upload with progress bars
yt-upload --file config.yaml --profile work --progress
# Concurrent upload (3 concurrent by default)
yt-upload --file config.yaml --profile work --async
# Custom concurrency level
yt-upload --file config.yaml --profile work --async --concurrent 5The yt-list tool lists all videos from your YouTube channel with comprehensive metadata. This is useful for:
- Downloading videos - Get video IDs for download tools
- Updating metadata - Export video info to update recording date, language, and audio language
Basic Usage:
# List all videos in table format (default) - profile required
yt-list --profile work
# Export as JSON (for programmatic access)
yt-list --profile work --format json
# Export as JSONL (one video per line, useful for piping)
yt-list --profile work --format jsonl
# Save to file instead of stdout
yt-list --profile work --format json --output videos.json
# Show only video IDs (one per line)
yt-list --profile work --ids-onlyOutput Formats:
- table (default): Human-readable table with video ID, title, status, and recording date
- json: Single JSON array containing all videos
- jsonl: JSON Lines format - one JSON object per line (great for piping to other tools)
Video Details Exported:
Each video includes:
id: YouTube video ID (needed for downloading)title: Video titledescription: Video descriptionstatus: Privacy status (public, private, unlisted)upload_date: When the video was uploadedrecording_date: When the video was recorded (if set)category_id: YouTube category IDtags: Video tags/keywordsdefault_language: Default language for the videodefault_audio_language: Default audio language for the video
Examples:
# Export videos to JSON and pipe to jq for further processing
yt-list --profile work --format json | jq '.[].id'
# Extract video IDs and titles for batch download
yt-list --profile work --format jsonl | jq -r '[.id, .title] | join(": ")'
# Save all video metadata for backup
yt-list --profile work --format json --output my_videos_backup.jsonThe yt-update-lang tool automatically updates language metadata for all public videos in your channel. It sets:
defaultLanguage: zh (Chinese)defaultAudioLanguage: zh-Hans (Simplified Chinese)
For any videos that don't already have these values set.
Basic Usage:
# Show what would be updated (dry run) - profile required
yt-update-lang --profile work --dry-run
# Update all public videos with language metadata
yt-update-lang --profile work
# Verbose mode - show each video being processed
yt-update-lang --profile work --verbose
# Only update videos with no language metadata at all
yt-update-lang --profile work --only-emptyFeatures:
- Dry Run Mode (
--dry-run): Preview which videos would be updated without making changes - Verbose Output (
--verbose): Show detailed information about each video being updated - Smart Filtering (
--only-empty): Only update videos with completely empty language fields - Rate Limiting: Automatically adds small delays between updates to avoid API rate limits
- Progress Tracking: Shows progress and summary of successful/failed updates
Examples:
# Preview changes before applying
yt-update-lang --profile work --dry-run
# Update with verbose output to see what's happening
yt-update-lang --profile work --verbose
# Combine with yt-list to verify your videos first
yt-list --profile work --format json | jq '.[] | {id, title, default_language, default_audio_language}'
# Then update them
yt-update-lang --profile workUse Cases:
- Batch Language Setup - Set correct language metadata after bulk uploads
- Content Localization - Ensure Chinese content is properly marked as such
- Accessibility - Help YouTube properly display captions and audio tracks
- Content Organization - Maintain consistent metadata across your channel
tokio: Async runtime for high-performance I/Oreqwest: HTTP client for API callsserde/serde_yaml: Configuration parsing and serializationclap: Command-line argument parsingvalidator: Input validation with custom validatorstracing: Structured logginganyhow/thiserror: Comprehensive error handling
- Never commit
client_secret-{profile}.jsonoryoutube-oauth2-{profile}.jsonfiles to version control - Store credentials securely with appropriate file permissions (600)
- Regularly rotate OAuth tokens if needed
- Use private/unlisted privacy settings for sensitive content
- Rust 2024 edition or later
pre-commitfor git hooks (optional but recommended)
Pre-commit hooks automatically run linters, formatters, and tests before each commit:
# Install pre-commit (if not already installed)
pip install pre-commit
# Install the git hooks
pre-commit install
# Run hooks manually on all files
pre-commit run --all-files
# Update hooks to the latest version
pre-commit autoupdateThe pre-commit configuration includes:
- cargo fmt - Checks code formatting
- cargo clippy - Runs the Rust linter
- cargo test - Runs all tests
- Generic checks - YAML/JSON syntax, trailing whitespace, merge conflicts, etc.
# Format code
cargo fmt
# Check formatting without making changes
cargo fmt -- --check
# Run linter
cargo clippy --all-targets --all-features
# Run tests
cargo test --all-features
# Run tests with output
cargo test --all-features -- --nocapture
# Run specific test
cargo test test_nameThis project is licensed under the MIT License - see the LICENSE file for details.
- Built with the Tokio async runtime for high-performance I/O
- Use yup_oauth2 as an alternative