Examveda Ad Remover & Question Downloader

Removes ads, enables text copying, and adds download buttons for question sections

Size

12.0 KB

Version

2.1.3

Created

Oct 29, 2025

Updated

about 2 months ago

1// ==UserScript==
2// @name		Examveda Ad Remover & Question Downloader
3// @description		Removes ads, enables text copying, and adds download buttons for question sections
4// @version		2.1.3
5// @match		https://*.examveda.com/*
6// @icon		https://www.examveda.com/favicon.ico
7// @require		https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js
8// ==/UserScript==
9(function() {
10    'use strict';
11
12    console.log('=== Examveda Extension Starting ===');
13
14    // Add CSS to hide ads, banners, and enable text selection
15    TM_addStyle(`
16        /* Remove all ads including floating and banner ads */
17        ins.adsbygoogle,
18        .adsbygoogle,
19        [data-ad-slot],
20        [id*="google_ads"],
21        [id*="google-auto-placed"],
22        [class*="advertisement"],
23        [class*="google-auto-placed"],
24        iframe[src*="doubleclick"],
25        iframe[src*="googlesyndication"],
26        div[style*="z-index: 2147483647"],
27        div[style*="position: fixed"][style*="bottom"],
28        div[style*="position: fixed"][style*="top"],
29        .banner-ad,
30        #banner-ad,
31        [class*="sticky-ad"],
32        [id*="sticky-ad"] {
33            display: none !important;
34            visibility: hidden !important;
35            height: 0 !important;
36            width: 0 !important;
37            opacity: 0 !important;
38            pointer-events: none !important;
39        }
40        
41        /* Enable text selection everywhere */
42        * {
43            -webkit-user-select: text !important;
44            -moz-user-select: text !important;
45            -ms-user-select: text !important;
46            user-select: text !important;
47        }
48        
49        /* Download button styles */
50        .examveda-download-btn {
51            background: #4CAF50 !important;
52            color: white !important;
53            border: none !important;
54            padding: 12px 24px !important;
55            margin: 20px 0 !important;
56            border-radius: 5px !important;
57            cursor: pointer !important;
58            font-size: 16px !important;
59            font-weight: bold !important;
60            box-shadow: 0 2px 5px rgba(0,0,0,0.2) !important;
61            transition: all 0.3s ease !important;
62            display: block !important;
63            width: 100% !important;
64            max-width: 300px !important;
65        }
66        
67        .examveda-download-btn:hover {
68            background: #45a049 !important;
69            transform: scale(1.02) !important;
70        }
71    `);
72
73    console.log('CSS styles added');
74
75    // Remove copy protection event listeners
76    ['copy', 'cut', 'contextmenu', 'selectstart'].forEach(eventType => {
77        document.addEventListener(eventType, function(e) {
78            e.stopPropagation();
79        }, true);
80    });
81
82    // Override copy protection properties
83    document.oncopy = null;
84    document.oncut = null;
85    document.onselectstart = null;
86    document.oncontextmenu = null;
87
88    TM_runBody(() => {
89        document.body.oncopy = null;
90        document.body.oncut = null;
91        document.body.onselectstart = null;
92        document.body.oncontextmenu = null;
93        console.log('Copy protection removed');
94    });
95
96    // Function to aggressively remove ad elements
97    function removeAdElements() {
98        const adSelectors = [
99            'ins.adsbygoogle',
100            '.adsbygoogle',
101            '[data-ad-slot]',
102            '[id*="google_ads"]',
103            '[id*="google-auto-placed"]',
104            '[class*="google-auto-placed"]',
105            'iframe[src*="doubleclick"]',
106            'iframe[src*="googlesyndication"]',
107            '.banner-ad',
108            '#banner-ad'
109        ];
110
111        let removedCount = 0;
112        adSelectors.forEach(selector => {
113            const elements = document.querySelectorAll(selector);
114            elements.forEach(el => {
115                el.remove();
116                removedCount++;
117            });
118        });
119
120        // Remove floating/fixed positioned elements that look like ads
121        const allElements = document.querySelectorAll('*');
122        allElements.forEach(el => {
123            const style = window.getComputedStyle(el);
124            if ((style.position === 'fixed' || style.position === 'sticky') && 
125                (el.innerHTML.includes('google') || el.innerHTML.includes('ad') || 
126                 el.className.includes('ad') || el.id.includes('ad'))) {
127                el.remove();
128                removedCount++;
129            }
130        });
131
132        if (removedCount > 0) {
133            console.log(`Removed ${removedCount} ad elements`);
134        }
135    }
136
137    // Function to download entire page content as PDF
138    async function downloadPageAsPDF() {
139        console.log('Starting PDF download...');
140        
141        try {
142            const { jsPDF } = window.jspdf;
143            const pdf = new jsPDF('p', 'pt', 'a4');
144            
145            // Get page title
146            const pageTitle = document.title || 'Examveda Content';
147            
148            // Get main content
149            const mainContent = document.querySelector('.main-content') || document.body;
150            
151            // Extract all text content from questions and answers
152            let contentText = `${pageTitle}\n\n`;
153            contentText += `URL: ${window.location.href}\n`;
154            contentText += `Downloaded: ${new Date().toLocaleString()}\n\n`;
155            contentText += '='.repeat(80) + '\n\n';
156            
157            // Get all questions
158            const questions = mainContent.querySelectorAll('.question.single-question');
159            
160            if (questions.length > 0) {
161                questions.forEach((question, index) => {
162                    // Get question text
163                    const questionText = question.querySelector('.question-main');
164                    if (questionText) {
165                        contentText += `Question ${index + 1}: ${questionText.textContent.trim()}\n\n`;
166                    }
167                    
168                    // Get options
169                    const options = question.querySelectorAll('.question-options p');
170                    options.forEach(option => {
171                        const optionText = option.textContent.trim();
172                        if (optionText) {
173                            contentText += `  ${optionText}\n`;
174                        }
175                    });
176                    
177                    // Get answer if visible
178                    const answer = question.querySelector('.question-answer');
179                    if (answer) {
180                        contentText += `\nAnswer: ${answer.textContent.trim()}\n`;
181                    }
182                    
183                    // Get explanation if visible
184                    const explanation = question.querySelector('.question-explanation');
185                    if (explanation) {
186                        contentText += `Explanation: ${explanation.textContent.trim()}\n`;
187                    }
188                    
189                    contentText += '\n' + '-'.repeat(80) + '\n\n';
190                });
191            } else {
192                // If no questions found, get all text content
193                contentText += mainContent.innerText || mainContent.textContent;
194            }
195            
196            // Add text to PDF with proper formatting
197            const pageWidth = pdf.internal.pageSize.getWidth();
198            const pageHeight = pdf.internal.pageSize.getHeight();
199            const margin = 40;
200            const maxWidth = pageWidth - (margin * 2);
201            const lineHeight = 15;
202            let yPosition = margin;
203            
204            pdf.setFontSize(10);
205            
206            const lines = pdf.splitTextToSize(contentText, maxWidth);
207            
208            lines.forEach(line => {
209                if (yPosition > pageHeight - margin) {
210                    pdf.addPage();
211                    yPosition = margin;
212                }
213                pdf.text(line, margin, yPosition);
214                yPosition += lineHeight;
215            });
216            
217            // Save the PDF
218            const fileName = pageTitle.replace(/[^a-z0-9]/gi, '_') + '.pdf';
219            pdf.save(fileName);
220            
221            console.log('PDF download complete:', fileName);
222            alert('PDF downloaded successfully!');
223            
224        } catch (error) {
225            console.error('PDF download error:', error);
226            alert('Error creating PDF. Falling back to text download.');
227            downloadPageAsText();
228        }
229    }
230
231    // Fallback function to download as text
232    function downloadPageAsText() {
233        console.log('Downloading as text...');
234        
235        const mainContent = document.querySelector('.main-content') || document.body;
236        const content = mainContent.innerText || mainContent.textContent;
237        
238        const pageTitle = document.title || 'Examveda_Content';
239        const fullContent = `${pageTitle}\n\nURL: ${window.location.href}\n\nDownloaded: ${new Date().toLocaleString()}\n\n${'='.repeat(80)}\n\n${content}`;
240        
241        const blob = new Blob([fullContent], { type: 'text/plain;charset=utf-8' });
242        const url = URL.createObjectURL(blob);
243        
244        const a = document.createElement('a');
245        a.href = url;
246        a.download = `${pageTitle.replace(/[^a-z0-9]/gi, '_')}.txt`;
247        document.body.appendChild(a);
248        a.click();
249        document.body.removeChild(a);
250        URL.revokeObjectURL(url);
251        
252        console.log('Text download complete');
253    }
254
255    // Function to add download button at the end of content
256    function addDownloadButton() {
257        console.log('Adding download button...');
258        
259        // Remove any existing download buttons
260        const existingButtons = document.querySelectorAll('.examveda-download-btn');
261        existingButtons.forEach(btn => btn.remove());
262        
263        // Find the main content area
264        const mainContent = document.querySelector('.main-content .col-md-8');
265        
266        if (!mainContent) {
267            console.log('Main content area not found');
268            return;
269        }
270        
271        // Create download button
272        const downloadBtn = document.createElement('button');
273        downloadBtn.className = 'examveda-download-btn';
274        downloadBtn.textContent = '📥 Download This Page as PDF';
275        downloadBtn.type = 'button';
276        
277        // Add click handler
278        downloadBtn.onclick = function(e) {
279            e.preventDefault();
280            e.stopPropagation();
281            downloadPageAsPDF();
282        };
283        
284        // Insert button at the end of content
285        mainContent.appendChild(downloadBtn);
286        console.log('Download button added at the end of content');
287    }
288
289    // Debounce function to prevent excessive calls
290    function debounce(func, wait) {
291        let timeout;
292        return function executedFunction(...args) {
293            const later = () => {
294                clearTimeout(timeout);
295                func(...args);
296            };
297            clearTimeout(timeout);
298            timeout = setTimeout(later, wait);
299        };
300    }
301
302    // Main initialization function
303    function init() {
304        console.log('Initializing extension...');
305        
306        // Remove ads immediately
307        removeAdElements();
308        
309        // Add download button after a short delay to ensure content is loaded
310        setTimeout(() => {
311            addDownloadButton();
312        }, 1000);
313        
314        // Set up observer for dynamic content with debouncing
315        const debouncedRemoveAds = debounce(removeAdElements, 500);
316        const debouncedAddButton = debounce(addDownloadButton, 1000);
317        
318        const observer = new MutationObserver(function() {
319            debouncedRemoveAds();
320            debouncedAddButton();
321        });
322        
323        observer.observe(document.body, {
324            childList: true,
325            subtree: true
326        });
327        
328        // Periodically remove ads
329        setInterval(removeAdElements, 2000);
330        
331        console.log('Extension initialized successfully!');
332    }
333
334    // Wait for page to load
335    if (document.readyState === 'loading') {
336        document.addEventListener('DOMContentLoaded', init);
337    } else {
338        init();
339    }
340
341})();
Examveda Ad Remover & Question Downloader | Robomonkey