YouTube Publisher
Drive → YouTube → Transcript → Metadata → Cleanup.
Setup
1. Google OAuth (required for Drive download + YouTube upload)
- Go to Google Cloud Console
- Create a project → enable Google Drive API and YouTube Data API v3
- Create OAuth 2.0 credentials (Desktop app) → download as
google-oauth-client.json - Run the authorization flow to get
google-oauth-tokens.jsonwith scopes:https://www.googleapis.com/auth/drive.readonlyhttps://www.googleapis.com/auth/youtube.uploadhttps://www.googleapis.com/auth/youtube
Place both files in one of these locations (checked in order):
- Skill root:
youtube-publisher/google-oauth-client.json - Config dir:
youtube-publisher/config/google-oauth-client.json - Workspace:
~/.openclaw/workspace/scripts/google-oauth-client.json - Env vars:
GOOGLE_OAUTH_CLIENTandGOOGLE_OAUTH_TOKENS(paths to files)
2. Transcription API key (at least one required)
Option A — Fireworks Whisper v3 Turbo (preferred: faster, cheaper, $0.0009/min):
- Set
FIREWORKS_API_KEYenv var, or - Save key to
youtube-publisher/config/fireworks-api-key.txt
Option B — Deepgram Nova-3 (fallback: good quality, smart_format):
- Set
DEEPGRAM_API_KEYenv var, or - Save key to
youtube-publisher/config/deepgram-api-key.txt
3. ffmpeg (required)
Must be on PATH. Install: apt install ffmpeg / brew install ffmpeg.
Procedure
Step 1: Extract file ID from Drive URL
Parse the Google Drive URL. Extract file ID from pattern /file/d/{ID}/.
If user provides a raw file ID, use it directly.
Step 2: Download video from Google Drive
- Refresh OAuth access token
- Fetch file metadata (name, size, mimeType) via Drive API v3
- Download file via
?alt=mediaendpoint to temp dir - Log file name and size
Step 3: Upload to YouTube
- Create resumable upload session via YouTube Data API v3
- Set initial metadata: placeholder title, privacy status from user (default:
unlisted) - Upload video file
- Save returned
video_id - Log YouTube URL:
https://youtube.com/watch?v={video_id}
Step 4: Extract audio
ffmpeg -i source.mp4 -vn -acodec libmp3lame -ab 64k -ar 16000 -ac 1 audio.mp3 -y
64kbps mono, 16kHz — optimized for speech transcription, minimal file size.
Step 5: Split into chunks
Split audio into 15-minute segments for parallel transcription:
ffmpeg -i audio.mp3 -ss {start} -t 900 -c copy chunk-{i}.mp3 -y
Step 6: Transcribe (Fireworks or Deepgram)
Fireworks Whisper v3 Turbo (default if FIREWORKS_API_KEY set):
POST https://audio-turbo.us-virginia-1.direct.fireworks.ai/v1/audio/transcriptions
model=whisper-v3-turbo, language={lang}, response_format=verbose_json
Deepgram Nova-3 (fallback if only DEEPGRAM_API_KEY set):
POST https://api.deepgram.com/v1/listen?model=nova-3&language={lang}&smart_format=true¶graphs=true
Override with --transcriber fireworks|deepgram.
Chunks transcribed in parallel (6 workers). Merge with time offset: chunk_index × 900 seconds.
Step 7: Generate timestamps
Extract topic boundaries from transcript. Rules:
- Minimum 3 minutes between timestamps
- First timestamp MUST be
0:00 - Format under 1 hour:
MM:SS(e.g.,05:30,45:12) - Format 1 hour and over:
H:MM:SS(e.g.,1:00:01,1:25:30) - NEVER write
60:01or75:30— convert to1:00:01,1:15:30
Step 8: Update YouTube metadata
Update video via YouTube Data API v3 PUT /videos?part=snippet:
- Title: generate from transcript content (concise, descriptive)
- Description: summary + timestamps block + relevant links
- Tags: extract key topics
- Category:
28(Science & Technology) unless user specifies otherwise - Language: from user or auto-detect
Step 9: Clean up temp files
MANDATORY. No large files left behind.
rm -rf /tmp/yt-publisher-*/
Verify: find /tmp -maxdepth 1 \( -name "*.mp4" -o -name "*.mp3" \) -size +1M should return nothing.
Script
Full automated pipeline:
python3 scripts/publish.py "DRIVE_URL" [--privacy unlisted] [--language ru] [--transcriber auto|fireworks|deepgram]
Options:
--privacy—public,unlisted(default),private--language— language code for transcription (default:ru)--transcriber— force backend:auto(default),fireworks,deepgram--skip-upload— transcribe only, don't upload to YouTube--video-id— update existing video metadata instead of uploading new--title— override auto-generated title--keep-files— don't delete temp media files after processing
Error Handling
- OAuth expired: refresh token automatically; if refresh fails, ask user to re-authorize
- Drive 404: file not shared or wrong ID — ask user to check sharing settings
- YouTube quota exceeded: daily upload limit is 6 videos — inform user, retry tomorrow
- Transcription timeout: retry failed chunk once; if still fails, skip and note gap
- Large files (>2GB): warn user about upload time; use chunked upload
Timestamp Format Reference
0→0:00330→05:302712→45:123601→1:00:014530→1:15:307200→2:00:00