A minimal CLI for uploading videos to YouTube — single files or entire directories, powered by the YouTube Data API v3.
Project description
ytee
A minimal CLI for uploading videos to YouTube — single files or entire directories — powered by the YouTube Data API v3.
⛔ PLEASE USE LATEST VERSION v0.1.5 ⛔
Versions below v0.1.5 should not be used. Earlier versions have known bugs in upload history logging and missing error handling.
Please upgrade:
pip install --upgrade ytee
Quickstart
ytee init → ytee set-creds → ytee upload
These three commands are all you need. init must be run before anything else.
Installation
pip install ytee
Requires Python 3.9+.
Setup
1. Get Google API credentials
Before using ytee, you need a Google Cloud project with the YouTube Data API v3 enabled:
- Go to the Google Cloud Console.
- Enable the YouTube Data API v3.
- Create OAuth 2.0 credentials for a Desktop application.
- Download the credentials as a JSON file (e.g.
client_secret.json).
CLI Commands
ytee init — Run this first
Copies your Google OAuth credentials into ~/.ytee/.google_secrets/ so ytee can find them.
ytee init --secret-path /path/to/client_secret.json
| Option | Short | Description |
|---|---|---|
--secret-path |
-s |
Path to your client_secret.json downloaded from Google Cloud Console |
--token-path |
-t |
Path to an existing token.json (optional — skip if you don't have one yet) |
⚠️ This must be run at least once before any other command will work.
ytee migrate — Migrate from v0.1.0
If you used ytee version v0.1.0, your credentials were stored under ~/.secrets/. Newer versions store them in ~/.ytee/.google_secrets/.
Run this once to move your existing credentials to the new location:
ytee migrate
Only needed if you previously ran ytee init on v0.1.0.
ytee set-creds — Authenticate with Google
Opens a browser window for Google OAuth authorization and saves the access token to ~/.ytee/.google_secrets/token.json.
ytee set-creds
Run this after init. If your credentials are still valid they are reused automatically — you don't need to re-run this every time. If your token has expired, ytee will automatically open the browser to re-authenticate.
ytee verify-creds — Check credential status
Checks whether client_secret.json and token.json are present in ~/.ytee/.google_secrets/.
ytee verify-creds
ytee upload — Upload a video or directory
Upload a single video:
ytee upload --path video.mp4 --name "My Video Title" --desc "My description"
Upload all videos in a directory:
ytee upload --path ./videos --name "Episode - " --desc "My description"
When a directory path is given, ytee automatically detects it and uploads every file inside. Each filename (without extension) is appended to the --name prefix to form the video title. For example, if the directory contains part1.mp4, the title becomes Episode - part1.
| Option | Short | Description |
|---|---|---|
--path |
-p |
Path to a video file or a directory of videos |
--name / --prefix |
-n |
YouTube video title (used as a prefix for directory uploads) |
--desc |
-d |
YouTube video description applied to all uploaded videos |
--privacy |
— | Privacy setting: unlisted (default), public, or private |
Supported formats: .mp4, .mov, .avi, .wmv, .mkv, .webm, .m4v, .mpeg, .mpg, .flv
After each successful upload, ytee saves a log entry to ~/.ytee/.uploads/uploaded.json.
Uploads show a live progress table displaying upload speed, file size, time elapsed, and time remaining.
ytee show-uploads — View upload history
ytee show-uploads
Prints the contents of ~/.ytee/.uploads/uploaded.json, showing the file path, video title, and YouTube video ID of every past upload.
Full Example Walkthrough
# Step 1 — point ytee to your Google credentials (once)
ytee init --secret-path ~/Downloads/client_secret.json
# Step 2 — authenticate with Google (once, or when token expires)
ytee set-creds
# Step 3 — check credentials are in place (optional)
ytee verify-creds
# Step 4a — upload a single video
ytee upload --path ~/videos/intro.mp4 --name "Introduction" --desc "Welcome to my channel"
# Step 4b — or upload a whole folder
ytee upload --path ~/videos --name "Lecture - " --desc "Course upload"
# Step 5 — view upload history
ytee show-uploads
Error handling & retries
ytee handles common upload failures gracefully:
- Token expired — detected before and during upload, prompts you to run
ytee set-creds - Quota exceeded — YouTube's daily 10,000 unit limit (each upload costs ~1,600 units).
yteereports this clearly when hit. Quota resets at midnight Pacific Time. - Network errors — timeouts, SSL errors, and connection drops are retried automatically with exponential backoff, up to 10 retries
- Server errors — YouTube 5xx errors are retried up to 5 times
- Unsupported file types — filtered out before upload with a clear message
Notes
- Videos are uploaded as unlisted by default. Use
--privacy publicor--privacy privateto change this. - Credentials are stored in
~/.ytee/.google_secrets/(client_secret.jsonandtoken.json). - Upload history is stored in
~/.ytee/.uploads/uploaded.json. - Directory uploads process files sequentially with a short delay between each upload.
Dependencies
| Package | Purpose |
|---|---|
google-api-python-client |
YouTube Data API v3 client |
google-auth-oauthlib |
OAuth 2.0 authentication flow |
rich |
Live progress table and terminal output |
typer |
CLI framework |
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ytee-0.1.5.tar.gz.
File metadata
- Download URL: ytee-0.1.5.tar.gz
- Upload date:
- Size: 11.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d939babf765a1dee8e69aa9067d23be37332b580c8b9e83baf2c93a0a34cd51c
|
|
| MD5 |
38229bd480aef1b8929749bac908e52b
|
|
| BLAKE2b-256 |
7773f23e45658cda1f1de35056430ed97ab642bdc4970e4cc345b8567d2e9ef1
|
Provenance
The following attestation bundles were made for ytee-0.1.5.tar.gz:
Publisher:
publish.yml on rooooop5/ytee
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ytee-0.1.5.tar.gz -
Subject digest:
d939babf765a1dee8e69aa9067d23be37332b580c8b9e83baf2c93a0a34cd51c - Sigstore transparency entry: 1523860749
- Sigstore integration time:
-
Permalink:
rooooop5/ytee@b11a7e982333ddcc357c25e92c612cdbaabc481b -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/rooooop5
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b11a7e982333ddcc357c25e92c612cdbaabc481b -
Trigger Event:
push
-
Statement type:
File details
Details for the file ytee-0.1.5-py3-none-any.whl.
File metadata
- Download URL: ytee-0.1.5-py3-none-any.whl
- Upload date:
- Size: 11.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1647ad5ebbb1f17396c8493da1bc1b3e376458934a5a4d3b7a26a33e0b84db3
|
|
| MD5 |
084fc20422440e36ca8c04ff4cd74e45
|
|
| BLAKE2b-256 |
10e4a27acdfba6651ae946816d1e4c9f60e0b2fcf996078b9d83b1b83da514fb
|
Provenance
The following attestation bundles were made for ytee-0.1.5-py3-none-any.whl:
Publisher:
publish.yml on rooooop5/ytee
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ytee-0.1.5-py3-none-any.whl -
Subject digest:
a1647ad5ebbb1f17396c8493da1bc1b3e376458934a5a4d3b7a26a33e0b84db3 - Sigstore transparency entry: 1523860764
- Sigstore integration time:
-
Permalink:
rooooop5/ytee@b11a7e982333ddcc357c25e92c612cdbaabc481b -
Branch / Tag:
refs/tags/v0.1.5 - Owner: https://github.com/rooooop5
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b11a7e982333ddcc357c25e92c612cdbaabc481b -
Trigger Event:
push
-
Statement type: