Intelligent AI-powered ad blocker that removes ads, sponsored content, and promotional elements from all websites
Size
9.9 KB
Version
1.0.1
Created
Oct 16, 2025
Updated
3 months ago
1// ==UserScript==
2// @name AI Ad Blocker - Remove Ads from Any Website
3// @description Intelligent AI-powered ad blocker that removes ads, sponsored content, and promotional elements from all websites
4// @version 1.0.1
5// @match *://*/*
6// @icon https://www.youtube.com/s/desktop/3d178601/img/favicon_32x32.png
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('AI Ad Blocker initialized');
12
13 // Track processed elements to avoid reprocessing
14 const processedElements = new WeakSet();
15
16 // Common ad-related selectors for quick removal
17 const commonAdSelectors = [
18 '[class*="ad-"]',
19 '[id*="ad-"]',
20 '[class*="advertisement"]',
21 '[id*="advertisement"]',
22 '[class*="sponsor"]',
23 '[id*="sponsor"]',
24 'iframe[src*="doubleclick"]',
25 'iframe[src*="googlesyndication"]',
26 'iframe[src*="advertising"]',
27 '[data-ad]',
28 '[data-advertisement]'
29 ];
30
31 // Debounce function to limit AI calls
32 function debounce(func, wait) {
33 let timeout;
34 return function executedFunction(...args) {
35 const later = () => {
36 clearTimeout(timeout);
37 func(...args);
38 };
39 clearTimeout(timeout);
40 timeout = setTimeout(later, wait);
41 };
42 }
43
44 // Quick removal of obvious ads using selectors
45 function removeObviousAds() {
46 let removedCount = 0;
47 commonAdSelectors.forEach(selector => {
48 try {
49 const elements = document.querySelectorAll(selector);
50 elements.forEach(el => {
51 if (!processedElements.has(el)) {
52 el.style.display = 'none';
53 processedElements.add(el);
54 removedCount++;
55 }
56 });
57 } catch (e) {
58 // Invalid selector, skip
59 }
60 });
61 if (removedCount > 0) {
62 console.log(`AI Ad Blocker: Removed ${removedCount} obvious ads`);
63 }
64 }
65
66 // AI-powered ad detection for subtle ads
67 async function analyzeElementWithAI(element) {
68 if (processedElements.has(element)) {
69 return;
70 }
71
72 // Skip if element is too small or hidden
73 const rect = element.getBoundingClientRect();
74 if (rect.width < 50 || rect.height < 50) {
75 return;
76 }
77
78 // Get element context
79 const elementText = element.textContent?.trim().substring(0, 500) || '';
80 const elementHTML = element.outerHTML.substring(0, 1000);
81 const classList = Array.from(element.classList).join(' ');
82 const elementId = element.id || '';
83
84 // Skip if no meaningful content
85 if (!elementText && !classList && !elementId) {
86 return;
87 }
88
89 try {
90 const analysis = await RM.aiCall(
91 `Analyze if this web element is an advertisement, sponsored content, or promotional material.
92
93Element details:
94- Classes: ${classList}
95- ID: ${elementId}
96- Text content: ${elementText}
97- HTML snippet: ${elementHTML}
98
99Consider:
1001. Promotional language (e.g., "sponsored", "ad", "promoted")
1012. Marketing calls-to-action (e.g., "buy now", "shop", "limited offer")
1023. Third-party advertising indicators
1034. Tracking or analytics attributes
1045. Typical ad placement patterns
105
106Respond with your analysis.`,
107 {
108 type: "json_schema",
109 json_schema: {
110 name: "ad_detection",
111 schema: {
112 type: "object",
113 properties: {
114 isAd: {
115 type: "boolean",
116 description: "Whether this element is an advertisement"
117 },
118 confidence: {
119 type: "number",
120 description: "Confidence level from 0 to 1",
121 minimum: 0,
122 maximum: 1
123 },
124 reason: {
125 type: "string",
126 description: "Brief explanation of the decision"
127 },
128 adType: {
129 type: "string",
130 enum: ["banner", "sponsored_content", "popup", "video_ad", "native_ad", "not_ad"],
131 description: "Type of advertisement if detected"
132 }
133 },
134 required: ["isAd", "confidence", "reason", "adType"]
135 }
136 }
137 }
138 );
139
140 processedElements.add(element);
141
142 // Remove if AI confirms it's an ad with high confidence
143 if (analysis.isAd && analysis.confidence > 0.7) {
144 element.style.display = 'none';
145 console.log(`AI Ad Blocker: Removed ${analysis.adType} (confidence: ${analysis.confidence}) - ${analysis.reason}`);
146
147 // Store blocked ad info
148 const blockedAds = await GM.getValue('blockedAdsCount', 0);
149 await GM.setValue('blockedAdsCount', blockedAds + 1);
150 }
151
152 } catch (error) {
153 console.error('AI Ad Blocker: Error analyzing element:', error);
154 processedElements.add(element);
155 }
156 }
157
158 // Batch process suspicious elements
159 async function scanForAds() {
160 // First, remove obvious ads quickly
161 removeObviousAds();
162
163 // Then analyze suspicious elements with AI
164 const suspiciousElements = document.querySelectorAll(
165 'div, article, section, aside, iframe'
166 );
167
168 const elementsToAnalyze = Array.from(suspiciousElements).filter(el => {
169 if (processedElements.has(el)) return false;
170
171 // Check if element might be an ad based on attributes
172 const text = el.textContent?.toLowerCase() || '';
173 const classes = el.className?.toLowerCase() || '';
174 const id = el.id?.toLowerCase() || '';
175
176 const suspiciousKeywords = [
177 'sponsor', 'promoted', 'advertisement', 'promo',
178 'banner', 'commercial', 'marketing', 'affiliate'
179 ];
180
181 return suspiciousKeywords.some(keyword =>
182 text.includes(keyword) ||
183 classes.includes(keyword) ||
184 id.includes(keyword)
185 );
186 });
187
188 // Analyze up to 5 elements at a time to avoid overwhelming the AI
189 const batch = elementsToAnalyze.slice(0, 5);
190
191 for (const element of batch) {
192 await analyzeElementWithAI(element);
193 }
194 }
195
196 // Debounced scan function
197 const debouncedScan = debounce(scanForAds, 2000);
198
199 // Initial scan
200 async function init() {
201 console.log('AI Ad Blocker: Starting initial scan...');
202
203 // Wait for page to load
204 if (document.readyState === 'loading') {
205 document.addEventListener('DOMContentLoaded', () => {
206 setTimeout(scanForAds, 1000);
207 });
208 } else {
209 setTimeout(scanForAds, 1000);
210 }
211
212 // Monitor DOM changes for dynamically loaded ads
213 const observer = new MutationObserver(debounce((mutations) => {
214 // Check if new elements were added
215 const hasNewElements = mutations.some(mutation =>
216 mutation.addedNodes.length > 0
217 );
218
219 if (hasNewElements) {
220 removeObviousAds(); // Quick check first
221 debouncedScan(); // Then AI analysis
222 }
223 }, 1000));
224
225 observer.observe(document.body, {
226 childList: true,
227 subtree: true
228 });
229
230 // Show stats badge
231 await showStatsBadge();
232 }
233
234 // Display blocked ads counter
235 async function showStatsBadge() {
236 const badge = document.createElement('div');
237 badge.id = 'ai-adblocker-badge';
238 badge.style.cssText = `
239 position: fixed;
240 bottom: 20px;
241 right: 20px;
242 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
243 color: white;
244 padding: 12px 20px;
245 border-radius: 25px;
246 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
247 font-size: 14px;
248 font-weight: 600;
249 box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
250 z-index: 999999;
251 cursor: pointer;
252 transition: transform 0.2s;
253 `;
254
255 const blockedCount = await GM.getValue('blockedAdsCount', 0);
256 badge.textContent = `🛡️ ${blockedCount} ads blocked`;
257
258 badge.addEventListener('mouseenter', () => {
259 badge.style.transform = 'scale(1.05)';
260 });
261
262 badge.addEventListener('mouseleave', () => {
263 badge.style.transform = 'scale(1)';
264 });
265
266 badge.addEventListener('click', async () => {
267 const count = await GM.getValue('blockedAdsCount', 0);
268 alert(`AI Ad Blocker Statistics:\n\n✓ Total ads blocked: ${count}\n✓ Using AI-powered detection\n✓ Protecting your browsing experience`);
269 });
270
271 document.body.appendChild(badge);
272
273 // Update badge periodically
274 setInterval(async () => {
275 const count = await GM.getValue('blockedAdsCount', 0);
276 badge.textContent = `🛡️ ${count} ads blocked`;
277 }, 5000);
278 }
279
280 // Start the ad blocker
281 if (document.body) {
282 init();
283 } else {
284 document.addEventListener('DOMContentLoaded', init);
285 }
286
287})();