Examveda Ad-Free with PDF Downloads

Removes all ads, hides login options, and adds PDF download buttons to content sections

Size

14.3 KB

Version

1.1.3

Created

Nov 7, 2025

Updated

about 1 month ago

1// ==UserScript==
2// @name		Examveda Ad-Free with PDF Downloads
3// @description		Removes all ads, hides login options, and adds PDF download buttons to content sections
4// @version		1.1.3
5// @match		https://*.examveda.com/*
6// @icon		https://www.examveda.com/favicon.ico
7// @grant		GM.xmlhttpRequest
8// @require		https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js
9// @require		https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js
10// ==/UserScript==
11(function() {
12    'use strict';
13
14    console.log('Examveda Ad-Free Extension: Starting...');
15
16    // Function to remove all advertisements
17    function removeAds() {
18        console.log('Removing advertisements...');
19        
20        // Remove Google AdSense ads
21        const adsbyGoogle = document.querySelectorAll('.adsbygoogle, ins.adsbygoogle');
22        adsbyGoogle.forEach(ad => {
23            console.log('Removing AdSense element:', ad);
24            ad.remove();
25        });
26
27        // Remove ad iframes
28        const adIframes = document.querySelectorAll('iframe[src*="ads"], iframe[src*="doubleclick"], iframe[src*="googlesyndication"]');
29        adIframes.forEach(iframe => {
30            console.log('Removing ad iframe:', iframe);
31            iframe.remove();
32        });
33
34        // Remove elements with ad-related IDs and classes
35        const adElements = document.querySelectorAll('[id*="ad-"], [class*="ad-container"], [id*="advertisement"], [class*="advertisement"]');
36        adElements.forEach(el => {
37            console.log('Removing ad element:', el);
38            el.remove();
39        });
40
41        // Remove parent containers that only contain ads
42        const pageShortcodes = document.querySelectorAll('.page-content.page-shortcode');
43        pageShortcodes.forEach(container => {
44            // If container only has ad content and no meaningful text
45            if (container.querySelector('.adsbygoogle') && container.textContent.trim().length < 50) {
46                console.log('Removing ad container:', container);
47                container.remove();
48            }
49        });
50
51        console.log('Advertisements removed successfully');
52    }
53
54    // Function to remove floating banners and sticky elements
55    function removeFloatingElements() {
56        console.log('Removing floating banners and sticky elements...');
57        
58        // Remove bg-lock overlay
59        const bgLock = document.querySelectorAll('.bg-lock');
60        bgLock.forEach(el => {
61            console.log('Removing bg-lock:', el);
62            el.remove();
63        });
64
65        // Remove go-up button
66        const goUp = document.querySelectorAll('.go-up');
67        goUp.forEach(el => {
68            console.log('Removing go-up button:', el);
69            el.remove();
70        });
71
72        // Remove sticky mobile menu
73        const mobileMenu = document.querySelectorAll('.new-mobile-menu-container');
74        mobileMenu.forEach(el => {
75            console.log('Removing mobile menu:', el);
76            el.remove();
77        });
78
79        // Remove VDO.AI video ads (floating video players)
80        const vdoAds = document.querySelectorAll('[id*="vdo_ads"], [class*="vdo_"], .vdo_floating, .vdo_video_unit');
81        vdoAds.forEach(el => {
82            console.log('Removing VDO video ad:', el);
83            el.remove();
84        });
85
86        // Remove any other fixed/sticky positioned elements that might be ads or banners
87        const allElements = document.querySelectorAll('*');
88        allElements.forEach(el => {
89            const style = window.getComputedStyle(el);
90            if ((style.position === 'fixed' || style.position === 'sticky')) {
91                // Check if it's likely an ad or unwanted element
92                const className = el.className.toLowerCase();
93                const id = el.id.toLowerCase();
94                
95                if (className.includes('banner') || className.includes('popup') || 
96                    className.includes('modal') || className.includes('ad') ||
97                    className.includes('vdo') || className.includes('floating') ||
98                    id.includes('banner') || id.includes('ad') || id.includes('vdo') ||
99                    id.includes('popup') || id.includes('floating')) {
100                    console.log('Removing floating element:', el);
101                    el.remove();
102                }
103            }
104        });
105
106        console.log('Floating elements removed successfully');
107    }
108
109    // Function to hide login and signup options
110    function hideLoginSignup() {
111        console.log('Hiding login/signup options...');
112        
113        // Hide login links
114        const loginLinks = document.querySelectorAll('a[href*="login"], a[href*="signin"], button[class*="login"]');
115        loginLinks.forEach(link => {
116            console.log('Hiding login element:', link);
117            link.style.display = 'none';
118        });
119
120        // Hide signup/register links
121        const signupLinks = document.querySelectorAll('a[href*="signup"], a[href*="register"], button[class*="signup"], button[class*="register"]');
122        signupLinks.forEach(link => {
123            console.log('Hiding signup element:', link);
124            link.style.display = 'none';
125        });
126
127        console.log('Login/signup options hidden successfully');
128    }
129
130    // Function to add PDF download buttons to content sections
131    function addPDFDownloadButtons() {
132        console.log('Adding PDF download buttons...');
133
134        // Try to find the main content container
135        const mainContent = document.querySelector('.main-content, .container.main-content');
136        if (!mainContent) {
137            console.log('Main content container not found');
138            return;
139        }
140
141        // Check if we already added a PDF button to this page
142        if (document.querySelector('.pdf-download-btn-page')) {
143            console.log('PDF button already exists on this page');
144            return;
145        }
146
147        // Find the page title
148        let titleElement = document.querySelector('.boxedtitle.page-title h2, h1.page-title, .page-title h1, .page-title h2');
149        let pageTitle = 'Page Content';
150        
151        if (titleElement) {
152            pageTitle = titleElement.textContent.trim();
153        } else {
154            // Fallback to document title
155            pageTitle = document.title.split('-')[0].trim();
156        }
157
158        // Create download button
159        const downloadBtn = document.createElement('button');
160        downloadBtn.className = 'pdf-download-btn pdf-download-btn-page';
161        downloadBtn.innerHTML = '📥 Download Page as PDF';
162        downloadBtn.style.cssText = `
163            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
164            color: white;
165            border: none;
166            padding: 12px 24px;
167            border-radius: 6px;
168            cursor: pointer;
169            font-size: 16px;
170            font-weight: 600;
171            margin: 20px 0;
172            display: inline-block;
173            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
174            transition: all 0.3s ease;
175            position: relative;
176            z-index: 1000;
177        `;
178
179        // Add hover effect
180        downloadBtn.onmouseover = function() {
181            this.style.transform = 'translateY(-2px)';
182            this.style.boxShadow = '0 6px 12px rgba(0, 0, 0, 0.15)';
183        };
184        downloadBtn.onmouseout = function() {
185            this.style.transform = 'translateY(0)';
186            this.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
187        };
188
189        // Add click handler
190        downloadBtn.onclick = async function() {
191            const originalText = this.innerHTML;
192            this.innerHTML = '⏳ Generating PDF...';
193            this.disabled = true;
194
195            try {
196                await generatePDF(mainContent, pageTitle);
197                this.innerHTML = '✅ Downloaded!';
198                setTimeout(() => {
199                    this.innerHTML = originalText;
200                    this.disabled = false;
201                }, 2000);
202            } catch (error) {
203                console.error('PDF generation error:', error);
204                this.innerHTML = '❌ Error - Try Again';
205                setTimeout(() => {
206                    this.innerHTML = originalText;
207                    this.disabled = false;
208                }, 2000);
209            }
210        };
211
212        // Insert button at the top of main content
213        const firstChild = mainContent.querySelector('.col-md-8, article, .page-content');
214        if (firstChild) {
215            firstChild.insertBefore(downloadBtn, firstChild.firstChild);
216            console.log('Added PDF download button to page');
217        } else {
218            mainContent.insertBefore(downloadBtn, mainContent.firstChild);
219            console.log('Added PDF download button to main content');
220        }
221    }
222
223    // Function to generate PDF from content section
224    async function generatePDF(section, title) {
225        console.log('Generating PDF for:', title);
226
227        const { jsPDF } = window.jspdf;
228        const pdf = new jsPDF('p', 'mm', 'a4');
229        
230        // Clone the section to avoid modifying the original
231        const clonedSection = section.cloneNode(true);
232        
233        // Remove the PDF download button from the clone
234        const pdfButton = clonedSection.querySelector('.pdf-download-btn');
235        if (pdfButton) {
236            pdfButton.remove();
237        }
238
239        // Create a temporary container with white background
240        const tempContainer = document.createElement('div');
241        tempContainer.style.cssText = `
242            position: absolute;
243            left: -9999px;
244            top: 0;
245            background: white;
246            padding: 20px;
247            width: 800px;
248            font-family: Arial, sans-serif;
249        `;
250        tempContainer.appendChild(clonedSection);
251        document.body.appendChild(tempContainer);
252
253        try {
254            // Use html2canvas to capture the content with better quality
255            const canvas = await html2canvas(tempContainer, {
256                scale: 2,
257                useCORS: true,
258                logging: false,
259                backgroundColor: '#ffffff',
260                windowWidth: 800,
261                windowHeight: tempContainer.scrollHeight
262            });
263
264            const imgData = canvas.toDataURL('image/png');
265            const imgWidth = 180; // A4 width minus margins
266            const imgHeight = (canvas.height * imgWidth) / canvas.width;
267            
268            let heightLeft = imgHeight;
269            let position = 10;
270
271            // Add first page
272            pdf.addImage(imgData, 'PNG', 15, position, imgWidth, imgHeight);
273            heightLeft -= (pdf.internal.pageSize.height - position);
274
275            // Add additional pages if needed
276            while (heightLeft > 0) {
277                position = heightLeft - imgHeight + 10;
278                pdf.addPage();
279                pdf.addImage(imgData, 'PNG', 15, position, imgWidth, imgHeight);
280                heightLeft -= pdf.internal.pageSize.height;
281            }
282
283            // Generate filename from title
284            const filename = title.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '.pdf';
285            pdf.save(filename);
286            
287            console.log('PDF generated successfully:', filename);
288        } finally {
289            // Clean up temporary container
290            document.body.removeChild(tempContainer);
291        }
292    }
293
294    // Add custom CSS to improve appearance
295    function addCustomStyles() {
296        const style = document.createElement('style');
297        style.textContent = `
298            /* Hide ad spaces */
299            .adsbygoogle,
300            ins.adsbygoogle,
301            [id*="ad-"],
302            [class*="ad-container"],
303            [id*="vdo_ads"],
304            [class*="vdo_"],
305            .vdo_floating,
306            .vdo_video_unit {
307                display: none !important;
308                visibility: hidden !important;
309                opacity: 0 !important;
310                pointer-events: none !important;
311            }
312
313            /* Hide floating elements */
314            .bg-lock,
315            .go-up,
316            .new-mobile-menu-container {
317                display: none !important;
318            }
319
320            /* Remove fixed positioning from potential ad containers */
321            [class*="banner"],
322            [class*="popup"],
323            [id*="banner"] {
324                position: static !important;
325            }
326
327            /* Improve content spacing after ad removal */
328            .page-content.page-shortcode {
329                margin-bottom: 20px;
330            }
331
332            /* PDF button responsive design */
333            @media (max-width: 768px) {
334                .pdf-download-btn {
335                    width: 100%;
336                    margin: 15px 0 !important;
337                }
338            }
339
340            /* Clean layout */
341            .main-content {
342                background: white;
343            }
344        `;
345        document.head.appendChild(style);
346        console.log('Custom styles added');
347    }
348
349    // Debounce function for MutationObserver
350    function debounce(func, wait) {
351        let timeout;
352        return function executedFunction(...args) {
353            const later = () => {
354                clearTimeout(timeout);
355                func(...args);
356            };
357            clearTimeout(timeout);
358            timeout = setTimeout(later, wait);
359        };
360    }
361
362    // Initialize the extension
363    function init() {
364        console.log('Initializing Examveda Ad-Free Extension...');
365        
366        // Add custom styles
367        addCustomStyles();
368        
369        // Remove ads
370        removeAds();
371        
372        // Remove floating elements
373        removeFloatingElements();
374        
375        // Hide login/signup
376        hideLoginSignup();
377        
378        // Add PDF download buttons
379        addPDFDownloadButtons();
380
381        // Watch for dynamic content changes
382        const debouncedUpdate = debounce(() => {
383            removeAds();
384            removeFloatingElements();
385            hideLoginSignup();
386            addPDFDownloadButtons();
387        }, 1000);
388
389        const observer = new MutationObserver(debouncedUpdate);
390        observer.observe(document.body, {
391            childList: true,
392            subtree: true
393        });
394
395        console.log('Examveda Ad-Free Extension: Initialized successfully!');
396    }
397
398    // Wait for page to load
399    if (document.readyState === 'loading') {
400        document.addEventListener('DOMContentLoaded', init);
401    } else {
402        init();
403    }
404
405})();
Examveda Ad-Free with PDF Downloads | Robomonkey