How to Auto Generate YouTube Comments with AI?
Need faster YouTube engagement? Try this AI comment assistant for smart replies, web automation, and comment generation.
If you spend time on YouTube for marketing, outreach, or audience engagement, writing comments manually can slow everything down. This Tampermonkey script helps automate that process in a cleaner way.
The script extracts video details like the title, expanded description, and sample comments directly from the page. It then sends the data to OpenRouter AI to generate a relevant YouTube comment automatically.
The interface is lightweight, draggable, and built for daily use. You can quickly generate, copy, regenerate, or auto-fill comments into the YouTube comment box without switching tabs.
Quick setup:
- Install Tampermonkey extension
- Create a new userscript
- Paste the script and save it
- Open Settings inside the floating panel
- Add your OpenRouter API key
- Select your preferred AI model
- Open any YouTube video and generate comments instantly
Simple browser automation without extra software.
This is useful for creators, marketers, researchers, and anyone working with web automation or repetitive engagement tasks. It also shows how browser-based data extraction and web scraping workflows can be combined with AI tools for practical automation.
Features
- Extract YouTube video title and description
- Collect sample comments from viewers
- AI-powered comment generation with OpenRouter
- Quick auto-write into the comment box
- Persistent floating UI
- Custom prompts and model selection
- Works directly inside YouTube
The script is a simple example of how browser automation and AI can work together to speed up repetitive online tasks while keeping comments contextual and readable.
// ==UserScript==
// @name YouTube AI Comment Assistant
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description Extract video title, description, comments and generate AI-powered comments using OpenRouter API
// @author Ali
// @match https://www.youtube.com/watch?v=*
// @match https://www.youtube.com/watch?*
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @connect openrouter.ai
// @license MIT
// ==/UserScript==
(function() {
'use strict';
window.trustedTypes.createPolicy('default', {createHTML: (string, sink) => string})
// ==================== CONFIGURATION ====================
const CONFIG = {
API_ENDPOINT: 'https://openrouter.ai/api/v1/chat/completions',
DEFAULT_MODEL: 'google/gemini-2.0-flash-exp:free',
DEFAULT_SYSTEM_PROMPT: `You are a helpful YouTube comment assistant. Write engaging, thoughtful, and relevant comments for YouTube videos. Keep comments under 300 characters, be respectful, and add value to the conversation. Don't use markdown or emojis in excessive amounts.`,
STORAGE_KEYS: {
API_KEY: 'yt_comment_api_key',
MODEL: 'yt_comment_model',
PROMPT: 'yt_comment_prompt'
}
};
// Available models for selection
const AVAILABLE_MODELS = [
{ value: 'google/gemini-2.0-flash-exp:free', label: 'Gemini 2.0 Flash (Free)' },
{ value: 'google/gemini-2.0-pro-exp:free', label: 'Gemini 2.0 Pro (Free)' },
{ value: 'meta-llama/llama-3.2-3b-instruct:free', label: 'Llama 3.2 3B (Free)' },
{ value: 'microsoft/phi-3-mini-128k-instruct:free', label: 'Phi-3 Mini (Free)' },
{ value: 'mistralai/mistral-7b-instruct:free', label: 'Mistral 7B (Free)' },
{ value: 'openai/gpt-3.5-turbo', label: 'GPT-3.5 Turbo (Paid)' },
{ value: 'openai/gpt-4-turbo', label: 'GPT-4 Turbo (Paid)' },
{ value: 'anthropic/claude-3-haiku', label: 'Claude 3 Haiku (Paid)' }
];
// ==================== UI CREATION ====================
function createUI() {
// Main floating panel
const panel = document.createElement('div');
panel.id = 'yt-ai-comment-panel';
panel.innerHTML = `
<div class="yt-ai-header">
<span class="yt-ai-title">🤖 AI Comment Assistant</span>
<button class="yt-ai-minimize">−</button>
</div>
<div class="yt-ai-content">
<div class="yt-ai-section">
<div class="yt-ai-status">
<span id="yt-ai-status-text">Ready</span>
<span id="yt-ai-status-icon">●</span>
</div>
</div>
<div class="yt-ai-section">
<button id="yt-ai-extract-btn" class="yt-ai-btn yt-ai-btn-primary">
📋 Extract Video Data
</button>
</div>
<div class="yt-ai-section yt-ai-data-preview" id="yt-ai-data-preview" style="display: none;">
<div class="yt-ai-preview-title">📊 Extracted Data</div>
<div id="yt-ai-title-preview" class="yt-ai-preview-item"></div>
<div id="yt-ai-desc-preview" class="yt-ai-preview-item yt-ai-desc-preview"></div>
<div id="yt-ai-comments-count" class="yt-ai-preview-item"></div>
</div>
<div class="yt-ai-section">
<button id="yt-ai-generate-btn" class="yt-ai-btn yt-ai-btn-secondary" disabled>
✨ Generate Comment
</button>
</div>
<div class="yt-ai-section">
<div id="yt-ai-generated-comment" class="yt-ai-generated-comment" style="display: none;">
<div class="yt-ai-comment-header">
<span>💬 Generated Comment</span>
<button id="yt-ai-copy-btn" class="yt-ai-icon-btn" title="Copy">📋</button>
<button id="yt-ai-write-btn" class="yt-ai-icon-btn" title="Write to Comment Box">✏️</button>
<button id="yt-ai-regenerate-btn" class="yt-ai-icon-btn" title="Regenerate">🔄</button>
</div>
<div id="yt-ai-comment-text" class="yt-ai-comment-text"></div>
</div>
</div>
<div class="yt-ai-section">
<button id="yt-ai-settings-btn" class="yt-ai-btn yt-ai-btn-outline">
⚙️ Settings
</button>
</div>
</div>
`;
// Settings Modal
const modal = document.createElement('div');
modal.id = 'yt-ai-settings-modal';
modal.className = 'yt-ai-modal';
modal.style.display = 'none';
modal.innerHTML = `
<div class="yt-ai-modal-content">
<div class="yt-ai-modal-header">
<span>⚙️ Settings</span>
<button class="yt-ai-modal-close">×</button>
</div>
<div class="yt-ai-modal-body">
<div class="yt-ai-form-group">
<label for="yt-ai-api-key">OpenRouter API Key</label>
<input type="password" id="yt-ai-api-key" placeholder="sk-or-v1-..." value="${GM_getValue(CONFIG.STORAGE_KEYS.API_KEY, '')}">
<small>Get your key from <a href="https://openrouter.ai/keys" target="_blank">openrouter.ai/keys</a></small>
</div>
<div class="yt-ai-form-group">
<label for="yt-ai-model-select">AI Model</label>
<select id="yt-ai-model-select">
${AVAILABLE_MODELS.map(m => `<option value="${m.value}" ${GM_getValue(CONFIG.STORAGE_KEYS.MODEL, CONFIG.DEFAULT_MODEL) === m.value ? 'selected' : ''}>${m.label}</option>`).join('')}
</select>
</div>
<div class="yt-ai-form-group">
<label for="yt-ai-prompt">System Prompt</label>
<textarea id="yt-ai-prompt" rows="4" placeholder="Enter custom system prompt...">${GM_getValue(CONFIG.STORAGE_KEYS.PROMPT, CONFIG.DEFAULT_SYSTEM_PROMPT)}</textarea>
</div>
<div class="yt-ai-form-group">
<button id="yt-ai-save-settings" class="yt-ai-btn yt-ai-btn-primary">Save Settings</button>
</div>
</div>
</div>
`;
document.body.appendChild(panel);
document.body.appendChild(modal);
// Add styles
addStyles();
// Bind events
bindEvents(panel, modal);
}
function addStyles() {
const style = document.createElement('style');
style.textContent = `
#yt-ai-comment-panel {
position: fixed;
bottom: 20px;
right: 20px;
width: 380px;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
z-index: 10000;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
transition: all 0.3s ease;
border: 1px solid rgba(255,255,255,0.1);
backdrop-filter: blur(10px);
}
#yt-ai-comment-panel.minimized .yt-ai-content {
display: none;
}
#yt-ai-comment-panel.minimized {
width: auto;
min-width: 200px;
}
.yt-ai-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background: rgba(0,0,0,0.3);
border-radius: 16px 16px 0 0;
cursor: move;
user-select: none;
}
.yt-ai-title {
font-weight: 600;
font-size: 14px;
color: #fff;
}
.yt-ai-minimize {
background: none;
border: none;
color: #fff;
font-size: 20px;
cursor: pointer;
padding: 0 8px;
border-radius: 4px;
transition: background 0.2s;
}
.yt-ai-minimize:hover {
background: rgba(255,255,255,0.1);
}
.yt-ai-content {
padding: 16px;
}
.yt-ai-section {
margin-bottom: 12px;
}
.yt-ai-status {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
color: #aaa;
padding: 8px;
background: rgba(0,0,0,0.2);
border-radius: 8px;
}
#yt-ai-status-icon {
font-size: 8px;
margin-right: 6px;
}
.yt-ai-status.idle #yt-ai-status-icon { color: #f39c12; }
.yt-ai-status.success #yt-ai-status-icon { color: #2ecc71; }
.yt-ai-status.error #yt-ai-status-icon { color: #e74c3c; }
.yt-ai-status.loading #yt-ai-status-icon {
color: #3498db;
animation: pulse 1s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
.yt-ai-btn {
width: 100%;
padding: 10px 16px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.yt-ai-btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.yt-ai-btn-primary:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(102,126,234,0.4);
}
.yt-ai-btn-secondary {
background: linear-gradient(135deg, #f39c12 0%, #e74c3c 100%);
color: white;
}
.yt-ai-btn-secondary:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(243,156,18,0.4);
}
.yt-ai-btn-outline {
background: transparent;
border: 1px solid rgba(255,255,255,0.2);
color: #fff;
}
.yt-ai-btn-outline:hover {
background: rgba(255,255,255,0.1);
}
.yt-ai-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.yt-ai-data-preview {
background: rgba(0,0,0,0.3);
border-radius: 8px;
padding: 10px;
font-size: 12px;
}
.yt-ai-preview-title {
font-weight: 600;
margin-bottom: 8px;
color: #ddd;
}
.yt-ai-preview-item {
margin-bottom: 6px;
color: #bbb;
word-break: break-word;
}
.yt-ai-desc-preview {
max-height: 60px;
overflow-y: auto;
}
.yt-ai-generated-comment {
background: rgba(46,204,113,0.1);
border-radius: 8px;
padding: 12px;
border-left: 3px solid #2ecc71;
}
.yt-ai-comment-header {
display: flex;
gap: 8px;
margin-bottom: 8px;
font-size: 12px;
color: #2ecc71;
}
.yt-ai-icon-btn {
background: none;
border: none;
cursor: pointer;
font-size: 14px;
padding: 2px 6px;
border-radius: 4px;
transition: background 0.2s;
}
.yt-ai-icon-btn:hover {
background: rgba(255,255,255,0.1);
}
.yt-ai-comment-text {
font-size: 13px;
line-height: 1.5;
color: #ddd;
max-height: 150px;
overflow-y: auto;
padding-right: 8px;
}
/* Modal Styles */
.yt-ai-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
backdrop-filter: blur(4px);
z-index: 10001;
display: flex;
align-items: center;
justify-content: center;
}
.yt-ai-modal-content {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
border-radius: 16px;
width: 450px;
max-width: 90%;
border: 1px solid rgba(255,255,255,0.1);
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.yt-ai-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.yt-ai-modal-close {
background: none;
border: none;
color: #fff;
font-size: 24px;
cursor: pointer;
padding: 0 8px;
}
.yt-ai-modal-body {
padding: 20px;
}
.yt-ai-form-group {
margin-bottom: 16px;
}
.yt-ai-form-group label {
display: block;
margin-bottom: 6px;
font-size: 13px;
color: #ddd;
}
.yt-ai-form-group input, .yt-ai-form-group select, .yt-ai-form-group textarea {
width: 100%;
padding: 10px;
background: rgba(0,0,0,0.3);
border: 1px solid rgba(255,255,255,0.2);
border-radius: 8px;
color: #fff;
font-size: 13px;
}
.yt-ai-form-group textarea {
resize: vertical;
}
.yt-ai-form-group small {
display: block;
margin-top: 4px;
font-size: 11px;
color: #888;
}
.yt-ai-form-group small a {
color: #667eea;
}
`;
document.head.appendChild(style);
}
// ==================== STATE MANAGEMENT ====================
let extractedData = {
title: '',
description: '',
comments: []
};
function updateStatus(message, status = 'idle') {
const statusText = document.getElementById('yt-ai-status-text');
const panel = document.getElementById('yt-ai-comment-panel');
if (statusText) {
statusText.textContent = message;
}
if (panel) {
panel.querySelector('.yt-ai-status').className = `yt-ai-status ${status}`;
}
}
async function extractVideoData() {
updateStatus('Extracting data...', 'loading');
// Extract title
const titleElement = document.querySelector('h1.title yt-formatted-string, h1.ytd-watch-metadata yt-formatted-string, #title h1 yt-formatted-string');
const title = titleElement ? titleElement.textContent.trim() : document.title.replace(' - YouTube', '');
// Extract description - click "more" button if exists
const descriptionArea = document.querySelector('#description-inline-expander, #description');
let description = '';
// Try to expand description if there's a "more" button
const moreButton = document.querySelector('#expand, #more, .ytd-text-inline-expander #expand, tp-yt-paper-button#expand');
if (moreButton && moreButton.offsetParent !== null) {
updateStatus('Expanding description...', 'loading');
moreButton.click();
await new Promise(resolve => setTimeout(resolve, 500));
}
const descElement = document.querySelector('div#expanded');
if (descElement) {
description = descElement.textContent.trim();
} else {
const metaDesc = document.querySelector('div#expanded');
if (metaDesc) description = metaDesc.getAttribute('content');
}
// Extract sample comments (first 5)
updateStatus('Extracting comments...', 'loading');
const commentElements = document.querySelectorAll('#comments ytd-comment-thread-renderer, #comments ytd-comment-view-model');
const comments = [];
for (let i = 0; i < Math.min(commentElements.length, 5); i++) {
const commentEl = commentElements[i];
let commentText = '';
// Try different selectors for comment text
const textElement = commentEl.querySelector('#content-text, yt-attributed-string, #comment-content');
if (textElement) {
commentText = textElement.textContent.trim();
}
if (commentText) {
comments.push(commentText.substring(0, 200));
}
}
extractedData = { title, description, comments };
// Update preview
const previewDiv = document.getElementById('yt-ai-data-preview');
const titlePreview = document.getElementById('yt-ai-title-preview');
const descPreview = document.getElementById('yt-ai-desc-preview');
const commentsCount = document.getElementById('yt-ai-comments-count');
const generateBtn = document.getElementById('yt-ai-generate-btn');
if (titlePreview) titlePreview.innerHTML = `<strong>Title:</strong> ${title.substring(0, 80)}${title.length > 80 ? '...' : ''}`;
if (descPreview) descPreview.innerHTML = `<strong>Description:</strong> ${description.substring(0, 120)}${description.length > 120 ? '...' : ''}`;
if (commentsCount) commentsCount.innerHTML = `<strong>Comments:</strong> ${comments.length} extracted`;
if (previewDiv) previewDiv.style.display = 'block';
if (generateBtn) generateBtn.disabled = false;
updateStatus(`Extracted: "${title.substring(0, 40)}..."`, 'success');
setTimeout(() => updateStatus('Ready', 'idle'), 2000);
return extractedData;
}
async function generateComment() {
const apiKey = GM_getValue(CONFIG.STORAGE_KEYS.API_KEY, '');
if (!apiKey) {
updateStatus('Please add API key in settings', 'error');
document.getElementById('yt-ai-settings-btn').click();
return;
}
if (!extractedData.title) {
await extractVideoData();
}
updateStatus('Generating comment...', 'loading');
const model = GM_getValue(CONFIG.STORAGE_KEYS.MODEL, CONFIG.DEFAULT_MODEL);
const systemPrompt = GM_getValue(CONFIG.STORAGE_KEYS.PROMPT, CONFIG.DEFAULT_SYSTEM_PROMPT);
// Build user prompt with video data
let userPrompt = `Write an engaging YouTube comment for this video:\n\nTitle: "${extractedData.title}"\n\nDescription: "${extractedData.description.substring(0, 500)}"`;
if (extractedData.comments.length > 0) {
userPrompt += `\n\nSample comments from viewers:\n${extractedData.comments.map((c, i) => `${i+1}. "${c}"`).join('\n')}`;
}
userPrompt += `\n\nWrite a thoughtful, relevant comment (max 280 characters). Be genuine and add value to the discussion.`;
GM_xmlhttpRequest({
method: 'POST',
url: CONFIG.API_ENDPOINT,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
'HTTP-Referer': window.location.origin,
'X-Title': 'YouTube AI Comment Assistant'
},
data: JSON.stringify({
model: model,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
max_tokens: 200,
temperature: 0.8
}),
onload: function(response) {
if (response.status === 200) {
try {
const data = JSON.parse(response.responseText);
const generatedComment = data.choices[0].message.content.trim();
displayGeneratedComment(generatedComment);
updateStatus('Comment generated!', 'success');
setTimeout(() => updateStatus('Ready', 'idle'), 2000);
} catch (e) {
updateStatus('Error parsing response', 'error');
console.error(e);
}
} else {
let errorMsg = `API Error: ${response.status}`;
try {
const error = JSON.parse(response.responseText);
errorMsg = error.error?.message || errorMsg;
} catch(e) {}
updateStatus(errorMsg.substring(0, 50), 'error');
console.error('API Error:', response.responseText);
}
},
onerror: function(error) {
updateStatus('Network error', 'error');
console.error('Request failed:', error);
}
});
}
function displayGeneratedComment(comment) {
const commentDiv = document.getElementById('yt-ai-generated-comment');
const commentText = document.getElementById('yt-ai-comment-text');
if (commentText) commentText.textContent = comment;
if (commentDiv) commentDiv.style.display = 'block';
}
function copyToClipboard() {
const commentText = document.getElementById('yt-ai-comment-text');
if (commentText && commentText.textContent) {
navigator.clipboard.writeText(commentText.textContent);
updateStatus('Copied!', 'success');
setTimeout(() => updateStatus('Ready', 'idle'), 1500);
}
}
function writeToCommentBox() {
const commentText = document.getElementById('yt-ai-comment-text');
if (!commentText || !commentText.textContent) return;
// Find comment input box
const commentInput = document.querySelector('#simplebox-placeholder, #placeholder-area, ytd-comment-simplebox-renderer #placeholder-area, #comment-simplebox-renderer');
if (commentInput) {
// Click to focus and activate
commentInput.click();
setTimeout(() => {
// Find the actual input/textarea
const textarea = document.querySelector('#contenteditable-root, [contenteditable="true"], #comment-input, textarea');
if (textarea) {
if (textarea.isContentEditable) {
textarea.focus();
document.execCommand('insertText', false, commentText.textContent);
} else if (textarea.tagName === 'TEXTAREA' || textarea.tagName === 'INPUT') {
textarea.value = commentText.textContent;
textarea.dispatchEvent(new Event('input', { bubbles: true }));
textarea.focus();
}
// Scroll to comment area
const commentSection = document.querySelector('#comments, ytd-comments');
if (commentSection) {
commentSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
updateStatus('Comment written!', 'success');
setTimeout(() => updateStatus('Ready', 'idle'), 1500);
} else {
updateStatus('Could not find comment input', 'error');
}
}, 500);
} else {
updateStatus('Please expand comments section first', 'error');
}
}
function openSettings() {
const modal = document.getElementById('yt-ai-settings-modal');
if (modal) modal.style.display = 'flex';
}
function saveSettings() {
const apiKey = document.getElementById('yt-ai-api-key').value;
const model = document.getElementById('yt-ai-model-select').value;
const prompt = document.getElementById('yt-ai-prompt').value;
GM_setValue(CONFIG.STORAGE_KEYS.API_KEY, apiKey);
GM_setValue(CONFIG.STORAGE_KEYS.MODEL, model);
GM_setValue(CONFIG.STORAGE_KEYS.PROMPT, prompt);
const modal = document.getElementById('yt-ai-settings-modal');
if (modal) modal.style.display = 'none';
updateStatus('Settings saved!', 'success');
setTimeout(() => updateStatus('Ready', 'idle'), 1500);
}
function bindEvents(panel, modal) {
// Minimize button
const minimizeBtn = panel.querySelector('.yt-ai-minimize');
minimizeBtn.addEventListener('click', () => {
panel.classList.toggle('minimized');
minimizeBtn.textContent = panel.classList.contains('minimized') ? '+' : '−';
});
// Extract button
const extractBtn = document.getElementById('yt-ai-extract-btn');
if (extractBtn) extractBtn.addEventListener('click', extractVideoData);
// Generate button
const generateBtn = document.getElementById('yt-ai-generate-btn');
if (generateBtn) generateBtn.addEventListener('click', generateComment);
// Settings button
const settingsBtn = document.getElementById('yt-ai-settings-btn');
if (settingsBtn) settingsBtn.addEventListener('click', openSettings);
// Modal close
const closeBtn = modal.querySelector('.yt-ai-modal-close');
if (closeBtn) closeBtn.addEventListener('click', () => modal.style.display = 'none');
// Save settings
const saveBtn = document.getElementById('yt-ai-save-settings');
if (saveBtn) saveBtn.addEventListener('click', saveSettings);
// Copy button
const copyBtn = document.getElementById('yt-ai-copy-btn');
if (copyBtn) copyBtn.addEventListener('click', copyToClipboard);
// Write button
const writeBtn = document.getElementById('yt-ai-write-btn');
if (writeBtn) writeBtn.addEventListener('click', writeToCommentBox);
// Regenerate button
const regenerateBtn = document.getElementById('yt-ai-regenerate-btn');
if (regenerateBtn) regenerateBtn.addEventListener('click', generateComment);
// Close modal on outside click
window.addEventListener('click', (e) => {
if (e.target === modal) modal.style.display = 'none';
});
// Make panel draggable
let isDragging = false;
let dragOffset = { x: 0, y: 0 };
const header = panel.querySelector('.yt-ai-header');
header.addEventListener('mousedown', (e) => {
if (e.target === minimizeBtn) return;
isDragging = true;
const rect = panel.getBoundingClientRect();
dragOffset.x = e.clientX - rect.left;
dragOffset.y = e.clientY - rect.top;
panel.style.position = 'fixed';
panel.style.margin = '0';
});
window.addEventListener('mousemove', (e) => {
if (!isDragging) return;
let newX = e.clientX - dragOffset.x;
let newY = e.clientY - dragOffset.y;
newX = Math.max(0, Math.min(window.innerWidth - panel.offsetWidth, newX));
newY = Math.max(0, Math.min(window.innerHeight - panel.offsetHeight, newY));
panel.style.left = newX + 'px';
panel.style.right = 'auto';
panel.style.bottom = 'auto';
panel.style.top = newY + 'px';
});
window.addEventListener('mouseup', () => {
isDragging = false;
});
}
// ==================== QUICK COMMENT BUTTON ====================
function addQuickCommentButton() {
// Wait for player controls or video actions area
const checkInterval = setInterval(() => {
const actionsArea = document.querySelector('#actions-inner, #menu-container, .ytd-watch-metadata #actions');
if (actionsArea && !document.querySelector('#yt-ai-quick-btn')) {
const quickBtn = document.createElement('button');
quickBtn.id = 'yt-ai-quick-btn';
quickBtn.className = 'yt-ai-quick-btn';
quickBtn.innerHTML = '🤖 AI Comment';
quickBtn.style.cssText = `
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 18px;
padding: 8px 16px;
color: white;
font-size: 14px;
font-weight: 500;
cursor: pointer;
margin-left: 12px;
transition: all 0.2s;
`;
quickBtn.onmouseenter = () => quickBtn.style.transform = 'scale(1.02)';
quickBtn.onmouseleave = () => quickBtn.style.transform = 'scale(1)';
quickBtn.onclick = async () => {
await extractVideoData();
generateComment();
// Show the main panel if minimized
const panel = document.getElementById('yt-ai-comment-panel');
if (panel && panel.classList.contains('minimized')) {
panel.classList.remove('minimized');
const minimizeBtn = panel.querySelector('.yt-ai-minimize');
if (minimizeBtn) minimizeBtn.textContent = '−';
}
};
actionsArea.appendChild(quickBtn);
clearInterval(checkInterval);
}
}, 2000);
}
// ==================== INITIALIZATION ====================
function init() {
createUI();
addQuickCommentButton();
// Auto-extract on page load
setTimeout(() => {
extractVideoData();
}, 3000);
}
// Start the script
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();