```bash
VIDEO_URL="https://www.youtube.com/watch?v=VIDEO_ID"
OUTPUT_DIR="transcripts"
# Create output directory if it doesn't exist
mkdir -p "$OUTPUT_DIR"
# Get video title for filename
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
OUTPUT_NAME="$OUTPUT_DIR/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: Try manual subtitles first
# ============================================
echo "Downloading subtitles for: $VIDEO_TITLE"
if yt-dlp --write-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
echo "Manual subtitles downloaded!"
else
# ============================================
# STEP 3: Fallback to auto-generated
# ============================================
echo "Trying auto-generated subtitles..."
if yt-dlp --write-auto-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
echo "Auto-generated subtitles downloaded!"
else
echo "No subtitles available for this video."
exit 1
fi
fi
# ============================================
# STEP 4: Convert to readable markdown with deduplication
# ============================================
VTT_FILE=$(ls ${OUTPUT_NAME}*.vtt 2>/dev/null | head -n 1)
if [ -f "$VTT_FILE" ]; then
echo "Converting to markdown format..."
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('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
" > "$OUTPUT_DIR/${VIDEO_TITLE}.md"
echo "Saved raw transcript to: $OUTPUT_DIR/${VIDEO_TITLE}.md"
# Clean up temporary VTT file
rm "$VTT_FILE"
else
echo "No VTT file found to convert"
exit 1
fi
# ============================================
# STEP 5: Automatically polish the transcript
# ============================================
echo "Polishing transcript (removing filler, fixing grammar, adding structure)..."
python3 << 'POLISH_EOF'
import re
with open('$OUTPUT_DIR/${VIDEO_TITLE}.md', 'r') as f:
content = f.read()
# Preserve metadata and header
lines = content.split('\n')
metadata = []
content_start = 0
for i, line in enumerate(lines):
if line.startswith('#') or line.startswith('Source:') or line.startswith('---'):
metadata.append(line)
content_start = i + 1
else:
break
transcript_text = '\n'.join(lines[content_start:]).strip()
# Remove filler words and phrases aggressively (maintain 100% meaning)
filler_patterns = [
(r'\b(um|uh|ah|er|hmm)\b', ''),
(r'\byou\s+know\b', ''),
(r',\s+(so|basically|actually)\s+', ', '),
(r'\b(basically|actually|really)\s+', ''),
(r'\b(kind|sort)\s+of\s+', ''),
(r'\bi\s+(think|mean)\s+', ''),
]
polished = transcript_text
for pattern, replacement in filler_patterns:
polished = re.sub(pattern, replacement, polished, flags=re.IGNORECASE)
# Join broken lines while preserving sentence structure
polished = re.sub(r'(?<=[a-z]),\n(?=[a-z])', ', ', polished)
polished = re.sub(r'(?<=[a-z])\n(?![\n#])', ' ', polished)
# Clean up spacing and punctuation
polished = re.sub(r' +', ' ', polished)
polished = re.sub(r'\s+([.!?,;:])', r'\1', polished)
# Reconstruct with metadata
final = '\n'.join(metadata) + '\n\n' + polished.strip()
with open('$OUTPUT_DIR/${VIDEO_TITLE}.md', 'w') as f:
f.write(final)
print("Transcript polished")
POLISH_EOF
echo "Complete!"
```
Notes:
- Output directory can be customized (default:
transcripts/) - Files are named based on the video title with special characters sanitized
- Transcripts are automatically deduplicated to remove caption overlaps
- Polishing step removes filler words/phrases while maintaining 100% meaning fidelity
- Grammar and run-on sentences are automatically fixed
- Paragraph breaks consolidate content into logical sections
- The temporary VTT file is cleaned up after conversion