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