YouTube Transcript Downloader skill

Download YouTube video transcripts when user provides a YouTube URL or asks to download/get/fetch a transcript from YouTube.

by michalparkola·MIT license·GitHub ↗

★ 547 Stars on the repo·Checked

npx degit michalparkola/tapestry-skills-for-claude-code/youtube-transcript#main ~/.claude/skills/youtube-transcript

SKILL.md · 13.4 KB · names 1 other file — download is this file only · installs the whole folder to ~/.claude/skills/youtube-transcript

Files of YouTube Transcript Downloader

Files 1 file
Show the full text416 lines

YouTube Transcript Downloader

This skill helps download transcripts (subtitles/captions) from YouTube videos using yt-dlp.

When to Use This Skill

Activate this skill when the user:

  • Provides a YouTube URL and wants the transcript
  • Asks to "download transcript from YouTube"
  • Wants to "get captions" or "get subtitles" from a video
  • Asks to "transcribe a YouTube video"
  • Needs text content from a YouTube video

How It Works

Priority Order:
  1. Check if yt-dlp is installed - install if needed
  2. List available subtitles - see what's actually available
  3. Try manual subtitles first (--write-sub) - highest quality
  4. Fallback to auto-generated (--write-auto-sub) - usually available
  5. Last resort: Whisper transcription - if no subtitles exist (requires user confirmation)
  6. Confirm the download and show the user where the file is saved
  7. Optionally clean up the VTT format if the user wants plain text

Installation Check

IMPORTANT: Always check if yt-dlp is installed first:

which yt-dlp || command -v yt-dlp
If Not Installed

Attempt automatic installation based on the system:

macOS (Homebrew):

brew install yt-dlp

Linux (apt/Debian/Ubuntu):

sudo apt update && sudo apt install -y yt-dlp

Alternative (pip - works on all systems):

pip3 install yt-dlp
# or
python3 -m pip install yt-dlp

If installation fails: Inform the user they need to install yt-dlp manually and provide them with installation instructions from https://github.com/yt-dlp/yt-dlp#installation

Check Available Subtitles

ALWAYS do this first before attempting to download:

yt-dlp --list-subs "YOUTUBE_URL"

This shows what subtitle types are available without downloading anything. Look for:

  • Manual subtitles (better quality)
  • Auto-generated subtitles (usually available)
  • Available languages

Download Strategy

Option 1: Manual Subtitles (Preferred)

Try this first - highest quality, human-created:

yt-dlp --write-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"
Option 2: Auto-Generated Subtitles (Fallback)

If manual subtitles aren't available:

yt-dlp --write-auto-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"

Both commands create a .vtt file (WebVTT subtitle format).

Option 3: Whisper Transcription (Last Resort)

ONLY use this if both manual and auto-generated subtitles are unavailable.

Step 1: Show File Size and Ask for Confirmation
# Get audio file size estimate
yt-dlp --print "%(filesize,filesize_approx)s" -f "bestaudio" "YOUTUBE_URL"

# Or get duration to estimate
yt-dlp --print "%(duration)s %(title)s" "YOUTUBE_URL"

IMPORTANT: Display the file size to the user and ask: "No subtitles are available. I can download the audio (approximately X MB) and transcribe it using Whisper. Would you like to proceed?"

Wait for user confirmation before continuing.

Step 2: Check for Whisper Installation
command -v whisper

If not installed, ask user: "Whisper is not installed. Install it with pip install openai-whisper (requires ~1-3GB for models)? This is a one-time installation."

Wait for user confirmation before installing.

Install if approved:

pip3 install openai-whisper
Step 3: Download Audio Only
yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "YOUTUBE_URL"
Step 4: Transcribe with Whisper
# Auto-detect language (recommended)
whisper audio_VIDEO_ID.mp3 --model base --output_format vtt

# Or specify language if known
whisper audio_VIDEO_ID.mp3 --model base --language en --output_format vtt

Model Options (stick to base for now):

  • tiny - fastest, least accurate (~1GB)
  • base - good balance (~1GB) ← USE THIS
  • small - better accuracy (~2GB)
  • medium - very good (~5GB)
  • large - best accuracy (~10GB)
Step 5: Cleanup

After transcription completes, ask user: "Transcription complete! Would you like me to delete the audio file to save space?"

If yes:

rm audio_VIDEO_ID.mp3

Getting Video Information

Extract Video Title (for filename)
yt-dlp --print "%(title)s" "YOUTUBE_URL"

Use this to create meaningful filenames based on the video title. Clean the title for filesystem compatibility:

  • Replace / with -
  • Replace special characters that might cause issues
  • Consider using sanitized version: $(yt-dlp --print "%(title)s" "URL" | tr '/' '-' | tr ':' '-')

Post-Processing

YouTube's auto-generated VTT files contain duplicate lines because captions are shown progressively with overlapping timestamps. Always deduplicate when converting to plain text while preserving the original speaking order.

python3 -c "
import sys, re
seen = set()
with open('transcript.en.vtt', 'r') as f:
    for line in f:
        line = line.strip()
        if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
            clean = re.sub('<[^>]*>', '', line)
            clean = clean.replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<')
            if clean and clean not in seen:
                print(clean)
                seen.add(clean)
" > transcript.txt
Complete Post-Processing with Video Title
# Get video title
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "YOUTUBE_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')

# Find the VTT file
VTT_FILE=$(ls *.vtt | head -n 1)

# Convert with deduplication
python3 -c "
import sys, re
seen = set()
with open('$VTT_FILE', 'r') as f:
    for line in f:
        line = line.strip()
        if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
            clean = re.sub('<[^>]*>', '', line)
            clean = clean.replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<')
            if clean and clean not in seen:
                print(clean)
                seen.add(clean)
" > "${VIDEO_TITLE}.txt"

echo "✓ Saved to: ${VIDEO_TITLE}.txt"

# Clean up VTT file
rm "$VTT_FILE"
echo "✓ Cleaned up temporary VTT file"

Output Formats

  • VTT format (.vtt): Includes timestamps and formatting, good for video players
  • Plain text (.txt): Just the text content, good for reading or analysis

Tips

  • The filename will be {output_name}.{language_code}.vtt (e.g., transcript.en.vtt)
  • Most YouTube videos have auto-generated English subtitles
  • Some videos may have multiple language options
  • If auto-subtitles aren't available, try --write-sub instead for manual subtitles

Complete Workflow Example

VIDEO_URL="https://www.youtube.com/watch?v=dQw4w9WgXcQ"

# Get video title for filename
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
OUTPUT_NAME="transcript_temp"

# ============================================
# STEP 1: Check if yt-dlp is installed
# ============================================
if ! command -v yt-dlp &> /dev/null; then
    echo "yt-dlp not found, attempting to install..."
    if command -v brew &> /dev/null; then
        brew install yt-dlp
    elif command -v apt &> /dev/null; then
        sudo apt update && sudo apt install -y yt-dlp
    else
        pip3 install yt-dlp
    fi
fi

# ============================================
# STEP 2: List available subtitles
# ============================================
echo "Checking available subtitles..."
yt-dlp --list-subs "$VIDEO_URL"

# ============================================
# STEP 3: Try manual subtitles first
# ============================================
echo "Attempting to download manual subtitles..."
if yt-dlp --write-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
    echo "✓ Manual subtitles downloaded successfully!"
    ls -lh ${OUTPUT_NAME}.*
else
    # ============================================
    # STEP 4: Fallback to auto-generated
    # ============================================
    echo "Manual subtitles not available. Trying auto-generated..."
    if yt-dlp --write-auto-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
        echo "✓ Auto-generated subtitles downloaded successfully!"
        ls -lh ${OUTPUT_NAME}.*
    else
        # ============================================
        # STEP 5: Last resort - Whisper transcription
        # ============================================
        echo "⚠ No subtitles available for this video."

        # Get file size
        FILE_SIZE=$(yt-dlp --print "%(filesize_approx)s" -f "bestaudio" "$VIDEO_URL")
        DURATION=$(yt-dlp --print "%(duration)s" "$VIDEO_URL")
        TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL")

        echo "Video: $TITLE"
        echo "Duration: $((DURATION / 60)) minutes"
        echo "Audio size: ~$((FILE_SIZE / 1024 / 1024)) MB"
        echo ""
        echo "Would you like to download and transcribe with Whisper? (y/n)"
        read -r RESPONSE

        if [[ "$RESPONSE" =~ ^[Yy]$ ]]; then
            # Check for Whisper
            if ! command -v whisper &> /dev/null; then
                echo "Whisper not installed. Install now? (requires ~1-3GB) (y/n)"
                read -r INSTALL_RESPONSE
                if [[ "$INSTALL_RESPONSE" =~ ^[Yy]$ ]]; then
                    pip3 install openai-whisper
                else
                    echo "Cannot proceed without Whisper. Exiting."
                    exit 1
                fi
            fi

            # Download audio
            echo "Downloading audio..."
            yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "$VIDEO_URL"

            # Get the actual audio filename
            AUDIO_FILE=$(ls audio_*.mp3 | head -n 1)

            # Transcribe
            echo "Transcribing with Whisper (this may take a few minutes)..."
            whisper "$AUDIO_FILE" --model base --output_format vtt

            # Cleanup
            echo "Transcription complete! Delete audio file? (y/n)"
            read -r CLEANUP_RESPONSE
            if [[ "$CLEANUP_RESPONSE" =~ ^[Yy]$ ]]; then
                rm "$AUDIO_FILE"
                echo "Audio file deleted."
            fi

            ls -lh *.vtt
        else
            echo "Transcription cancelled."
            exit 0
        fi
    fi
fi

# ============================================
# STEP 6: Convert to readable plain text with deduplication
# ============================================
VTT_FILE=$(ls ${OUTPUT_NAME}*.vtt 2>/dev/null || ls *.vtt | head -n 1)
if [ -f "$VTT_FILE" ]; then
    echo "Converting to readable format and removing duplicates..."
    python3 -c "
import sys, re
seen = set()
with open('$VTT_FILE', 'r') as f:
    for line in f:
        line = line.strip()
        if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
            clean = re.sub('<[^>]*>', '', line)
            clean = clean.replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<')
            if clean and clean not in seen:
                print(clean)
                seen.add(clean)
" > "${VIDEO_TITLE}.txt"
    echo "✓ Saved to: ${VIDEO_TITLE}.txt"

    # Clean up temporary VTT file
    rm "$VTT_FILE"
    echo "✓ Cleaned up temporary VTT file"
else
    echo "⚠ No VTT file found to convert"
fi

echo "✓ Complete!"

Note: This complete workflow handles all scenarios with proper error checking and user prompts at each decision point.

Error Handling

Common Issues and Solutions:

1. yt-dlp not installed

  • Attempt automatic installation based on system (Homebrew/apt/pip)
  • If installation fails, provide manual installation link
  • Verify installation before proceeding

2. No subtitles available

  • List available subtitles first to confirm
  • Try both --write-sub and --write-auto-sub
  • If both fail, offer Whisper transcription option
  • Show file size and ask for user confirmation before downloading audio

3. Invalid or private video

  • Check if URL is correct format: https://www.youtube.com/watch?v=VIDEO_ID
  • Some videos may be private, age-restricted, or geo-blocked
  • Inform user of the specific error from yt-dlp

4. Whisper installation fails

  • May require system dependencies (ffmpeg, rust)
  • Provide fallback: "Install manually with: pip3 install openai-whisper"
  • Check available disk space (models require 1-10GB depending on size)

5. Download interrupted or failed

  • Check internet connection
  • Verify sufficient disk space
  • Try again with --no-check-certificate if SSL issues occur

6. Multiple subtitle languages

  • By default, yt-dlp downloads all available languages
  • Can specify with --sub-langs en for English only
  • List available with --list-subs first
Best Practices:
  • ✅ Always check what's available before attempting download (--list-subs)
  • ✅ Verify success at each step before proceeding to next
  • ✅ Ask user before large downloads (audio files, Whisper models)
  • ✅ Clean up temporary files after processing
  • ✅ Provide clear feedback about what's happening at each stage
  • ✅ Handle errors gracefully with helpful messages
1---
2name: youtube-transcript
3description: Download YouTube video transcripts when user provides a YouTube URL or asks to download/get/fetch a transcript from YouTube. Also use when user wants to transcribe or get captions/subtitles from a YouTube video.
4allowed-tools: Bash,Read,Write
5---
6 
7# YouTube Transcript Downloader
8 
9This skill helps download transcripts (subtitles/captions) from YouTube videos using yt-dlp.
10 
11## When to Use This Skill
12 
13Activate this skill when the user:
14- Provides a YouTube URL and wants the transcript
15- Asks to "download transcript from YouTube"
16- Wants to "get captions" or "get subtitles" from a video
17- Asks to "transcribe a YouTube video"
18- Needs text content from a YouTube video
19 
20## How It Works
21 
22### Priority Order:
231. **Check if yt-dlp is installed** - install if needed
242. **List available subtitles** - see what's actually available
253. **Try manual subtitles first** (`--write-sub`) - highest quality
264. **Fallback to auto-generated** (`--write-auto-sub`) - usually available
275. **Last resort: Whisper transcription** - if no subtitles exist (requires user confirmation)
286. **Confirm the download** and show the user where the file is saved
297. **Optionally clean up** the VTT format if the user wants plain text
30 
31## Installation Check
32 
33**IMPORTANT**: Always check if yt-dlp is installed first:
34 
35```bash
36which yt-dlp || command -v yt-dlp
37```
38 
39### If Not Installed
40 
41Attempt automatic installation based on the system:
42 
43**macOS (Homebrew)**:
44```bash
45brew install yt-dlp
46```
47 
48**Linux (apt/Debian/Ubuntu)**:
49```bash
50sudo apt update && sudo apt install -y yt-dlp
51```
52 
53**Alternative (pip - works on all systems)**:
54```bash
55pip3 install yt-dlp
56# or
57python3 -m pip install yt-dlp
58```
59 
60**If installation fails**: Inform the user they need to install yt-dlp manually and provide them with installation instructions from https://github.com/yt-dlp/yt-dlp#installation
61 
62## Check Available Subtitles
63 
64**ALWAYS do this first** before attempting to download:
65 
66```bash
67yt-dlp --list-subs "YOUTUBE_URL"
68```
69 
70This shows what subtitle types are available without downloading anything. Look for:
71- Manual subtitles (better quality)
72- Auto-generated subtitles (usually available)
73- Available languages
74 
75## Download Strategy
76 
77### Option 1: Manual Subtitles (Preferred)
78 
79Try this first - highest quality, human-created:
80 
81```bash
82yt-dlp --write-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"
83```
84 
85### Option 2: Auto-Generated Subtitles (Fallback)
86 
87If manual subtitles aren't available:
88 
89```bash
90yt-dlp --write-auto-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"
91```
92 
93Both commands create a `.vtt` file (WebVTT subtitle format).
94 
95## Option 3: Whisper Transcription (Last Resort)
96 
97**ONLY use this if both manual and auto-generated subtitles are unavailable.**
98 
99### Step 1: Show File Size and Ask for Confirmation
100 
101```bash
102# Get audio file size estimate
103yt-dlp --print "%(filesize,filesize_approx)s" -f "bestaudio" "YOUTUBE_URL"
104 
105# Or get duration to estimate
106yt-dlp --print "%(duration)s %(title)s" "YOUTUBE_URL"
107```
108 
109**IMPORTANT**: Display the file size to the user and ask: "No subtitles are available. I can download the audio (approximately X MB) and transcribe it using Whisper. Would you like to proceed?"
110 
111**Wait for user confirmation before continuing.**
112 
113### Step 2: Check for Whisper Installation
114 
115```bash
116command -v whisper
117```
118 
119If not installed, ask user: "Whisper is not installed. Install it with `pip install openai-whisper` (requires ~1-3GB for models)? This is a one-time installation."
120 
121**Wait for user confirmation before installing.**
122 
123Install if approved:
124```bash
125pip3 install openai-whisper
126```
127 
128### Step 3: Download Audio Only
129 
130```bash
131yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "YOUTUBE_URL"
132```
133 
134### Step 4: Transcribe with Whisper
135 
136```bash
137# Auto-detect language (recommended)
138whisper audio_VIDEO_ID.mp3 --model base --output_format vtt
139 
140# Or specify language if known
141whisper audio_VIDEO_ID.mp3 --model base --language en --output_format vtt
142```
143 
144**Model Options** (stick to `base` for now):
145- `tiny` - fastest, least accurate (~1GB)
146- `base` - good balance (~1GB) ← **USE THIS**
147- `small` - better accuracy (~2GB)
148- `medium` - very good (~5GB)
149- `large` - best accuracy (~10GB)
150 
151### Step 5: Cleanup
152 
153After transcription completes, ask user: "Transcription complete! Would you like me to delete the audio file to save space?"
154 
155If yes:
156```bash
157rm audio_VIDEO_ID.mp3
158```
159 
160## Getting Video Information
161 
162### Extract Video Title (for filename)
163 
164```bash
165yt-dlp --print "%(title)s" "YOUTUBE_URL"
166```
167 
168Use this to create meaningful filenames based on the video title. Clean the title for filesystem compatibility:
169- Replace `/` with `-`
170- Replace special characters that might cause issues
171- Consider using sanitized version: `$(yt-dlp --print "%(title)s" "URL" | tr '/' '-' | tr ':' '-')`
172 
173## Post-Processing
174 
175### Convert to Plain Text (Recommended)
176 
177YouTube's auto-generated VTT files contain **duplicate lines** because captions are shown progressively with overlapping timestamps. Always deduplicate when converting to plain text while preserving the original speaking order.
178 
179```bash
180python3 -c "
181import sys, re
182seen = set()
183with open('transcript.en.vtt', 'r') as f:
184 for line in f:
185 line = line.strip()
186 if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
187 clean = re.sub('<[^>]*>', '', line)
188 clean = clean.replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<')
189 if clean and clean not in seen:
190 print(clean)
191 seen.add(clean)
192" > transcript.txt
193```
194 
195### Complete Post-Processing with Video Title
196 
197```bash
198# Get video title
199VIDEO_TITLE=$(yt-dlp --print "%(title)s" "YOUTUBE_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
200 
201# Find the VTT file
202VTT_FILE=$(ls *.vtt | head -n 1)
203 
204# Convert with deduplication
205python3 -c "
206import sys, re
207seen = set()
208with open('$VTT_FILE', 'r') as f:
209 for line in f:
210 line = line.strip()
211 if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
212 clean = re.sub('<[^>]*>', '', line)
213 clean = clean.replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<')
214 if clean and clean not in seen:
215 print(clean)
216 seen.add(clean)
217" > "${VIDEO_TITLE}.txt"
218 
219echo "✓ Saved to: ${VIDEO_TITLE}.txt"
220 
221# Clean up VTT file
222rm "$VTT_FILE"
223echo "✓ Cleaned up temporary VTT file"
224```
225 
226## Output Formats
227 
228- **VTT format** (`.vtt`): Includes timestamps and formatting, good for video players
229- **Plain text** (`.txt`): Just the text content, good for reading or analysis
230 
231## Tips
232 
233- The filename will be `{output_name}.{language_code}.vtt` (e.g., `transcript.en.vtt`)
234- Most YouTube videos have auto-generated English subtitles
235- Some videos may have multiple language options
236- If auto-subtitles aren't available, try `--write-sub` instead for manual subtitles
237 
238## Complete Workflow Example
239 
240```bash
241VIDEO_URL="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
242 
243# Get video title for filename
244VIDEO_TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
245OUTPUT_NAME="transcript_temp"
246 
247# ============================================
248# STEP 1: Check if yt-dlp is installed
249# ============================================
250if ! command -v yt-dlp &> /dev/null; then
251 echo "yt-dlp not found, attempting to install..."
252 if command -v brew &> /dev/null; then
253 brew install yt-dlp
254 elif command -v apt &> /dev/null; then
255 sudo apt update && sudo apt install -y yt-dlp
256 else
257 pip3 install yt-dlp
258 fi
259fi
260 
261# ============================================
262# STEP 2: List available subtitles
263# ============================================
264echo "Checking available subtitles..."
265yt-dlp --list-subs "$VIDEO_URL"
266 
267# ============================================
268# STEP 3: Try manual subtitles first
269# ============================================
270echo "Attempting to download manual subtitles..."
271if yt-dlp --write-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
272 echo "✓ Manual subtitles downloaded successfully!"
273 ls -lh ${OUTPUT_NAME}.*
274else
275 # ============================================
276 # STEP 4: Fallback to auto-generated
277 # ============================================
278 echo "Manual subtitles not available. Trying auto-generated..."
279 if yt-dlp --write-auto-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
280 echo "✓ Auto-generated subtitles downloaded successfully!"
281 ls -lh ${OUTPUT_NAME}.*
282 else
283 # ============================================
284 # STEP 5: Last resort - Whisper transcription
285 # ============================================
286 echo "⚠ No subtitles available for this video."
287 
288 # Get file size
289 FILE_SIZE=$(yt-dlp --print "%(filesize_approx)s" -f "bestaudio" "$VIDEO_URL")
290 DURATION=$(yt-dlp --print "%(duration)s" "$VIDEO_URL")
291 TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL")
292 
293 echo "Video: $TITLE"
294 echo "Duration: $((DURATION / 60)) minutes"
295 echo "Audio size: ~$((FILE_SIZE / 1024 / 1024)) MB"
296 echo ""
297 echo "Would you like to download and transcribe with Whisper? (y/n)"
298 read -r RESPONSE
299 
300 if [[ "$RESPONSE" =~ ^[Yy]$ ]]; then
301 # Check for Whisper
302 if ! command -v whisper &> /dev/null; then
303 echo "Whisper not installed. Install now? (requires ~1-3GB) (y/n)"
304 read -r INSTALL_RESPONSE
305 if [[ "$INSTALL_RESPONSE" =~ ^[Yy]$ ]]; then
306 pip3 install openai-whisper
307 else
308 echo "Cannot proceed without Whisper. Exiting."
309 exit 1
310 fi
311 fi
312 
313 # Download audio
314 echo "Downloading audio..."
315 yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "$VIDEO_URL"
316 
317 # Get the actual audio filename
318 AUDIO_FILE=$(ls audio_*.mp3 | head -n 1)
319 
320 # Transcribe
321 echo "Transcribing with Whisper (this may take a few minutes)..."
322 whisper "$AUDIO_FILE" --model base --output_format vtt
323 
324 # Cleanup
325 echo "Transcription complete! Delete audio file? (y/n)"
326 read -r CLEANUP_RESPONSE
327 if [[ "$CLEANUP_RESPONSE" =~ ^[Yy]$ ]]; then
328 rm "$AUDIO_FILE"
329 echo "Audio file deleted."
330 fi
331 
332 ls -lh *.vtt
333 else
334 echo "Transcription cancelled."
335 exit 0
336 fi
337 fi
338fi
339 
340# ============================================
341# STEP 6: Convert to readable plain text with deduplication
342# ============================================
343VTT_FILE=$(ls ${OUTPUT_NAME}*.vtt 2>/dev/null || ls *.vtt | head -n 1)
344if [ -f "$VTT_FILE" ]; then
345 echo "Converting to readable format and removing duplicates..."
346 python3 -c "
347import sys, re
348seen = set()
349with open('$VTT_FILE', 'r') as f:
350 for line in f:
351 line = line.strip()
352 if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
353 clean = re.sub('<[^>]*>', '', line)
354 clean = clean.replace('&amp;', '&').replace('&gt;', '>').replace('&lt;', '<')
355 if clean and clean not in seen:
356 print(clean)
357 seen.add(clean)
358" > "${VIDEO_TITLE}.txt"
359 echo "✓ Saved to: ${VIDEO_TITLE}.txt"
360 
361 # Clean up temporary VTT file
362 rm "$VTT_FILE"
363 echo "✓ Cleaned up temporary VTT file"
364else
365 echo "⚠ No VTT file found to convert"
366fi
367 
368echo "✓ Complete!"
369```
370 
371**Note**: This complete workflow handles all scenarios with proper error checking and user prompts at each decision point.
372 
373## Error Handling
374 
375### Common Issues and Solutions:
376 
377**1. yt-dlp not installed**
378- Attempt automatic installation based on system (Homebrew/apt/pip)
379- If installation fails, provide manual installation link
380- Verify installation before proceeding
381 
382**2. No subtitles available**
383- List available subtitles first to confirm
384- Try both `--write-sub` and `--write-auto-sub`
385- If both fail, offer Whisper transcription option
386- Show file size and ask for user confirmation before downloading audio
387 
388**3. Invalid or private video**
389- Check if URL is correct format: `https://www.youtube.com/watch?v=VIDEO_ID`
390- Some videos may be private, age-restricted, or geo-blocked
391- Inform user of the specific error from yt-dlp
392 
393**4. Whisper installation fails**
394- May require system dependencies (ffmpeg, rust)
395- Provide fallback: "Install manually with: `pip3 install openai-whisper`"
396- Check available disk space (models require 1-10GB depending on size)
397 
398**5. Download interrupted or failed**
399- Check internet connection
400- Verify sufficient disk space
401- Try again with `--no-check-certificate` if SSL issues occur
402 
403**6. Multiple subtitle languages**
404- By default, yt-dlp downloads all available languages
405- Can specify with `--sub-langs en` for English only
406- List available with `--list-subs` first
407 
408### Best Practices:
409 
410- ✅ Always check what's available before attempting download (`--list-subs`)
411- ✅ Verify success at each step before proceeding to next
412- ✅ Ask user before large downloads (audio files, Whisper models)
413- ✅ Clean up temporary files after processing
414- ✅ Provide clear feedback about what's happening at each stage
415- ✅ Handle errors gracefully with helpful messages
416 

Discussion

Alternatives

Also in Captions & subsSee all 316 in Content creator →