Brainly Ad Blocker & PDF Downloader

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})();
Brainly Ad Blocker & PDF Downloader | Robomonkey