Medium Member Bypass

Modern Medium GUI with multiple bypass services.

As of 16. 12. 2024. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Medium Member Bypass
// @author       UniverseDev
// @license      GPL-3.0-or-later
// @namespace    http://tampermonkey.net/
// @version      12.9
// @description  Modern Medium GUI with multiple bypass services.
// @match        *://*.medium.com/*
// @match        https://freedium.cfd/*
// @match        https://readmedium.com/*
// @match        https://md.vern.cc/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(() => {
    'use strict';

    const config = {
        bypassUrls: {
            freedium: 'https://freedium.cfd',
            readmedium: 'https://readmedium.com',
            libmedium: 'https://md.vern.cc/',
        },
        currentBypass: GM_getValue('currentBypass', 'freedium'),
        memberOnlyDivSelector: 'p.bf.b.bg.z.bk',
        autoRedirectDelay: GM_getValue('redirectDelay', 5000),
        autoRedirectEnabled: GM_getValue('autoRedirect', true),
        darkModeEnabled: GM_getValue('darkModeEnabled', false),
        isBypassSession: GM_getValue('isBypassSession', false),
    };

    const injectStyles = () => {
        const style = document.createElement('style');
        style.textContent = `
            .medium-settings {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 360px;
                background-color: var(--background-color, white);
                box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
                border-radius: 16px;
                font-family: 'Arial', sans-serif;
                z-index: 10000;
                padding: 20px;
                display: none;
                color: var(--text-color, #333);
                cursor: grab;
            }
            .medium-settings.dark {
                --background-color: #333;
                --text-color: white;
            }
            .medium-settings-header {
                font-size: 22px;
                font-weight: bold;
                margin-bottom: 20px;
                text-align: center;
            }
            .medium-settings-toggle {
                margin: 15px 0;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .medium-settings-input {
                margin-left: 10px;
                width: 70px;
                padding: 6px;
                text-align: center;
                border: 1px solid #ccc;
                border-radius: 4px;
            }
            .medium-settings-button {
                background-color: var(--button-bg-color, #1a8917);
                color: var(--button-text-color, white);
                border: none;
                padding: 8px 14px;
                border-radius: 20px;
                cursor: pointer;
                font-weight: bold;
                transition: background-color 0.3s;
            }
            .medium-settings-button:hover {
                background-color: #155c11;
            }
            .medium-notification {
                position: fixed;
                bottom: 20px;
                right: 20px;
                background-color: #1a8917;
                color: white;
                padding: 15px;
                border-radius: 20px;
                box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
                font-family: 'Arial', sans-serif;
                z-index: 10000;
                opacity: 0;
                transform: translateY(20px);
                transition: all 0.3s ease;
            }
            .medium-notification.show {
                opacity: 1;
                transform: translateY(0);
            }
        `;
        document.head.appendChild(style);
    };

    const stealthNotification = (message) => {
        const notification = document.createElement('div');
        notification.className = 'medium-notification';
        notification.textContent = message;
        document.body.appendChild(notification);

        setTimeout(() => notification.classList.add('show'), 50);
        setTimeout(() => {
            notification.classList.remove('show');
            setTimeout(() => notification.remove(), 300);
        }, 3000);
    };

    const showMediumSettings = () => {
        let existingPanel = document.querySelector('.medium-settings');
        if (existingPanel) {
            existingPanel.style.display = 'block';
            return;
        }

        const settingsContainer = document.createElement('div');
        settingsContainer.className = `medium-settings ${config.darkModeEnabled ? 'dark' : ''}`;

        settingsContainer.innerHTML = `
            <div class="medium-settings-header">Medium Settings</div>
            <div class="medium-settings-toggle">
                <span>Auto-Redirect</span>
                <button class="medium-settings-button" id="toggleRedirect">${config.autoRedirectEnabled ? 'ON' : 'OFF'}</button>
            </div>
            <div class="medium-settings-toggle">
                <span>Redirect Delay (ms)</span>
                <input type="number" class="medium-settings-input" id="redirectDelay" value="${config.autoRedirectDelay}" />
            </div>
            <div class="medium-settings-toggle">
                <span>Dark Mode</span>
                <button class="medium-settings-button" id="toggleDarkMode">${config.darkModeEnabled ? 'ON' : 'OFF'}</button>
            </div>
            <div class="medium-settings-toggle">
                <span>Bypass Service</span>
                <select id="bypassSelector" class="medium-settings-input">
                    ${Object.keys(config.bypassUrls).map((key) => `
                        <option value="${key}" ${config.currentBypass === key ? 'selected' : ''}>${key}</option>
                    `).join('')}
                </select>
            </div>
            <div class="medium-settings-toggle">
                <button class="medium-settings-button" id="bypassNow">Bypass Now</button>
            </div>
            <div class="medium-settings-toggle">
                <button class="medium-settings-button" id="resetDefaults">Reset to Default</button>
            </div>
            <div class="medium-settings-toggle">
                <button class="medium-settings-button" id="saveSettings">Save</button>
                <button class="medium-settings-button" id="closeSettings">Close</button>
            </div>
        `;

        document.body.appendChild(settingsContainer);

        let isDragging = false;
        let startX, startY;

        settingsContainer.addEventListener('mousedown', (e) => {
            isDragging = true;
            startX = e.clientX - settingsContainer.offsetLeft;
            startY = e.clientY - settingsContainer.offsetTop;
            settingsContainer.style.cursor = 'grabbing';
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            settingsContainer.style.left = `${e.clientX - startX}px`;
            settingsContainer.style.top = `${e.clientY - startY}px`;
        });

        document.addEventListener('mouseup', () => {
            isDragging = false;
            settingsContainer.style.cursor = 'grab';
        });

        settingsContainer.querySelector('#toggleRedirect').addEventListener('click', () => {
            config.autoRedirectEnabled = !config.autoRedirectEnabled;
            GM_setValue('autoRedirect', config.autoRedirectEnabled);
            settingsContainer.querySelector('#toggleRedirect').textContent = config.autoRedirectEnabled ? 'ON' : 'OFF';
            stealthNotification('Auto-Redirect toggled');
        });

        settingsContainer.querySelector('#toggleDarkMode').addEventListener('click', () => {
            config.darkModeEnabled = !config.darkModeEnabled;
            GM_setValue('darkModeEnabled', config.darkModeEnabled);
            settingsContainer.classList.toggle('dark', config.darkModeEnabled);
            settingsContainer.querySelector('#toggleDarkMode').textContent = config.darkModeEnabled ? 'ON' : 'OFF';
            stealthNotification('Dark Mode toggled');
        });

        settingsContainer.querySelector('#bypassSelector').addEventListener('change', (e) => {
            config.currentBypass = e.target.value;
            GM_setValue('currentBypass', config.currentBypass);
            stealthNotification(`Bypass service set to ${config.currentBypass}`);
        });

        settingsContainer.querySelector('#bypassNow').addEventListener('click', () => {
            window.location.href = config.bypassUrls[config.currentBypass] + window.location.pathname;
        });

        settingsContainer.querySelector('#resetDefaults').addEventListener('click', () => {
            config.autoRedirectDelay = 5000;
            config.autoRedirectEnabled = true;
            config.darkModeEnabled = false;
            config.currentBypass = 'freedium';

            GM_setValue('redirectDelay', config.autoRedirectDelay);
            GM_setValue('autoRedirect', config.autoRedirectEnabled);
            GM_setValue('darkModeEnabled', config.darkModeEnabled);
            GM_setValue('currentBypass', config.currentBypass);

            settingsContainer.querySelector('#redirectDelay').value = config.autoRedirectDelay;
            settingsContainer.querySelector('#toggleRedirect').textContent = 'ON';
            settingsContainer.querySelector('#toggleDarkMode').textContent = 'OFF';
            settingsContainer.querySelector('#bypassSelector').value = 'freedium';
            settingsContainer.classList.remove('dark');
            stealthNotification('Settings reset to defaults');
        });

        settingsContainer.querySelector('#saveSettings').addEventListener('click', () => {
            const newDelay = parseInt(settingsContainer.querySelector('#redirectDelay').value, 10);
            if (!isNaN(newDelay) && newDelay >= 0) {
                config.autoRedirectDelay = newDelay;
                GM_setValue('redirectDelay', newDelay);
                stealthNotification('Settings saved');
            }
        });

        settingsContainer.querySelector('#closeSettings').addEventListener('click', () => {
            settingsContainer.style.display = 'none';
        });

        settingsContainer.style.display = 'block';
    };

    const performAutoRedirect = () => {
        if (config.isBypassSession) {
            GM_setValue('isBypassSession', false);
            return;
        }

        if (config.autoRedirectEnabled && document.querySelector(config.memberOnlyDivSelector)) {
            setTimeout(() => {
                window.location.href = config.bypassUrls[config.currentBypass] + window.location.pathname;
            }, config.autoRedirectDelay);
            stealthNotification('Redirecting to bypass service...');
        }
    };

    const initializeScript = () => {
        injectStyles();

        const isBypassPage = Object.values(config.bypassUrls).some((url) => window.location.href.startsWith(url));

        if (isBypassPage) {
            GM_setValue('isBypassSession', true);
        } else if (window.location.href.startsWith('https://medium.com/')) {
            GM_registerMenuCommand('Open Medium Settings', showMediumSettings);
            performAutoRedirect();
        }
    };

    initializeScript();
})();