Social Media AI Comment Responder

Intelligent comment responses for Facebook, X.com, YouTube, and TikTok using AI (OpenAI/Claude/Gemini)

Size

16.4 KB

Version

1.0.3

Created

Mar 26, 2026

Updated

21 days ago

1// ==UserScript==
2// @name		Social Media AI Comment Responder
3// @description		Intelligent comment responses for Facebook, X.com, YouTube, and TikTok using AI (OpenAI/Claude/Gemini)
4// @version		1.0.3
5// @match		https://*.facebook.com/*
6// @match		https://*.x.com/*
7// @match		https://*.youtube.com/*
8// @match		https://*.tiktok.com/*
9// @icon		data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAC3ElEQVR4AcRWO2sUURg99+ZFFlmy67NSUlmIEjJBCx9YWKQStfZBSGwENWzEP2BrQiJoQBJS2IuoiNgoCoKQkWAaG42l5DEJiUSMyVy/c2cSMibOzq67O5fvm72P851z9s7d2dFI2I7dm8u2D85edAZnRpzB2XHJOcm1MNmXuZkRYohNSIuiBpyB74cpuuqbeQU8AlQ3AEcyL8l6Jvsyp7qJIZY1rBVMbLD4nwAhuQtd/wmBaCwW0SZY1c1ayxFdi4wEGBnbgTPgybeeHQdUH/67qT65TePk3I5qi4H2gemT0P4bAcuWyrUy4ZDTcv/FFzFAl0rrJ4LhPZWPikae3NTYzKo3D8TlmIyrIS60NvKhhh3wsmEgPCyV3Hbyb5dOqGXXrAFHfmoo48BlGhWudDRj+EIWJ1obkbzJwbSagDUAXXczeTHQebAJD85n8bInh+vHMzi0tx7ZJlUKBdY1dfDUUl1Jqi87zXh1NYc7nTtwdH8DMg0K5TfVRW392zdnhSTYCenExYFcHfKZALrw02D6hx8HL7ZmtbWCOV0Mub7uLft4+3UFt58v4cxDD9/m19aXyvqktnwd1Za0+v77ZRSeLeH1l5WkJUVwqk0MoBXptVYaaElPHy00kKI+7HNgIUUHC9yBqRQNTIkBM5GeATOhDRT/+1PxQG3doNVTUfclax0+tfWHGzsXATNWa3VqUlvOgEj7a0NyrW2EmtaAW9g3KY76S3Vw7fEiOobmcGrYw4vPv0ooN/2BJuxzwBa6vbtvSceVrHa4oZbVsTtge7z4mu8FHrtVSg+BxgZ9xIBbyE8a3z8nq9Uw4ZGbGsK/EREDnP1Y2PNOXPIdoZK3wyWn5abIptxigGt06fbu6ijnYLI+mnLghIuc0flgtK2BYAlweTD91SNiZFTmfMmkIVgzCqm1HDFVsQZYx5+LkPTUa5UzwKXQDG8Pz4kIgcm+zJlRYohlDWvJEZd/AAAA//+lQe39AAAABklEQVQDAN8M/fdDhMOKAAAAAElFTkSuQmCC
10// @require		https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
11// ==/UserScript==
12(function() {
13  'use strict';
14
15  // Configuration
16  const CONFIG = {
17    facebook: {
18      commentSelector: '[data-sigil="mfeed_pivots_message feed-story-highlight-candidate"] [data-sigil="mfeed_premessage"]',
19      replyButtonSelector: '[data-sigil="messageable_reply_button"]',
20      replyBoxSelector: '[data-sigil="mfeed_pivots_message feed-story-highlight-candidate"] textarea',
21      postButtonSelector: '[data-sigil="send"]'
22    },
23    twitter: {
24      commentSelector: '[data-testid="tweet"]',
25      replyButtonSelector: '[data-testid="reply"]',
26      replyBoxSelector: '[data-testid="tweetTextarea_0"]',
27      postButtonSelector: '[data-testid="tweetButton"]'
28    },
29    youtube: {
30      commentSelector: '#comment',
31      replyButtonSelector: '#reply-button-end',
32      replyBoxSelector: '#textarea',
33      postButtonSelector: '#submit-button'
34    },
35    tiktok: {
36      commentSelector: '[data-e2e="comment-container"]',
37      replyButtonSelector: '[data-e2e="reply-button"]',
38      replyBoxSelector: '[data-e2e="user-comment-input"]',
39      postButtonSelector: '[data-e2e="add-comment-btn"]'
40    }
41  };
42
43  // AI Providers configuration
44  const AI_PROVIDERS = {
45    openai: {
46      name: 'OpenAI (GPT)',
47      apiUrl: 'https://api.openai.com/v1/chat/completions',
48      model: 'gpt-3.5-turbo'
49    },
50    claude: {
51      name: 'Claude (Anthropic)',
52      apiUrl: 'https://api.anthropic.com/v1/messages',
53      model: 'claude-3-haiku-20240307'
54    },
55    gemini: {
56      name: 'Gemini (Google)',
57      apiUrl: 'https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent',
58      model: 'gemini-pro'
59    }
60  };
61
62  // Default reply message
63  const DEFAULT_REPLY = "Thank you for your comment! I'll get back to you soon.";
64
65  // Initialize the extension
66  function init() {
67    console.log('Social Media AI Comment Responder initialized');
68    
69    // Check which platform we're on
70    const platform = detectPlatform();
71    if (platform) {
72      console.log(`Detected platform: ${platform}`);
73      setupAutoReply(platform);
74    } else {
75      console.log('Unsupported platform');
76    }
77  }
78
79  // Detect which social media platform we're on
80  function detectPlatform() {
81    const hostname = window.location.hostname;
82    
83    if (hostname.includes('facebook.com')) {
84      return 'facebook';
85    } else if (hostname.includes('x.com') || hostname.includes('twitter.com')) {
86      return 'twitter';
87    } else if (hostname.includes('youtube.com')) {
88      return 'youtube';
89    } else if (hostname.includes('tiktok.com')) {
90      return 'tiktok';
91    }
92    
93    return null;
94  }
95
96  // Set up auto-reply functionality for the detected platform
97  function setupAutoReply(platform) {
98    // Add UI controls to manage auto-replies
99    addControlPanel(platform);
100    
101    // Start observing for new comments
102    observeComments(platform);
103  }
104
105  // Add control panel for managing auto-replies
106  function addControlPanel(platform) {
107    // Create control panel element
108    const panel = document.createElement('div');
109    panel.id = 'auto-reply-control-panel';
110    panel.style.cssText = `
111      position: fixed;
112      top: 20px;
113      right: 20px;
114      width: 320px;
115      background: white;
116      border: 1px solid #ccc;
117      border-radius: 8px;
118      padding: 15px;
119      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
120      z-index: 10000;
121      font-family: Arial, sans-serif;
122      font-size: 14px;
123    `;
124    
125    // Generate AI provider options
126    let aiProviderOptions = '';
127    for (const [key, provider] of Object.entries(AI_PROVIDERS)) {
128      aiProviderOptions += `<option value="${key}">${provider.name}</option>`;
129    }
130    
131    panel.innerHTML = `
132      <h3 style="margin-top: 0; color: #333;">AI Comment Responder</h3>
133      <div style="margin-bottom: 10px;">
134        <label for="auto-reply-toggle" style="display: flex; align-items: center; cursor: pointer;">
135          <input type="checkbox" id="auto-reply-toggle" style="margin-right: 8px;">
136          Enable AI Replies
137        </label>
138      </div>
139      <div style="margin-bottom: 10px;">
140        <label for="ai-provider" style="display: block; margin-bottom: 5px;">AI Provider:</label>
141        <select id="ai-provider" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;">
142          ${aiProviderOptions}
143        </select>
144      </div>
145      <div style="margin-bottom: 10px;">
146        <label for="api-key" style="display: block; margin-bottom: 5px;">API Key:</label>
147        <input type="password" id="api-key" style="width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px;" placeholder="Enter your API key">
148      </div>
149      <div style="margin-bottom: 10px;">
150        <label for="custom-prompt" style="display: block; margin-bottom: 5px;">Custom Prompt:</label>
151        <textarea id="custom-prompt" style="width: 100%; height: 80px; padding: 8px; border: 1px solid #ccc; border-radius: 4px;" placeholder="Enter custom prompt for AI response generation">You are responding to a social media comment. Be friendly, engaging, and authentic. Keep responses concise but personalized to the comment content.</textarea>
152      </div>
153      <div>
154        <button id="save-settings" style="background: #1877f2; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; margin-right: 5px;">Save Settings</button>
155        <button id="test-ai" style="background: #4CAF50; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer;">Test AI</button>
156      </div>
157    `;
158    
159    // Add panel to page
160    document.body.appendChild(panel);
161    
162    // Load saved settings
163    loadSettings(platform);
164    
165    // Add event listeners
166    document.getElementById('save-settings').addEventListener('click', () => {
167      saveSettings(platform);
168      alert('Settings saved!');
169    });
170    
171    document.getElementById('test-ai').addEventListener('click', async () => {
172      testAIConnection(platform);
173    });
174  }
175
176  // Load saved settings from storage
177  async function loadSettings(platform) {
178    try {
179      const enabled = await GM.getValue(`${platform}_auto_reply_enabled`, false);
180      const aiProvider = await GM.getValue(`${platform}_ai_provider`, 'openai');
181      const apiKey = await GM.getValue(`${platform}_api_key`, '');
182      const customPrompt = await GM.getValue(`${platform}_custom_prompt`, 'You are responding to a social media comment. Be friendly, engaging, and authentic. Keep responses concise but personalized to the comment content.');
183      
184      document.getElementById('auto-reply-toggle').checked = enabled;
185      document.getElementById('ai-provider').value = aiProvider;
186      document.getElementById('api-key').value = apiKey;
187      document.getElementById('custom-prompt').value = customPrompt;
188    } catch (error) {
189      console.error('Error loading settings:', error);
190    }
191  }
192
193  // Save settings to storage
194  async function saveSettings(platform) {
195    try {
196      const enabled = document.getElementById('auto-reply-toggle').checked;
197      const aiProvider = document.getElementById('ai-provider').value;
198      const apiKey = document.getElementById('api-key').value;
199      const customPrompt = document.getElementById('custom-prompt').value;
200      
201      await GM.setValue(`${platform}_auto_reply_enabled`, enabled);
202      await GM.setValue(`${platform}_ai_provider`, aiProvider);
203      await GM.setValue(`${platform}_api_key`, apiKey);
204      await GM.setValue(`${platform}_custom_prompt`, customPrompt);
205    } catch (error) {
206      console.error('Error saving settings:', error);
207    }
208  }
209
210  // Test AI connection
211  async function testAIConnection(platform) {
212    try {
213      const aiProvider = document.getElementById('ai-provider').value;
214      const apiKey = document.getElementById('api-key').value;
215      const customPrompt = document.getElementById('custom-prompt').value;
216      
217      if (!apiKey) {
218        alert('Please enter your API key');
219        return;
220      }
221      
222      const testResponse = await generateAIResponse(
223        "This is a test comment",
224        aiProvider,
225        apiKey,
226        customPrompt
227      );
228      
229      alert(`AI Connection Successful!\nSample Response: ${testResponse}`);
230    } catch (error) {
231      console.error('AI Test Error:', error);
232      alert(`AI Test Failed: ${error.message}`);
233    }
234  }
235
236  // Generate AI response based on comment content
237  async function generateAIResponse(commentText, aiProvider, apiKey, customPrompt) {
238    try {
239      const provider = AI_PROVIDERS[aiProvider];
240      if (!provider) {
241        throw new Error('Invalid AI provider selected');
242      }
243      
244      const fullPrompt = `${customPrompt}\n\nComment: "${commentText}"\n\nResponse:`;
245      
246      let response;
247      
248      switch (aiProvider) {
249        case 'openai':
250          response = await axios.post(provider.apiUrl, {
251            model: provider.model,
252            messages: [{ role: 'user', content: fullPrompt }],
253            max_tokens: 150,
254            temperature: 0.7
255          }, {
256            headers: {
257              'Authorization': `Bearer ${apiKey}`,
258              'Content-Type': 'application/json'
259            }
260          });
261          return response.data.choices[0].message.content.trim();
262          
263        case 'claude':
264          response = await axios.post(provider.apiUrl, {
265            model: provider.model,
266            messages: [{ role: 'user', content: fullPrompt }],
267            max_tokens: 150,
268            temperature: 0.7
269          }, {
270            headers: {
271              'x-api-key': apiKey,
272              'Content-Type': 'application/json',
273              'anthropic-version': '2023-06-01'
274            }
275          });
276          return response.data.content[0].text.trim();
277          
278        case 'gemini':
279          response = await axios.post(`${provider.apiUrl}?key=${apiKey}`, {
280            contents: [{
281              parts: [{
282                text: fullPrompt
283              }]
284            }]
285          }, {
286            headers: {
287              'Content-Type': 'application/json'
288            }
289          });
290          return response.data.candidates[0].content.parts[0].text.trim();
291          
292        default:
293          throw new Error('Unsupported AI provider');
294      }
295    } catch (error) {
296      console.error('AI Generation Error:', error);
297      throw new Error(`Failed to generate AI response: ${error.message}`);
298    }
299  }
300
301  // Observe comments and auto-reply when new ones appear
302  function observeComments(platform) {
303    const config = CONFIG[platform];
304    if (!config) return;
305    
306    // Create observer
307    const observer = new MutationObserver(async (mutations) => {
308      // Check if auto-reply is enabled
309      const enabled = await GM.getValue(`${platform}_auto_reply_enabled`, false);
310      if (!enabled) return;
311      
312      // Process mutations
313      for (const mutation of mutations) {
314        if (mutation.type === 'childList') {
315          mutation.addedNodes.forEach(node => {
316            if (node.nodeType === Node.ELEMENT_NODE) {
317              // Check if this is a new comment
318              if (node.matches && node.matches(config.commentSelector)) {
319                processComment(node, platform);
320              }
321              
322              // Also check child elements
323              const comments = node.querySelectorAll ? node.querySelectorAll(config.commentSelector) : [];
324              comments.forEach(comment => processComment(comment, platform));
325            }
326          });
327        }
328      }
329    });
330    
331    // Start observing
332    observer.observe(document.body, {
333      childList: true,
334      subtree: true
335    });
336  }
337
338  // Process a comment and potentially reply to it
339  async function processComment(commentElement, platform) {
340    try {
341      // Get settings
342      const enabled = await GM.getValue(`${platform}_auto_reply_enabled`, false);
343      if (!enabled) return;
344      
345      const aiProvider = await GM.getValue(`${platform}_ai_provider`, 'openai');
346      const apiKey = await GM.getValue(`${platform}_api_key`, '');
347      const customPrompt = await GM.getValue(`${platform}_custom_prompt`, 'You are responding to a social media comment. Be friendly, engaging, and authentic. Keep responses concise but personalized to the comment content.');
348      
349      if (!apiKey) {
350        console.warn('API key not set, skipping AI response generation');
351        return;
352      }
353      
354      // Extract comment text (this would need to be adapted for each platform)
355      let commentText = '';
356      if (platform === 'facebook') {
357        const commentTextElement = commentElement.querySelector('[data-sigil="mfeed_pivots_message feed-story-highlight-candidate"] [data-sigil="mfeed_premessage"]');
358        commentText = commentTextElement ? commentTextElement.textContent : '';
359      } else if (platform === 'twitter') {
360        const commentTextElement = commentElement.querySelector('[data-testid="tweetText"]');
361        commentText = commentTextElement ? commentTextElement.textContent : '';
362      } else if (platform === 'youtube') {
363        const commentTextElement = commentElement.querySelector('#comment-content');
364        commentText = commentTextElement ? commentTextElement.textContent : '';
365      } else if (platform === 'tiktok') {
366        const commentTextElement = commentElement.querySelector('[data-e2e="comment-text"]');
367        commentText = commentTextElement ? commentTextElement.textContent : '';
368      }
369      
370      if (!commentText.trim()) {
371        console.log('No comment text found, skipping');
372        return;
373      }
374      
375      // Generate AI response
376      const aiResponse = await generateAIResponse(commentText, aiProvider, apiKey, customPrompt);
377      
378      // Find reply button
379      const replyButton = commentElement.querySelector(CONFIG[platform].replyButtonSelector) || 
380                          commentElement.closest(CONFIG[platform].commentSelector)?.querySelector(CONFIG[platform].replyButtonSelector);
381      
382      if (replyButton) {
383        // Click reply button
384        replyButton.click();
385        
386        // Wait for reply box to appear
387        setTimeout(() => {
388          // Find reply box
389          const replyBox = document.querySelector(CONFIG[platform].replyBoxSelector);
390          
391          if (replyBox) {
392            // Fill reply box with AI-generated message
393            replyBox.value = aiResponse;
394            
395            // Trigger input event
396            const inputEvent = new Event('input', { bubbles: true });
397            replyBox.dispatchEvent(inputEvent);
398            
399            // Wait a bit then click post button
400            setTimeout(() => {
401              const postButton = document.querySelector(CONFIG[platform].postButtonSelector);
402              if (postButton) {
403                postButton.click();
404                console.log(`AI-replied to comment on ${platform}: ${commentText} -> ${aiResponse}`);
405              }
406            }, 1000);
407          }
408        }, 1000);
409      }
410    } catch (error) {
411      console.error(`Error processing comment on ${platform}:`, error);
412    }
413  }
414
415  // Run initialization when page loads
416  if (document.readyState === 'loading') {
417    document.addEventListener('DOMContentLoaded', init);
418  } else {
419    init();
420  }
421})();