ExamVeda Ad Blocker & PDF Downloader

Blocks ads, removes floating elements and login prompts, and adds PDF download functionality to ExamVeda pages

Size

11.5 KB

Version

1.0.1

Created

Dec 29, 2025

Updated

2 months ago

1// ==UserScript==
2// @name		ExamVeda Ad Blocker & PDF Downloader
3// @description		Blocks ads, removes floating elements and login prompts, and adds PDF download functionality to ExamVeda pages
4// @version		1.0.1
5// @match		https://*.examveda.com/*
6// @icon		https://www.examveda.com/favicon.ico
7// @require		https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js
8// ==/UserScript==
9(function() {
10    'use strict';
11
12    console.log('ExamVeda Ad Blocker & PDF Downloader initialized');
13
14    // Utility function to debounce
15    function debounce(func, wait) {
16        let timeout;
17        return function executedFunction(...args) {
18            const later = () => {
19                clearTimeout(timeout);
20                func(...args);
21            };
22            clearTimeout(timeout);
23            timeout = setTimeout(later, wait);
24        };
25    }
26
27    // Function to remove ads and unwanted elements
28    function removeAdsAndFloatingElements() {
29        console.log('Removing ads and floating elements...');
30
31        // Remove Google AdSense ads
32        const adsSelectors = [
33            '.adsbygoogle',
34            'ins.adsbygoogle',
35            '.google-auto-placed',
36            '[data-ad-slot]',
37            '[data-ad-format]',
38            'div[id*="aswift"]',
39            'iframe[id*="aswift"]',
40            '.goog-rtopics',
41            '.google-anno-skip',
42            '.google-anno-sc'
43        ];
44
45        adsSelectors.forEach(selector => {
46            const elements = document.querySelectorAll(selector);
47            elements.forEach(el => {
48                console.log('Removing ad element:', selector);
49                el.remove();
50            });
51        });
52
53        // Remove floating elements
54        const floatingSelectors = [
55            'div[id*="clever"]',
56            'div[id*="top-scroll"]',
57            '.whatsapp-wrapper',
58            '.whatsapp-float',
59            '.fire-ring',
60            '[class*="floating"]',
61            '[class*="sticky-ad"]',
62            '[id*="sticky"]',
63            '.popup-overlay',
64            '.modal-overlay'
65        ];
66
67        floatingSelectors.forEach(selector => {
68            const elements = document.querySelectorAll(selector);
69            elements.forEach(el => {
70                console.log('Removing floating element:', selector);
71                el.remove();
72            });
73        });
74
75        // Remove login modals and popups
76        const loginSelectors = [
77            '.login-modal',
78            '.login-popup',
79            '#login-modal',
80            '[class*="login-overlay"]',
81            '[id*="login-popup"]',
82            '.signin-modal',
83            '.auth-modal'
84        ];
85
86        loginSelectors.forEach(selector => {
87            const elements = document.querySelectorAll(selector);
88            elements.forEach(el => {
89                console.log('Removing login element:', selector);
90                el.remove();
91            });
92        });
93
94        // Remove any overlay backgrounds
95        const overlays = document.querySelectorAll('[class*="overlay"], [id*="overlay"]');
96        overlays.forEach(overlay => {
97            if (overlay.style.position === 'fixed' || overlay.style.position === 'absolute') {
98                console.log('Removing overlay');
99                overlay.remove();
100            }
101        });
102
103        // Restore body scroll if it was disabled
104        document.body.style.overflow = 'auto';
105        document.documentElement.style.overflow = 'auto';
106    }
107
108    // Function to add CSS to hide ads and floating elements
109    function addBlockingStyles() {
110        const style = document.createElement('style');
111        style.textContent = `
112            /* Hide ads */
113            .adsbygoogle,
114            ins.adsbygoogle,
115            .google-auto-placed,
116            [data-ad-slot],
117            [data-ad-format],
118            div[id*="aswift"],
119            iframe[id*="aswift"],
120            .goog-rtopics,
121            .google-anno-skip,
122            .google-anno-sc {
123                display: none !important;
124                visibility: hidden !important;
125                opacity: 0 !important;
126                height: 0 !important;
127                width: 0 !important;
128            }
129
130            /* Hide floating elements */
131            div[id*="clever"],
132            div[id*="top-scroll"],
133            .whatsapp-wrapper,
134            .whatsapp-float,
135            .fire-ring,
136            [class*="floating"],
137            [class*="sticky-ad"],
138            [id*="sticky"] {
139                display: none !important;
140            }
141
142            /* Hide login modals */
143            .login-modal,
144            .login-popup,
145            #login-modal,
146            [class*="login-overlay"],
147            [id*="login-popup"],
148            .signin-modal,
149            .auth-modal {
150                display: none !important;
151            }
152
153            /* PDF Download Button Styles */
154            #examveda-pdf-download-btn {
155                position: fixed;
156                top: 100px;
157                right: 20px;
158                z-index: 9999;
159                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
160                color: white;
161                border: none;
162                padding: 12px 24px;
163                border-radius: 8px;
164                cursor: pointer;
165                font-size: 16px;
166                font-weight: bold;
167                box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
168                transition: all 0.3s ease;
169                display: flex;
170                align-items: center;
171                gap: 8px;
172            }
173
174            #examveda-pdf-download-btn:hover {
175                transform: translateY(-2px);
176                box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
177                background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
178            }
179
180            #examveda-pdf-download-btn:active {
181                transform: translateY(0);
182            }
183
184            #examveda-pdf-download-btn.downloading {
185                background: #6c757d;
186                cursor: wait;
187            }
188
189            /* Ensure body is scrollable */
190            body, html {
191                overflow: auto !important;
192            }
193        `;
194        document.head.appendChild(style);
195        console.log('Blocking styles added');
196    }
197
198    // Function to create PDF download button
199    function createPDFDownloadButton() {
200        // Check if button already exists
201        if (document.getElementById('examveda-pdf-download-btn')) {
202            console.log('PDF download button already exists');
203            return;
204        }
205
206        const button = document.createElement('button');
207        button.id = 'examveda-pdf-download-btn';
208        button.innerHTML = '📄 Download PDF';
209        button.title = 'Download this page as PDF';
210
211        button.addEventListener('click', async function() {
212            if (button.classList.contains('downloading')) {
213                return;
214            }
215
216            button.classList.add('downloading');
217            button.innerHTML = '⏳ Generating PDF...';
218
219            try {
220                await generatePDF();
221                button.innerHTML = '✅ Downloaded!';
222                setTimeout(() => {
223                    button.innerHTML = '📄 Download PDF';
224                    button.classList.remove('downloading');
225                }, 3000);
226            } catch (error) {
227                console.error('PDF generation failed:', error);
228                button.innerHTML = '❌ Failed';
229                setTimeout(() => {
230                    button.innerHTML = '📄 Download PDF';
231                    button.classList.remove('downloading');
232                }, 3000);
233            }
234        });
235
236        document.body.appendChild(button);
237        console.log('PDF download button created');
238    }
239
240    // Function to generate PDF
241    async function generatePDF() {
242        console.log('Starting PDF generation...');
243
244        // Find the main content area
245        const contentSelectors = [
246            '.page-content',
247            'article',
248            'main',
249            '.content',
250            '#content',
251            '.post-content',
252            '.entry-content'
253        ];
254
255        let contentElement = null;
256        for (const selector of contentSelectors) {
257            contentElement = document.querySelector(selector);
258            if (contentElement) {
259                console.log('Found content element:', selector);
260                break;
261            }
262        }
263
264        // If no specific content found, use body but clone it to remove unwanted elements
265        if (!contentElement) {
266            console.log('No specific content element found, using body');
267            contentElement = document.body;
268        }
269
270        // Clone the content to avoid modifying the original page
271        const clonedContent = contentElement.cloneNode(true);
272
273        // Remove unwanted elements from the clone
274        const unwantedSelectors = [
275            '#examveda-pdf-download-btn',
276            '.adsbygoogle',
277            'ins.adsbygoogle',
278            '.google-auto-placed',
279            '[data-ad-slot]',
280            'script',
281            'iframe',
282            '.whatsapp-wrapper',
283            'div[id*="clever"]',
284            'nav',
285            'header',
286            'footer',
287            '.sidebar',
288            '.comments',
289            '.social-share'
290        ];
291
292        unwantedSelectors.forEach(selector => {
293            const elements = clonedContent.querySelectorAll(selector);
294            elements.forEach(el => el.remove());
295        });
296
297        // Get page title for filename
298        const pageTitle = document.title.replace(/[^a-z0-9]/gi, '_').substring(0, 50) || 'examveda_page';
299
300        // Configure html2pdf options
301        const opt = {
302            margin: [10, 10, 10, 10],
303            filename: `${pageTitle}.pdf`,
304            image: { type: 'jpeg', quality: 0.98 },
305            html2canvas: { 
306                scale: 2,
307                useCORS: true,
308                logging: false,
309                letterRendering: true
310            },
311            jsPDF: { 
312                unit: 'mm', 
313                format: 'a4', 
314                orientation: 'portrait' 
315            },
316            pagebreak: { mode: ['avoid-all', 'css', 'legacy'] }
317        };
318
319        // Generate PDF
320        console.log('Generating PDF with html2pdf...');
321        await html2pdf().set(opt).from(clonedContent).save();
322        console.log('PDF generated successfully');
323    }
324
325    // Initialize the extension
326    function init() {
327        console.log('Initializing ExamVeda extension...');
328
329        // Add blocking styles immediately
330        addBlockingStyles();
331
332        // Remove ads and floating elements
333        removeAdsAndFloatingElements();
334
335        // Create PDF download button when DOM is ready
336        if (document.readyState === 'loading') {
337            document.addEventListener('DOMContentLoaded', createPDFDownloadButton);
338        } else {
339            createPDFDownloadButton();
340        }
341
342        // Use MutationObserver to catch dynamically loaded ads
343        const debouncedRemoval = debounce(removeAdsAndFloatingElements, 500);
344        
345        const observer = new MutationObserver(debouncedRemoval);
346        
347        observer.observe(document.body, {
348            childList: true,
349            subtree: true
350        });
351
352        console.log('MutationObserver started to watch for dynamic ads');
353
354        // Also check periodically for any ads that might slip through
355        setInterval(removeAdsAndFloatingElements, 3000);
356    }
357
358    // Start the extension
359    if (document.readyState === 'loading') {
360        document.addEventListener('DOMContentLoaded', init);
361    } else {
362        init();
363    }
364
365})();