AI-Powered Reddit Summarizer

Summarize Reddit posts and comments using AI

Size

15.9 KB

Version

1.0.1

Created

Oct 22, 2025

Updated

about 13 hours ago

1// ==UserScript==
2// @name		AI-Powered Reddit Summarizer
3// @description		Summarize Reddit posts and comments using AI
4// @version		1.0.1
5// @match		https://*.reddit.com/*
6// @icon		https://www.redditstatic.com/shreddit/assets/favicon/64x64.png
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('AI-Powered Reddit Summarizer initialized');
12
13    // Add custom styles for the summarizer
14    TM_addStyle(`
15        .reddit-summarizer-btn {
16            display: inline-flex;
17            align-items: center;
18            padding: 6px 12px;
19            margin-left: 8px;
20            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
21            color: white;
22            border: none;
23            border-radius: 20px;
24            font-size: 12px;
25            font-weight: 600;
26            cursor: pointer;
27            transition: all 0.3s ease;
28            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
29        }
30
31        .reddit-summarizer-btn:hover {
32            transform: translateY(-1px);
33            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
34            background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
35        }
36
37        .reddit-summarizer-btn:disabled {
38            opacity: 0.6;
39            cursor: not-allowed;
40            transform: none;
41        }
42
43        .reddit-summarizer-icon {
44            margin-right: 6px;
45            font-size: 14px;
46        }
47
48        .reddit-summary-modal {
49            position: fixed;
50            top: 0;
51            left: 0;
52            right: 0;
53            bottom: 0;
54            background: rgba(0, 0, 0, 0.7);
55            display: flex;
56            align-items: center;
57            justify-content: center;
58            z-index: 10000;
59            padding: 20px;
60            animation: fadeIn 0.3s ease;
61        }
62
63        @keyframes fadeIn {
64            from { opacity: 0; }
65            to { opacity: 1; }
66        }
67
68        .reddit-summary-content {
69            background: white;
70            border-radius: 12px;
71            max-width: 800px;
72            max-height: 90vh;
73            overflow-y: auto;
74            padding: 30px;
75            box-shadow: 0 10px 40px rgba(0,0,0,0.3);
76            animation: slideUp 0.3s ease;
77            position: relative;
78        }
79
80        @keyframes slideUp {
81            from { transform: translateY(20px); opacity: 0; }
82            to { transform: translateY(0); opacity: 1; }
83        }
84
85        .reddit-summary-header {
86            display: flex;
87            justify-content: space-between;
88            align-items: center;
89            margin-bottom: 20px;
90            padding-bottom: 15px;
91            border-bottom: 2px solid #f0f0f0;
92        }
93
94        .reddit-summary-title {
95            font-size: 24px;
96            font-weight: bold;
97            color: #1a1a1b;
98            margin: 0;
99        }
100
101        .reddit-summary-close {
102            background: none;
103            border: none;
104            font-size: 28px;
105            cursor: pointer;
106            color: #878a8c;
107            padding: 0;
108            width: 32px;
109            height: 32px;
110            display: flex;
111            align-items: center;
112            justify-content: center;
113            border-radius: 50%;
114            transition: all 0.2s ease;
115        }
116
117        .reddit-summary-close:hover {
118            background: #f6f7f8;
119            color: #1a1a1b;
120        }
121
122        .reddit-summary-body {
123            color: #1a1a1b;
124            line-height: 1.6;
125            font-size: 15px;
126        }
127
128        .reddit-summary-section {
129            margin-bottom: 20px;
130        }
131
132        .reddit-summary-section-title {
133            font-size: 18px;
134            font-weight: 600;
135            color: #1a1a1b;
136            margin-bottom: 10px;
137            display: flex;
138            align-items: center;
139        }
140
141        .reddit-summary-section-icon {
142            margin-right: 8px;
143        }
144
145        .reddit-summary-text {
146            color: #1c1c1c;
147            margin-bottom: 10px;
148        }
149
150        .reddit-summary-list {
151            list-style: none;
152            padding: 0;
153            margin: 0;
154        }
155
156        .reddit-summary-list li {
157            padding: 8px 0;
158            padding-left: 24px;
159            position: relative;
160            color: #1c1c1c;
161        }
162
163        .reddit-summary-list li:before {
164            content: "•";
165            position: absolute;
166            left: 8px;
167            color: #667eea;
168            font-weight: bold;
169        }
170
171        .reddit-summary-loading {
172            text-align: center;
173            padding: 40px;
174        }
175
176        .reddit-summary-spinner {
177            border: 3px solid #f3f3f3;
178            border-top: 3px solid #667eea;
179            border-radius: 50%;
180            width: 40px;
181            height: 40px;
182            animation: spin 1s linear infinite;
183            margin: 0 auto 20px;
184        }
185
186        @keyframes spin {
187            0% { transform: rotate(0deg); }
188            100% { transform: rotate(360deg); }
189        }
190
191        .reddit-summary-loading-text {
192            color: #1a1a1b;
193            font-size: 16px;
194        }
195    `);
196
197    // Function to extract post content
198    function extractPostContent() {
199        console.log('Extracting post content...');
200        
201        const postTitle = document.querySelector('h1[id^="post-title-"]')?.textContent?.trim() || '';
202        console.log('Post title:', postTitle);
203        
204        // Try to find post body text
205        let postBody = '';
206        const postTextBody = document.querySelector('shreddit-post-text-body div[slot="text-body"]');
207        if (postTextBody) {
208            postBody = postTextBody.textContent?.trim() || '';
209        }
210        console.log('Post body length:', postBody.length);
211        
212        return { postTitle, postBody };
213    }
214
215    // Function to extract comments
216    function extractComments(maxComments = 10) {
217        console.log('Extracting comments...');
218        
219        const comments = [];
220        const commentElements = document.querySelectorAll('shreddit-comment[depth="0"]');
221        
222        console.log('Found comment elements:', commentElements.length);
223        
224        for (let i = 0; i < Math.min(commentElements.length, maxComments); i++) {
225            const commentEl = commentElements[i];
226            const commentText = commentEl.querySelector('div[slot="comment"]')?.textContent?.trim();
227            
228            if (commentText && commentText.length > 20) {
229                comments.push(commentText);
230            }
231        }
232        
233        console.log('Extracted comments:', comments.length);
234        return comments;
235    }
236
237    // Function to generate summary using AI
238    async function generateSummary(postTitle, postBody, comments) {
239        console.log('Generating AI summary...');
240        
241        const prompt = `Please provide a comprehensive summary of this Reddit post and its discussion:
242
243POST TITLE: ${postTitle}
244
245POST CONTENT: ${postBody || 'No additional content'}
246
247TOP COMMENTS:
248${comments.map((c, i) => `${i + 1}. ${c}`).join('\n\n')}
249
250Please analyze and summarize this in a structured format.`;
251
252        try {
253            const summary = await RM.aiCall(prompt, {
254                type: "json_schema",
255                json_schema: {
256                    name: "reddit_summary",
257                    schema: {
258                        type: "object",
259                        properties: {
260                            mainTopic: {
261                                type: "string",
262                                description: "A brief one-sentence summary of what the post is about"
263                            },
264                            keyPoints: {
265                                type: "array",
266                                items: { type: "string" },
267                                description: "3-5 key points or main ideas from the post and discussion"
268                            },
269                            topPerspectives: {
270                                type: "array",
271                                items: { type: "string" },
272                                description: "2-4 different perspectives or opinions from the comments"
273                            },
274                            consensus: {
275                                type: "string",
276                                description: "What seems to be the general consensus or common theme in the discussion"
277                            }
278                        },
279                        required: ["mainTopic", "keyPoints", "topPerspectives", "consensus"]
280                    }
281                }
282            });
283            
284            console.log('AI summary generated successfully');
285            return summary;
286        } catch (error) {
287            console.error('Error generating summary:', error);
288            throw error;
289        }
290    }
291
292    // Function to display summary modal
293    function displaySummary(summary) {
294        console.log('Displaying summary modal');
295        
296        const modal = document.createElement('div');
297        modal.className = 'reddit-summary-modal';
298        
299        modal.innerHTML = `
300            <div class="reddit-summary-content">
301                <div class="reddit-summary-header">
302                    <h2 class="reddit-summary-title">📝 AI Summary</h2>
303                    <button class="reddit-summary-close" aria-label="Close">×</button>
304                </div>
305                <div class="reddit-summary-body">
306                    <div class="reddit-summary-section">
307                        <h3 class="reddit-summary-section-title">
308                            <span class="reddit-summary-section-icon">🎯</span>
309                            Main Topic
310                        </h3>
311                        <p class="reddit-summary-text">${summary.mainTopic}</p>
312                    </div>
313                    
314                    <div class="reddit-summary-section">
315                        <h3 class="reddit-summary-section-title">
316                            <span class="reddit-summary-section-icon">💡</span>
317                            Key Points
318                        </h3>
319                        <ul class="reddit-summary-list">
320                            ${summary.keyPoints.map(point => `<li>${point}</li>`).join('')}
321                        </ul>
322                    </div>
323                    
324                    <div class="reddit-summary-section">
325                        <h3 class="reddit-summary-section-title">
326                            <span class="reddit-summary-section-icon">💬</span>
327                            Top Perspectives
328                        </h3>
329                        <ul class="reddit-summary-list">
330                            ${summary.topPerspectives.map(perspective => `<li>${perspective}</li>`).join('')}
331                        </ul>
332                    </div>
333                    
334                    <div class="reddit-summary-section">
335                        <h3 class="reddit-summary-section-title">
336                            <span class="reddit-summary-section-icon">🤝</span>
337                            General Consensus
338                        </h3>
339                        <p class="reddit-summary-text">${summary.consensus}</p>
340                    </div>
341                </div>
342            </div>
343        `;
344        
345        document.body.appendChild(modal);
346        
347        // Close modal handlers
348        const closeBtn = modal.querySelector('.reddit-summary-close');
349        closeBtn.addEventListener('click', () => modal.remove());
350        
351        modal.addEventListener('click', (e) => {
352            if (e.target === modal) {
353                modal.remove();
354            }
355        });
356        
357        // Close on Escape key
358        const escapeHandler = (e) => {
359            if (e.key === 'Escape') {
360                modal.remove();
361                document.removeEventListener('keydown', escapeHandler);
362            }
363        };
364        document.addEventListener('keydown', escapeHandler);
365    }
366
367    // Function to show loading modal
368    function showLoadingModal() {
369        const modal = document.createElement('div');
370        modal.className = 'reddit-summary-modal';
371        modal.id = 'reddit-summary-loading';
372        
373        modal.innerHTML = `
374            <div class="reddit-summary-content">
375                <div class="reddit-summary-loading">
376                    <div class="reddit-summary-spinner"></div>
377                    <div class="reddit-summary-loading-text">🤖 AI is analyzing the post and comments...</div>
378                </div>
379            </div>
380        `;
381        
382        document.body.appendChild(modal);
383        return modal;
384    }
385
386    // Main summarize function
387    async function summarizePost(button) {
388        console.log('Summarize button clicked');
389        
390        button.disabled = true;
391        button.textContent = '⏳ Summarizing...';
392        
393        const loadingModal = showLoadingModal();
394        
395        try {
396            // Wait a bit for comments to load
397            await new Promise(resolve => setTimeout(resolve, 2000));
398            
399            const { postTitle, postBody } = extractPostContent();
400            const comments = extractComments(10);
401            
402            if (!postTitle) {
403                throw new Error('Could not extract post content');
404            }
405            
406            if (comments.length === 0) {
407                console.log('No comments found, summarizing post only');
408            }
409            
410            const summary = await generateSummary(postTitle, postBody, comments);
411            
412            loadingModal.remove();
413            displaySummary(summary);
414            
415        } catch (error) {
416            console.error('Error summarizing post:', error);
417            loadingModal.remove();
418            alert('Failed to generate summary. Please try again.');
419        } finally {
420            button.disabled = false;
421            button.innerHTML = '<span class="reddit-summarizer-icon">✨</span>Summarize';
422        }
423    }
424
425    // Function to add summarize button
426    function addSummarizeButton() {
427        console.log('Adding summarize button...');
428        
429        // Check if we're on a post page
430        if (!window.location.pathname.includes('/comments/')) {
431            console.log('Not on a post page, skipping button');
432            return;
433        }
434        
435        // Check if button already exists
436        if (document.querySelector('.reddit-summarizer-btn')) {
437            console.log('Button already exists');
438            return;
439        }
440        
441        // Find the share button
442        const shareButton = document.querySelector('faceplate-dropdown-menu.share-dropdown-menu button');
443        
444        if (shareButton) {
445            console.log('Found share button, adding summarize button');
446            
447            const summarizeBtn = document.createElement('button');
448            summarizeBtn.className = 'reddit-summarizer-btn';
449            summarizeBtn.innerHTML = '<span class="reddit-summarizer-icon">✨</span>Summarize';
450            
451            summarizeBtn.addEventListener('click', (e) => {
452                e.preventDefault();
453                e.stopPropagation();
454                summarizePost(summarizeBtn);
455            });
456            
457            shareButton.parentElement.insertAdjacentElement('afterend', summarizeBtn);
458            console.log('Summarize button added successfully');
459        } else {
460            console.log('Share button not found, will retry...');
461        }
462    }
463
464    // Initialize the extension
465    function init() {
466        console.log('Initializing Reddit Summarizer...');
467        
468        // Add button on page load
469        TM_runBody(() => {
470            setTimeout(addSummarizeButton, 2000);
471        });
472        
473        // Watch for navigation changes (Reddit is a SPA)
474        let lastUrl = location.href;
475        new MutationObserver(() => {
476            const url = location.href;
477            if (url !== lastUrl) {
478                lastUrl = url;
479                console.log('URL changed, re-initializing...');
480                setTimeout(addSummarizeButton, 2000);
481            }
482        }).observe(document.body, { subtree: true, childList: true });
483    }
484
485    // Start the extension
486    init();
487})();
AI-Powered Reddit Summarizer | Robomonkey