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})();