#!/bin/bash
# Scrape YouTube comments into searchable .md and .json files.
# Usage: ytcomments <url> [output_dir]
# url - YouTube video URL
# output_dir - where to save (default: current directory)
#
# Output files are named after the video title, sorted by like count.
# Search with: rg -i "keyword" file.md
die() { printf '%s\n' "$1" >&2; exit 1; }
[ -z "$1" ] && die "Usage: ytcomments <youtube-url> [output-dir]"
command -v yt-dlp >/dev/null || die "yt-dlp not found"
command -v jq >/dev/null || die "jq not found"
url="$1"
outdir="${2:-.}"
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
printf 'Scraping comments from: %s\n' "$url"
yt-dlp --skip-download --write-comments \
-o "$tmpdir/%(title)s.%(ext)s" "$url" 2>&1 | tail -1
infofile=$(find "$tmpdir" -name '*.info.json' | head -1)
[ -f "$infofile" ] || die "Failed to download comments"
title=$(jq -r '.title' "$infofile" | tr '/' '-' | tr -d '\n')
count=$(jq '.comments | length' "$infofile")
printf 'Found %s comments for: %s\n' "$count" "$title"
# Markdown — sorted by likes, most popular first
jq -r '
.comments | sort_by(-.like_count) | .[] |
"## \(.author) (\(.like_count) likes)\n\(.text)\n\n---\n"
' "$infofile" > "$outdir/$title.md"
# JSON — clean array sorted by likes
jq '[.comments | sort_by(-.like_count) | .[] | {
author, text, likes: .like_count,
replies: (.reply_count // 0),
time: .timestamp
}]' "$infofile" > "$outdir/$title.json"
printf 'Saved:\n %s/%s.md\n %s/%s.json\n' "$outdir" "$title" "$outdir" "$title"
printf 'Search with: rg -i "keyword" "%s/%s.md"\n' "$outdir" "$title"