Examveda Ad Remover & Question Downloader

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

Size

12.1 KB

Version

2.1.5

Created

Oct 31, 2025

Updated

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