Size
9.8 KB
Version
1.0.1
Created
Oct 20, 2025
Updated
3 days ago
1// ==UserScript==
2// @name Reddit Product Review Finder
3// @description Find all reviews for any product on Reddit
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('Reddit Product Review Finder initialized');
12
13 // Add custom styles
14 TM_addStyle(`
15 #product-review-finder {
16 position: fixed;
17 top: 80px;
18 right: 20px;
19 z-index: 10000;
20 background: white;
21 border: 2px solid #FF4500;
22 border-radius: 8px;
23 padding: 20px;
24 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
25 min-width: 320px;
26 max-width: 400px;
27 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
28 }
29
30 #product-review-finder h3 {
31 margin: 0 0 15px 0;
32 color: #FF4500;
33 font-size: 18px;
34 font-weight: 600;
35 }
36
37 #product-review-finder input {
38 width: 100%;
39 padding: 10px;
40 border: 2px solid #ddd;
41 border-radius: 4px;
42 font-size: 14px;
43 box-sizing: border-box;
44 margin-bottom: 10px;
45 }
46
47 #product-review-finder input:focus {
48 outline: none;
49 border-color: #FF4500;
50 }
51
52 #product-review-finder button {
53 width: 100%;
54 padding: 10px;
55 background: #FF4500;
56 color: white;
57 border: none;
58 border-radius: 4px;
59 font-size: 14px;
60 font-weight: 600;
61 cursor: pointer;
62 margin-bottom: 5px;
63 }
64
65 #product-review-finder button:hover {
66 background: #ff5722;
67 }
68
69 #product-review-finder button:disabled {
70 background: #ccc;
71 cursor: not-allowed;
72 }
73
74 #product-review-finder .close-btn {
75 background: #666;
76 margin-top: 10px;
77 }
78
79 #product-review-finder .close-btn:hover {
80 background: #888;
81 }
82
83 #product-review-results {
84 margin-top: 15px;
85 max-height: 400px;
86 overflow-y: auto;
87 }
88
89 .review-item {
90 background: #f8f9fa;
91 padding: 12px;
92 margin-bottom: 10px;
93 border-radius: 4px;
94 border-left: 3px solid #FF4500;
95 }
96
97 .review-item .review-title {
98 font-weight: 600;
99 color: #1a1a1b;
100 margin-bottom: 5px;
101 font-size: 14px;
102 }
103
104 .review-item .review-subreddit {
105 color: #FF4500;
106 font-size: 12px;
107 margin-bottom: 5px;
108 }
109
110 .review-item .review-score {
111 color: #7c7c7c;
112 font-size: 12px;
113 margin-bottom: 5px;
114 }
115
116 .review-item .review-link {
117 color: #0079d3;
118 text-decoration: none;
119 font-size: 12px;
120 }
121
122 .review-item .review-link:hover {
123 text-decoration: underline;
124 }
125
126 .loading-spinner {
127 text-align: center;
128 color: #FF4500;
129 font-size: 14px;
130 padding: 10px;
131 }
132
133 .no-results {
134 text-align: center;
135 color: #7c7c7c;
136 font-size: 14px;
137 padding: 10px;
138 }
139
140 #toggle-review-finder {
141 position: fixed;
142 top: 80px;
143 right: 20px;
144 z-index: 9999;
145 background: #FF4500;
146 color: white;
147 border: none;
148 border-radius: 50%;
149 width: 56px;
150 height: 56px;
151 font-size: 24px;
152 cursor: pointer;
153 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
154 display: flex;
155 align-items: center;
156 justify-content: center;
157 }
158
159 #toggle-review-finder:hover {
160 background: #ff5722;
161 transform: scale(1.05);
162 }
163 `);
164
165 function createReviewFinderUI() {
166 // Create toggle button
167 const toggleBtn = document.createElement('button');
168 toggleBtn.id = 'toggle-review-finder';
169 toggleBtn.innerHTML = '🔍';
170 toggleBtn.title = 'Find Product Reviews';
171 document.body.appendChild(toggleBtn);
172
173 // Create main panel (hidden by default)
174 const panel = document.createElement('div');
175 panel.id = 'product-review-finder';
176 panel.style.display = 'none';
177 panel.innerHTML = `
178 <h3>🔍 Find Product Reviews</h3>
179 <input type="text" id="product-name-input" placeholder="Enter product name (e.g., iPhone 15, Sony WH-1000XM5)">
180 <button id="search-reviews-btn">Search Reviews</button>
181 <div id="product-review-results"></div>
182 <button class="close-btn" id="close-panel-btn">Close</button>
183 `;
184 document.body.appendChild(panel);
185
186 // Toggle panel visibility
187 toggleBtn.addEventListener('click', () => {
188 const isVisible = panel.style.display !== 'none';
189 panel.style.display = isVisible ? 'none' : 'block';
190 toggleBtn.style.display = isVisible ? 'flex' : 'none';
191 });
192
193 // Close button
194 document.getElementById('close-panel-btn').addEventListener('click', () => {
195 panel.style.display = 'none';
196 toggleBtn.style.display = 'flex';
197 });
198
199 // Search button
200 document.getElementById('search-reviews-btn').addEventListener('click', searchProductReviews);
201
202 // Enter key support
203 document.getElementById('product-name-input').addEventListener('keypress', (e) => {
204 if (e.key === 'Enter') {
205 searchProductReviews();
206 }
207 });
208
209 console.log('Review finder UI created');
210 }
211
212 async function searchProductReviews() {
213 const productName = document.getElementById('product-name-input').value.trim();
214 const resultsDiv = document.getElementById('product-review-results');
215 const searchBtn = document.getElementById('search-reviews-btn');
216
217 if (!productName) {
218 resultsDiv.innerHTML = '<div class="no-results">Please enter a product name</div>';
219 return;
220 }
221
222 // Show loading state
223 searchBtn.disabled = true;
224 searchBtn.textContent = 'Searching...';
225 resultsDiv.innerHTML = '<div class="loading-spinner">🔄 Searching for reviews...</div>';
226
227 try {
228 console.log('Searching for reviews of:', productName);
229
230 // Search Reddit for product reviews
231 const searchQuery = `${productName} review`;
232 const searchUrl = `https://www.reddit.com/search.json?q=${encodeURIComponent(searchQuery)}&sort=relevance&limit=20`;
233
234 const response = await GM.xmlhttpRequest({
235 method: 'GET',
236 url: searchUrl,
237 headers: {
238 'User-Agent': 'Mozilla/5.0'
239 }
240 });
241
242 const data = JSON.parse(response.responseText);
243 const posts = data.data.children;
244
245 if (posts.length === 0) {
246 resultsDiv.innerHTML = '<div class="no-results">No reviews found. Try a different product name.</div>';
247 return;
248 }
249
250 // Filter and display relevant posts
251 let reviewsHTML = '';
252 let reviewCount = 0;
253
254 for (const post of posts) {
255 const postData = post.data;
256 const title = postData.title;
257 const subreddit = postData.subreddit;
258 const score = postData.score;
259 const permalink = `https://www.reddit.com${postData.permalink}`;
260 const numComments = postData.num_comments;
261
262 // Check if post is likely a review
263 const isReview = title.toLowerCase().includes('review') ||
264 title.toLowerCase().includes('thoughts') ||
265 title.toLowerCase().includes('opinion') ||
266 title.toLowerCase().includes('experience') ||
267 numComments > 5;
268
269 if (isReview) {
270 reviewCount++;
271 reviewsHTML += `
272 <div class="review-item">
273 <div class="review-title">${title}</div>
274 <div class="review-subreddit">r/${subreddit}</div>
275 <div class="review-score">⬆️ ${score} upvotes | 💬 ${numComments} comments</div>
276 <a href="${permalink}" target="_blank" class="review-link">View Review →</a>
277 </div>
278 `;
279 }
280 }
281
282 if (reviewCount === 0) {
283 resultsDiv.innerHTML = '<div class="no-results">No detailed reviews found. Try searching directly on Reddit.</div>';
284 } else {
285 resultsDiv.innerHTML = `<div style="margin-bottom: 10px; font-weight: 600; color: #1a1a1b;">Found ${reviewCount} reviews:</div>` + reviewsHTML;
286 }
287
288 console.log(`Found ${reviewCount} reviews for ${productName}`);
289
290 } catch (error) {
291 console.error('Error searching for reviews:', error);
292 resultsDiv.innerHTML = '<div class="no-results">Error searching for reviews. Please try again.</div>';
293 } finally {
294 searchBtn.disabled = false;
295 searchBtn.textContent = 'Search Reviews';
296 }
297 }
298
299 // Initialize when page is ready
300 function init() {
301 if (document.body) {
302 createReviewFinderUI();
303 } else {
304 setTimeout(init, 100);
305 }
306 }
307
308 init();
309
310})();