Article Login & Paywall Bypass

Automatically bypass login walls and paywalls on articles

Size

8.8 KB

Version

1.1.1

Created

Dec 11, 2025

Updated

3 months ago

1// ==UserScript==
2// @name		Article Login & Paywall Bypass
3// @description		Automatically bypass login walls and paywalls on articles
4// @version		1.1.1
5// @match		*://*/*
6// ==/UserScript==
7(function() {
8    'use strict';
9
10    console.log('Article Login & Paywall Bypass extension loaded');
11
12    // Debounce function to prevent excessive calls
13    function debounce(func, wait) {
14        let timeout;
15        return function executedFunction(...args) {
16            const later = () => {
17                clearTimeout(timeout);
18                func(...args);
19            };
20            clearTimeout(timeout);
21            timeout = setTimeout(later, wait);
22        };
23    }
24
25    // Check if element is likely a paywall overlay
26    function isPaywallOverlay(element) {
27        const style = window.getComputedStyle(element);
28        const rect = element.getBoundingClientRect();
29        
30        // Must be fixed or absolute positioned
31        if (style.position !== 'fixed' && style.position !== 'absolute') {
32            return false;
33        }
34        
35        // Must cover significant portion of screen
36        const coverageThreshold = 0.3;
37        const viewportArea = window.innerWidth * window.innerHeight;
38        const elementArea = rect.width * rect.height;
39        
40        if (elementArea / viewportArea < coverageThreshold) {
41            return false;
42        }
43        
44        // Check for paywall-related text or classes
45        const text = element.textContent.toLowerCase();
46        const className = element.className.toLowerCase();
47        const id = element.id.toLowerCase();
48        
49        const paywallKeywords = ['paywall', 'subscribe', 'subscription', 'premium', 'login', 'sign in', 'register', 'member'];
50        
51        return paywallKeywords.some(keyword => 
52            text.includes(keyword) || className.includes(keyword) || id.includes(keyword)
53        );
54    }
55
56    // Remove overlay elements that block content
57    function removeOverlays() {
58        console.log('Checking for overlay elements...');
59        
60        // Common paywall overlay selectors
61        const overlaySelectors = [
62            '[class*="paywall"][style*="fixed"]',
63            '[class*="paywall"][style*="absolute"]',
64            '[id*="paywall"][style*="fixed"]',
65            '[id*="paywall"][style*="absolute"]',
66            '[class*="subscription-wall"]',
67            '[id*="subscription-wall"]',
68            '[class*="login-wall"]',
69            '[id*="login-wall"]',
70            '[data-testid*="paywall"]',
71            '[class*="modal"][class*="paywall"]',
72            '[class*="overlay"][class*="paywall"]'
73        ];
74
75        let removedCount = 0;
76        overlaySelectors.forEach(selector => {
77            try {
78                const elements = document.querySelectorAll(selector);
79                elements.forEach(el => {
80                    if (isPaywallOverlay(el)) {
81                        console.log('Removing paywall overlay:', el);
82                        el.remove();
83                        removedCount++;
84                    }
85                });
86            } catch (e) {
87                console.error('Error processing selector:', selector, e);
88            }
89        });
90        
91        if (removedCount > 0) {
92            console.log(`Removed ${removedCount} paywall overlays`);
93        }
94    }
95
96    // Remove blur effects from content
97    function removeBlur() {
98        const blurredElements = document.querySelectorAll('[class*="blur"], [style*="blur"]');
99        
100        blurredElements.forEach(el => {
101            const style = window.getComputedStyle(el);
102            if (style.filter && style.filter.includes('blur')) {
103                console.log('Removing blur from element:', el);
104                el.style.filter = 'none';
105                el.style.webkitFilter = 'none';
106            }
107        });
108    }
109
110    // Restore scroll functionality
111    function restoreScroll() {
112        // Only restore if scroll is actually disabled
113        const bodyStyle = window.getComputedStyle(document.body);
114        const htmlStyle = window.getComputedStyle(document.documentElement);
115        
116        if (bodyStyle.overflow === 'hidden' || htmlStyle.overflow === 'hidden') {
117            console.log('Restoring scroll functionality...');
118            document.body.style.overflow = '';
119            document.body.style.overflowY = '';
120            document.documentElement.style.overflow = '';
121            document.documentElement.style.overflowY = '';
122            document.body.style.position = '';
123        }
124    }
125
126    // Expand truncated content
127    function expandContent() {
128        const contentSelectors = [
129            'article[style*="max-height"]',
130            '[class*="article"][style*="max-height"]',
131            '[class*="content"][style*="max-height"]',
132            '[class*="post"][style*="max-height"]'
133        ];
134
135        contentSelectors.forEach(selector => {
136            try {
137                const elements = document.querySelectorAll(selector);
138                elements.forEach(el => {
139                    const style = window.getComputedStyle(el);
140                    if (style.maxHeight && style.maxHeight !== 'none' && parseInt(style.maxHeight) < 1000) {
141                        console.log('Expanding content element:', el);
142                        el.style.maxHeight = 'none';
143                        el.style.height = 'auto';
144                        el.style.overflow = 'visible';
145                    }
146                });
147            } catch (e) {
148                console.error('Error expanding content:', e);
149            }
150        });
151    }
152
153    // Add CSS to override common paywall styles
154    function addOverrideStyles() {
155        const css = `
156            /* Hide common paywall overlays */
157            [class*="paywall-overlay"],
158            [id*="paywall-overlay"],
159            [class*="subscription-wall"],
160            [id*="subscription-wall"],
161            [data-testid*="paywall"] {
162                display: none !important;
163            }
164            
165            /* Ensure body can scroll */
166            body.paywall-active,
167            body.modal-open,
168            html.paywall-active {
169                overflow: auto !important;
170                position: static !important;
171            }
172            
173            /* Remove blur from content */
174            article[class*="blur"],
175            [class*="article"][class*="blur"],
176            [class*="content"][class*="blur"] {
177                filter: none !important;
178                -webkit-filter: none !important;
179            }
180        `;
181        
182        TM_addStyle(css);
183    }
184
185    // Check for and remove specific paywall implementations
186    function removeSpecificPaywalls() {
187        // Medium paywall
188        if (window.location.hostname.includes('medium.com')) {
189            const paywallDiv = document.querySelector('[data-testid="paywall"]');
190            if (paywallDiv) {
191                console.log('Removing Medium paywall');
192                paywallDiv.remove();
193            }
194        }
195        
196        // New York Times
197        if (window.location.hostname.includes('nytimes.com')) {
198            const gateway = document.querySelector('[id*="gateway-content"]');
199            if (gateway) {
200                console.log('Removing NYT gateway');
201                gateway.remove();
202            }
203        }
204        
205        // Bloomberg
206        if (window.location.hostname.includes('bloomberg.com')) {
207            const fence = document.querySelector('[class*="paywall-fence"]');
208            if (fence) {
209                console.log('Removing Bloomberg paywall');
210                fence.remove();
211            }
212        }
213    }
214
215    // Main bypass function
216    function bypassLoginWall() {
217        try {
218            removeOverlays();
219            removeBlur();
220            restoreScroll();
221            expandContent();
222            removeSpecificPaywalls();
223        } catch (error) {
224            console.error('Error in bypass function:', error);
225        }
226    }
227
228    // Initialize the extension
229    function init() {
230        console.log('Initializing Article Login & Paywall Bypass...');
231        
232        // Add override styles
233        addOverrideStyles();
234        
235        // Run immediately
236        bypassLoginWall();
237        
238        // Run after delays to catch dynamically loaded paywalls
239        setTimeout(bypassLoginWall, 2000);
240        setTimeout(bypassLoginWall, 5000);
241        
242        // Watch for DOM changes
243        const debouncedBypass = debounce(bypassLoginWall, 1000);
244        const observer = new MutationObserver(debouncedBypass);
245        
246        observer.observe(document.body, {
247            childList: true,
248            subtree: true,
249            attributes: true,
250            attributeFilter: ['class', 'style']
251        });
252        
253        console.log('Article Login & Paywall Bypass initialized successfully');
254    }
255
256    // Wait for body to be ready
257    if (document.body) {
258        init();
259    } else {
260        TM_runBody(init);
261    }
262
263})();