Removes ads, banners, and login prompts from Brainly and adds PDF download functionality
Size
11.9 KB
Version
1.0.0
Created
Nov 10, 2025
Updated
about 1 month ago
1// ==UserScript==
2// @name Brainly Ad Blocker & PDF Downloader
3// @description Removes ads, banners, and login prompts from Brainly and adds PDF download functionality
4// @version 1.0.0
5// @match https://*.brainly.in/*
6// @icon https://styleguide.brainly.in/images/favicons/brainly/favicon-8bc2eedef6.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('Brainly Ad Blocker & PDF Downloader initialized');
13
14 // Function to remove ads, banners, and login/signup elements
15 function removeAdsAndPrompts() {
16 console.log('Removing ads and login prompts...');
17
18 // Remove all ad containers
19 const adSelectors = [
20 '.ads_banner',
21 '.js-screening-ad-container',
22 '.js-rich-ad-container',
23 '#new-ad-placeholder-question-desktop',
24 '.brn-ads-box',
25 '.js-new-ad-placeholder',
26 '.js-react-ads-under-question-desktop',
27 '[data-testid="brainly_ads_placeholder"]',
28 '.BrainlyAdsPlaceholder-module__placeholder--iwQcq',
29 '.VideoAdUnit-module__video-ad-unit--EnHJ-',
30 '.withLabel-module__wrapper--WqQ32',
31 '[id*="ad"]',
32 '[class*="ad-"]',
33 '[class*="Ad-"]',
34 '[class*="ads-"]',
35 '[class*="Ads-"]'
36 ];
37
38 adSelectors.forEach(selector => {
39 const elements = document.querySelectorAll(selector);
40 elements.forEach(el => {
41 console.log('Removing ad element:', selector);
42 el.remove();
43 });
44 });
45
46 // Remove login/signup buttons and prompts
47 const loginSelectors = [
48 '[data-testid="navigation_login"]',
49 '[data-testid="navigation_register"]',
50 '[data-testid="registration_toplayer_close_button"]',
51 '.PromoButtonOutline-module__wrapper--qvQdn',
52 '.RegistrationPromoToplayer-module__image--73J4j'
53 ];
54
55 loginSelectors.forEach(selector => {
56 const elements = document.querySelectorAll(selector);
57 elements.forEach(el => {
58 console.log('Removing login/signup element:', selector);
59 el.closest('.sg-flex')?.remove() || el.remove();
60 });
61 });
62
63 // Remove any modal/overlay prompts
64 const modals = document.querySelectorAll('[class*="modal"], [class*="Modal"], [class*="overlay"], [class*="Overlay"], [class*="dialog"], [class*="Dialog"]');
65 modals.forEach(modal => {
66 if (modal.textContent.toLowerCase().includes('login') ||
67 modal.textContent.toLowerCase().includes('sign up') ||
68 modal.textContent.toLowerCase().includes('join')) {
69 console.log('Removing modal/overlay');
70 modal.remove();
71 }
72 });
73
74 console.log('Ads and prompts removed successfully');
75 }
76
77 // Function to add PDF download button
78 function addPDFDownloadButton() {
79 console.log('Adding PDF download button...');
80
81 // Check if button already exists
82 if (document.getElementById('brainly-pdf-download-btn')) {
83 console.log('PDF button already exists');
84 return;
85 }
86
87 // Find the question container
88 const questionContainer = document.querySelector('[data-testid="question_box"]') ||
89 document.querySelector('.js-question') ||
90 document.querySelector('#main-content');
91
92 if (!questionContainer) {
93 console.error('Question container not found');
94 return;
95 }
96
97 // Create download button
98 const downloadBtn = document.createElement('button');
99 downloadBtn.id = 'brainly-pdf-download-btn';
100 downloadBtn.innerHTML = `
101 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
102 <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
103 <polyline points="7 10 12 15 17 10"></polyline>
104 <line x1="12" y1="15" x2="12" y2="3"></line>
105 </svg>
106 <span>Download as PDF</span>
107 `;
108
109 // Style the button
110 downloadBtn.style.cssText = `
111 position: fixed;
112 top: 100px;
113 right: 20px;
114 z-index: 9999;
115 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
116 color: white;
117 border: none;
118 padding: 12px 24px;
119 border-radius: 8px;
120 font-size: 16px;
121 font-weight: 600;
122 cursor: pointer;
123 box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
124 display: flex;
125 align-items: center;
126 gap: 8px;
127 transition: all 0.3s ease;
128 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
129 `;
130
131 // Add hover effect
132 downloadBtn.addEventListener('mouseenter', () => {
133 downloadBtn.style.transform = 'translateY(-2px)';
134 downloadBtn.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.6)';
135 });
136
137 downloadBtn.addEventListener('mouseleave', () => {
138 downloadBtn.style.transform = 'translateY(0)';
139 downloadBtn.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.4)';
140 });
141
142 // Add click handler
143 downloadBtn.addEventListener('click', generatePDF);
144
145 // Add button to page
146 document.body.appendChild(downloadBtn);
147 console.log('PDF download button added successfully');
148 }
149
150 // Function to generate PDF
151 async function generatePDF() {
152 console.log('Generating PDF...');
153
154 const button = document.getElementById('brainly-pdf-download-btn');
155 const originalText = button.innerHTML;
156
157 try {
158 // Update button to show loading state
159 button.innerHTML = `
160 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
161 <circle cx="12" cy="12" r="10"></circle>
162 </svg>
163 <span>Generating PDF...</span>
164 `;
165 button.disabled = true;
166 button.style.opacity = '0.7';
167 button.style.cursor = 'not-allowed';
168
169 // Get the main content area
170 const contentElement = document.querySelector('#main-content') ||
171 document.querySelector('.brn-qpage-layout__main') ||
172 document.querySelector('.js-main-container');
173
174 if (!contentElement) {
175 throw new Error('Content not found');
176 }
177
178 // Clone the content to avoid modifying the original
179 const clonedContent = contentElement.cloneNode(true);
180
181 // Remove any remaining ads from cloned content
182 const adsInClone = clonedContent.querySelectorAll('[class*="ad"], [class*="Ad"], [id*="ad"]');
183 adsInClone.forEach(ad => ad.remove());
184
185 // Get page title for filename
186 const pageTitle = document.querySelector('h1')?.textContent ||
187 document.querySelector('[data-testid="question_box"] .sg-text')?.textContent ||
188 'brainly-question';
189 const filename = pageTitle.substring(0, 50).replace(/[^a-z0-9]/gi, '_').toLowerCase() + '.pdf';
190
191 // Configure PDF options
192 const opt = {
193 margin: [10, 10, 10, 10],
194 filename: filename,
195 image: { type: 'jpeg', quality: 0.98 },
196 html2canvas: {
197 scale: 2,
198 useCORS: true,
199 logging: false,
200 letterRendering: true,
201 scrollY: 0,
202 scrollX: 0
203 },
204 jsPDF: {
205 unit: 'mm',
206 format: 'a4',
207 orientation: 'portrait',
208 compress: true
209 },
210 pagebreak: { mode: ['avoid-all', 'css', 'legacy'] }
211 };
212
213 // Generate PDF
214 await html2pdf().set(opt).from(clonedContent).save();
215
216 console.log('PDF generated successfully');
217
218 // Show success message
219 button.innerHTML = `
220 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
221 <polyline points="20 6 9 17 4 12"></polyline>
222 </svg>
223 <span>Downloaded!</span>
224 `;
225
226 // Reset button after 2 seconds
227 setTimeout(() => {
228 button.innerHTML = originalText;
229 button.disabled = false;
230 button.style.opacity = '1';
231 button.style.cursor = 'pointer';
232 }, 2000);
233
234 } catch (error) {
235 console.error('Error generating PDF:', error);
236
237 // Show error message
238 button.innerHTML = `
239 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
240 <circle cx="12" cy="12" r="10"></circle>
241 <line x1="15" y1="9" x2="9" y2="15"></line>
242 <line x1="9" y1="9" x2="15" y2="15"></line>
243 </svg>
244 <span>Error! Try again</span>
245 `;
246
247 // Reset button after 2 seconds
248 setTimeout(() => {
249 button.innerHTML = originalText;
250 button.disabled = false;
251 button.style.opacity = '1';
252 button.style.cursor = 'pointer';
253 }, 2000);
254 }
255 }
256
257 // Function to observe DOM changes and remove ads dynamically
258 function observeDOMChanges() {
259 const observer = new MutationObserver((mutations) => {
260 let shouldRemoveAds = false;
261
262 mutations.forEach((mutation) => {
263 mutation.addedNodes.forEach((node) => {
264 if (node.nodeType === 1) { // Element node
265 const element = node;
266 // Check if added node is an ad or contains ads
267 if (element.className && (
268 element.className.includes('ad') ||
269 element.className.includes('Ad') ||
270 element.className.includes('login') ||
271 element.className.includes('signup') ||
272 element.className.includes('register')
273 )) {
274 shouldRemoveAds = true;
275 }
276 }
277 });
278 });
279
280 if (shouldRemoveAds) {
281 setTimeout(removeAdsAndPrompts, 100);
282 }
283 });
284
285 observer.observe(document.body, {
286 childList: true,
287 subtree: true
288 });
289
290 console.log('DOM observer initialized');
291 }
292
293 // Initialize the extension
294 function init() {
295 console.log('Initializing Brainly Ad Blocker & PDF Downloader...');
296
297 // Wait for page to load
298 if (document.readyState === 'loading') {
299 document.addEventListener('DOMContentLoaded', () => {
300 setTimeout(() => {
301 removeAdsAndPrompts();
302 addPDFDownloadButton();
303 observeDOMChanges();
304 }, 1000);
305 });
306 } else {
307 setTimeout(() => {
308 removeAdsAndPrompts();
309 addPDFDownloadButton();
310 observeDOMChanges();
311 }, 1000);
312 }
313
314 // Also run after a delay to catch lazy-loaded ads
315 setTimeout(removeAdsAndPrompts, 3000);
316 setTimeout(removeAdsAndPrompts, 5000);
317 }
318
319 // Start the extension
320 init();
321
322})();