Skip to content

Instantly share code, notes, and snippets.

@minanagehsalalma
Created October 6, 2025 14:00
Show Gist options
  • Save minanagehsalalma/4775f0ba18758ffa2e63dfa22895e46a to your computer and use it in GitHub Desktop.
Save minanagehsalalma/4775f0ba18758ffa2e63dfa22895e46a to your computer and use it in GitHub Desktop.
// YouTube Comments Extractor - With Full Reply Support
// Run this in the browser console while on a YouTube video page
async function extractAllYouTubeComments() {
console.clear();
console.log('%c🎬 YouTube Comments Extractor (With Replies)', 'font-size: 16px; font-weight: bold; color: #00ff00');
// First, expand ALL "Show replies" buttons
console.log('📂 Expanding all reply threads...');
let expandCount = 0;
let iteration = 0;
while (iteration < 10) { // Try up to 10 times
const replyButtons = Array.from(document.querySelectorAll('ytd-button-renderer#more-replies button, #more-replies button'))
.filter(btn => btn.offsetParent !== null); // Only visible buttons
if (replyButtons.length === 0) {
console.log(`✓ No more reply buttons found (checked ${iteration + 1} times)`);
break;
}
console.log(` Found ${replyButtons.length} reply buttons, clicking...`);
for (const btn of replyButtons) {
try {
btn.click();
expandCount++;
await sleep(200);
} catch (e) {
// Button might have disappeared, continue
}
}
// Scroll a bit to trigger any lazy loading
window.scrollBy(0, 500);
await sleep(800);
iteration++;
}
console.log(`✓ Expanded ${expandCount} reply threads`);
await sleep(1000); // Wait for replies to render
// Now extract everything
console.log('⚙️ Extracting all comments and replies...');
const comments = [];
const commentThreads = document.querySelectorAll('ytd-comment-thread-renderer');
console.log(` Found ${commentThreads.length} comment threads`);
for (const thread of commentThreads) {
// Main comment
const mainComment = thread.querySelector('#comment #main');
if (mainComment) {
const author = mainComment.querySelector('#author-text span')?.textContent.trim() ||
mainComment.querySelector('#author-text')?.textContent.trim() || 'Unknown';
const text = mainComment.querySelector('#content-text')?.textContent.trim() || '';
const likes = mainComment.querySelector('#vote-count-middle')?.textContent.trim() || '0';
const time = mainComment.querySelector('.published-time-text a')?.textContent.trim() || '';
if (text) {
comments.push({
type: 'comment',
author,
text,
likes,
time
});
}
// Get all replies in this thread
const replySection = thread.querySelector('#replies');
if (replySection) {
const replies = replySection.querySelectorAll('ytd-comment-renderer #main');
for (const reply of replies) {
const replyAuthor = reply.querySelector('#author-text span')?.textContent.trim() ||
reply.querySelector('#author-text')?.textContent.trim() || 'Unknown';
const replyText = reply.querySelector('#content-text')?.textContent.trim() || '';
const replyLikes = reply.querySelector('#vote-count-middle')?.textContent.trim() || '0';
const replyTime = reply.querySelector('.published-time-text a')?.textContent.trim() || '';
if (replyText) {
comments.push({
type: 'reply',
author: replyAuthor,
text: replyText,
likes: replyLikes,
time: replyTime,
parentAuthor: author
});
}
}
}
}
}
if (comments.length === 0) {
alert('❌ No comments found! Make sure:\n1. You scrolled to the comments section\n2. Comments are enabled for this video\n3. The page is fully loaded');
return null;
}
// Count comments vs replies
const mainComments = comments.filter(c => c.type === 'comment').length;
const replies = comments.filter(c => c.type === 'reply').length;
// Format for AI summary
const formatted = comments.map((c, i) => {
if (c.type === 'comment') {
return `${c.author} (${c.likes} likes, ${c.time}):\n${c.text}`;
} else {
return ` ↳ REPLY by ${c.author} (${c.likes} likes, ${c.time}):\n ${c.text}`;
}
}).join('\n\n');
// Create downloadable file
const blob = new Blob([formatted], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'youtube_comments_' + Date.now() + '.txt';
a.id = 'download-link-yt-comments';
console.log('\n' + '='.repeat(60));
console.log('%c✅ EXTRACTION COMPLETE!', 'font-size: 18px; font-weight: bold; color: #00ff00');
console.log('='.repeat(60));
console.log(`📊 Total extracted: ${comments.length}`);
console.log(` 💬 Main comments: ${mainComments}`);
console.log(` ↳ Replies: ${replies}`);
console.log('\n' + '='.repeat(60) + '\n');
// Show preview with replies
console.log('%c📝 PREVIEW (showing comment + replies structure):', 'font-weight: bold; font-size: 14px');
const previewItems = comments.slice(0, 5);
previewItems.forEach(c => {
const prefix = c.type === 'reply' ? ' ↳ ' : '';
const shortText = c.text.substring(0, 80) + (c.text.length > 80 ? '...' : '');
console.log(`${prefix}${c.author}: ${shortText}`);
});
console.log('\n' + '='.repeat(60) + '\n');
// Store data globally
window.ytCommentsData = formatted;
window.ytCommentsRaw = comments;
// Add download button to page
a.style.cssText = 'position:fixed;top:10px;right:10px;z-index:99999;padding:15px 25px;background:#ff0000;color:white;text-decoration:none;border-radius:5px;font-weight:bold;font-size:16px;box-shadow:0 4px 8px rgba(0,0,0,0.3);cursor:pointer;';
a.textContent = `📥 Download ${mainComments} Comments + ${replies} Replies`;
document.body.appendChild(a);
// Try to copy to clipboard
try {
await navigator.clipboard.writeText(formatted);
console.log('%c✅ All comments + replies copied to clipboard!', 'color: #00ff00; font-weight: bold; font-size: 14px');
console.log('%cPaste directly into Claude or ChatGPT now!', 'color: #00ff00');
} catch (e) {
console.log('%c⚠️ Could not auto-copy. Run:', 'color: #ffaa00; font-weight: bold');
console.log(' copy(window.ytCommentsData)');
}
console.log('\n' + '='.repeat(60));
console.log('%c📥 QUICK COMMANDS:', 'font-weight: bold; font-size: 14px');
console.log('copy(window.ytCommentsData) // Copy formatted text');
console.log('console.log(window.ytCommentsData) // View all text');
console.log('console.log(window.ytCommentsRaw) // View raw data');
console.log('='.repeat(60) + '\n');
alert(`✅ SUCCESS!\n\n📊 ${mainComments} comments + ${replies} replies = ${comments.length} total\n\n✓ Copied to clipboard\n✓ Red download button added\n\nReady to paste into AI!`);
return {
raw: comments,
formatted: formatted,
count: comments.length,
mainComments: mainComments,
replies: replies
};
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Run the extraction
extractAllYouTubeComments();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment