Skip to main content
Generalhamelsmu

youtube

Manage your YouTube channel — upload, list, edit metadata, schedule/unschedule videos, set thumbnails, download your own private videos, get transcripts, generate AI chapter summaries, and post comments (with a Chrome-automation playbook for pinning). Use when asked to upload to YouTube, schedule a video, edit video metadata, download a private YouTube video, get a transcript, generate chapters, or post/pin a comment.

Stars
57
Source
hamelsmu/hamel
Updated
2026-04-18
Slug
hamelsmu--hamel--youtube
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/hamelsmu/hamel/HEAD/plugins/hamel-tools/skills/youtube/SKILL.md -o .claude/skills/youtube.md

Drops the SKILL.md into .claude/skills/youtube.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

YouTube Channel Management

Use the youtube CLI tool to manage your YouTube channel: upload videos, list uploads, edit metadata, schedule/unschedule publication, set thumbnails, download your own videos (including private ones), get transcripts, and generate AI chapter summaries.

Architecture

Three separate systems:

  1. YouTube Data API v3 + OAuth 2.0 — upload, list, update, schedule, thumbnails
  2. yt-dlp + browser cookies — download your own videos (including private)
  3. youtube_transcript_api + Gemini — transcripts (fetches existing captions) and AI chapter generation

The YouTube Data API does not have a download endpoint for uploaded video files. Download is handled separately via yt-dlp with authenticated cookies. Transcripts are fetched from YouTube's existing captions (no AI needed). Chapter generation uses Google Gemini.

Setup

1. OAuth Credentials (Required for API operations)

Create OAuth 2.0 credentials in the Google Cloud Console:

  1. Create a project (or use an existing one)
  2. Enable the YouTube Data API v3
  3. Create OAuth 2.0 Client ID (type: Desktop app)
  4. Download the client secret JSON

Provide credentials via one of:

# Option A: Place the downloaded JSON file at the default path
cp ~/Downloads/client_secret_*.json ~/.youtube_client_secret.json

# Option B: Set env vars
export YOUTUBE_CLIENT_ID="your_client_id"
export YOUTUBE_CLIENT_SECRET="your_client_secret"

# Option C: Point to your JSON file
export YOUTUBE_CLIENT_SECRETS_FILE="/path/to/client_secret.json"

Then authenticate:

youtube auth

This opens a browser for Google login and saves the token to ~/.youtube_oauth_token.json.

2. yt-dlp (Required for download only)

pip install yt-dlp
# or
brew install yt-dlp

Commands

Command Description
youtube auth Authenticate via OAuth 2.0 (opens browser)
youtube upload Upload a video with metadata
youtube list List your uploaded videos
youtube update Edit metadata of an existing video
youtube schedule Schedule a private video for future publication
youtube unschedule Revert a scheduled video to private draft
youtube reschedule Change the scheduled publish time
youtube set-thumbnail Set or replace a video thumbnail
youtube download Download a video using yt-dlp (supports private videos)
youtube transcribe Get transcript of a YouTube video (fetches existing captions)
youtube chapters Generate AI chapter summaries using Gemini
youtube comment Post a top-level comment on a video (API cannot pin — see Chrome playbook below)

Not supported: youtube delete — deletion is explicitly excluded. Pinning comments is also not supported by the YouTube Data API; it must be done in Studio UI (see the Chrome automation playbook below).

Note: transcribe and chapters do NOT require YouTube OAuth. transcribe works with any public video. chapters requires GEMINI_API_KEY.

Usage

Upload a Video

# Upload as private (default)
youtube upload --file video.mp4 --title "My Video" --description "Description here"

# Upload with tags and schedule
youtube upload --file video.mp4 --title "My Video" --tags "tag1, tag2" --publish-at 2026-04-10T16:00:00Z

# Upload as public
youtube upload --file video.mp4 --title "My Video" --privacy public -v

List Uploads

# List recent uploads as a table
youtube list

# List more videos
youtube list -n 50

# Output as JSON
youtube list --json

# Verbose mode (shows tags, category)
youtube list -v

Update Metadata

# Update title only
youtube update --id VIDEO_ID --title "New Title"

# Update multiple fields
youtube update --id VIDEO_ID --title "New Title" --description "New desc" --tags "a, b, c"

# Change privacy
youtube update --id VIDEO_ID --privacy unlisted

# Change category
youtube update --id VIDEO_ID --category 28

Safe updates: The tool always fetches the current video first, merges your changes, and sends a complete payload — preserving required fields like title and categoryId.

Schedule / Unschedule / Reschedule

# Schedule a private video
youtube schedule --id VIDEO_ID --publish-at 2026-04-10T16:00:00Z

# Unschedule back to private draft
youtube unschedule --id VIDEO_ID

# Reschedule to a new time
youtube reschedule --id VIDEO_ID --publish-at 2026-04-11T16:00:00Z

Scheduling rules: publishAt only works on private videos that have never been published. You cannot reschedule a previously-public video.

Set Thumbnail

youtube set-thumbnail --id VIDEO_ID --file thumbnail.jpg

Download Videos

By default, youtube download automatically extracts cookies from Chrome for authentication. This means you just need to be logged into YouTube in Chrome — no manual cookie export needed.

# Download a video (auto-extracts Chrome cookies by default)
youtube download --id VIDEO_ID

# Download by URL
youtube download --url "https://youtu.be/VIDEO_ID"

# Save to specific path
youtube download --id VIDEO_ID -o ~/Downloads/video.mp4

# Use Firefox instead of Chrome
youtube download --id VIDEO_ID --cookies-from-browser firefox

# Specify a custom Chrome profile path
youtube download --id VIDEO_ID --cookies-from-browser "chrome:/path/to/profile"

# Use a cookies.txt file instead
youtube download --id VIDEO_ID --cookies ~/cookies.txt

# Skip cookie extraction (public videos only)
youtube download --id VIDEO_ID --no-cookies

# Choose format
youtube download --id VIDEO_ID -f "bestvideo+bestaudio"

How it works: yt-dlp reads cookies directly from Chrome's cookie database on disk. You must be logged into YouTube in Chrome. No browser window is opened — it reads the stored cookies programmatically. For private videos, the Chrome session must be logged into the account that owns the video.

Transcribe Videos

Fetches existing YouTube captions/subtitles — no AI or OAuth needed. For private/unplayable videos, automatically downloads via yt-dlp (with Chrome cookies) and transcribes locally with Whisper.

# Get transcript by URL
youtube transcribe "https://youtu.be/VIDEO_ID"

# Get transcript by video ID
youtube transcribe VIDEO_ID

# Timestamps in seconds format
youtube transcribe "https://youtu.be/VIDEO_ID" --seconds

# Transcribe a local video file (uses Whisper — supports mp4, webm, mkv, etc.)
youtube transcribe video.mp4

# Private videos work too (auto-downloads with Chrome cookies, then transcribes locally)
youtube transcribe "https://youtu.be/PRIVATE_VIDEO_ID"

# Save to file
youtube transcribe "https://youtu.be/VIDEO_ID" > transcript.txt

Post a Comment

Posts a top-level comment on a video as the authenticated channel. Uses commentThreads.insert with the youtube.force-ssl scope (already included in the OAuth token).

youtube comment --id VIDEO_ID --text "Your comment text here"

Prints the Thread ID, Comment ID, and a Studio deep link for pinning.

Pinning is NOT available via the API — it's a Studio-UI-only action. Use the Chrome automation playbook below after posting.

Pin a Comment via Chrome Automation

The YouTube Data API exposes no pin endpoint, so pinning requires driving Studio's UI. This playbook is verified end-to-end — follow it to avoid fishing for selectors.

Prerequisites: claude-in-chrome MCP connected and logged into the target YouTube channel in Chrome.

Steps:

  1. Navigate to https://studio.youtube.com/video/<VIDEO_ID>/comments in a fresh tab (create one with tabs_create_mcp — never clobber an existing tab).
  2. Clear the "Response status: Unresponded" filter chip. Studio hides the channel owner's own comments under this filter by default, so your just-posted comment will NOT appear until you clear it.
    • find query: "Response status filter chip with X to clear" — click the returned ref for the Remove (X) sub-element, not the chip itself.
  3. Screenshot to confirm your comment from @<your-handle> is now visible (labeled e.g. "1 minute ago").
  4. Open the kebab (three-dot) menu on YOUR comment row.
    • find query: "three-dot kebab action menu button on the <your-handle> comment row".
  5. Click "Pin" from the dropdown.
    • find query: "Pin menu item in the action menu dropdown".
    • ⚠️ Known quirk: the find-based click on the Pin menu item sometimes re-opens the dropdown instead of activating the item. If the confirmation dialog doesn't appear, fall back to a coordinate click on the visible "Pin" text — take a screenshot, read the coords, and computer.left_click there. This has been the consistent failure mode across multiple runs.
  6. Click "Pin" in the "Pin this comment?" confirmation dialog.
    • find query: "Pin button in the \"Pin this comment?\" confirmation dialog".
  7. Verify via screenshot — the comment should move to the top and show "📌 Pinned by @<your-handle>".

Parallelization: multiple subagents can pin comments on different videos in parallel. Each agent must create its own fresh tab (tabs_create_mcp) and only operate on that tabId — agents sharing a tab will thrash. Each video has its own independent pinned slot, so there's no cross-video contention.

Generate Chapters

Uses Google Gemini to generate chapter summaries with timestamps.

# Generate chapters for a YouTube video
youtube chapters "https://youtu.be/VIDEO_ID"

# Generate chapters for a local MP4
youtube chapters video.mp4

Requires: GEMINI_API_KEY environment variable. Get one at https://aistudio.google.com/apikey

Options Reference

Global Options

Option Short Description
--verbose -v Show progress and debug info

Upload Options

Option Short Description
--file -f Path to video file (required)
--title -t Video title (required)
--description -d Video description
--tags Comma-separated tags
--category YouTube category ID (default: 22)
--privacy -p public, private, unlisted (default: private)
--publish-at ISO 8601 timestamp for scheduling

Update Options

Option Short Description
--id Video ID (required)
--title -t New title
--description -d New description
--tags New comma-separated tags (replaces existing)
--category New category ID
--privacy -p New privacy status

Comment Options

Option Short Description
--id Video ID (required)
--text -t Comment text (required)

Download Options

Option Short Description
--id YouTube video ID
--url -u YouTube video URL
--output -o Output file path
--cookies Path to cookies.txt file
--cookies-from-browser Browser name or path (default: chrome). Examples: chrome, firefox, chrome:/path/to/profile
--format -f yt-dlp format string
--no-cookies Skip automatic cookie extraction

Environment Variables

Variable Description
YOUTUBE_CLIENT_ID OAuth 2.0 client ID
YOUTUBE_CLIENT_SECRET OAuth 2.0 client secret
YOUTUBE_CLIENT_SECRETS_FILE Path to client secret JSON (default: ~/.youtube_client_secret.json)
YOUTUBE_TOKEN_FILE Path to stored OAuth token (default: ~/.youtube_oauth_token.json)
GEMINI_API_KEY Google Gemini API key (required only for youtube chapters)

Requirements

  • The hamel package must be installed: pip install hamel
  • For download: yt-dlp must be installed separately
  • For chapters: GEMINI_API_KEY environment variable must be set
  • For local MP4 transcription: openai-whisper and ffmpeg are needed

Troubleshooting

"No OAuth credentials found": Set YOUTUBE_CLIENT_ID and YOUTUBE_CLIENT_SECRET env vars (or place a client_secret JSON file at ~/.youtube_client_secret.json), then run youtube auth.

"Token refresh failed": Your OAuth token has expired. Run youtube auth again to re-authenticate.

"yt-dlp not found": Install with pip install yt-dlp or brew install yt-dlp.

"Video not found or not accessible": Check the video ID is correct and that your authenticated account has access.

"Could not find browser cookies database": Chrome is not at the default location. Specify the profile path: --cookies-from-browser 'chrome:/path/to/profile', or use Firefox: --cookies-from-browser firefox.

"Authentication required for this video": You need to be logged into YouTube in Chrome. Open Chrome, go to youtube.com, sign in, then retry the download.

Scheduling fails: Only private videos that have never been published can be scheduled. If the video was previously public, scheduling will not work.

Complete Setup Walkthrough

If you're starting from scratch on a new machine:

  1. Install the package: pip install hamel
  2. Install yt-dlp (for downloads): pip install yt-dlp
  3. Create OAuth credentials:
  4. Set environment variables:
    export YOUTUBE_CLIENT_ID='your-client-id.apps.googleusercontent.com'
    export YOUTUBE_CLIENT_SECRET='your-client-secret'
    
  5. Authenticate: youtube auth (opens browser for one-time Google login)
  6. Verify: youtube list (should show your uploads)
  7. For downloads: Make sure you're logged into YouTube in Chrome, then youtube download --id VIDEO_ID
  8. For transcripts: youtube transcribe "https://youtu.be/VIDEO_ID" (no extra setup needed)
  9. For chapters: Set GEMINI_API_KEY env var, then youtube chapters "https://youtu.be/VIDEO_ID"