Medium Member Bypass

Modern Medium GUI with multiple bypass services.

Pada tanggal 18 Desember 2024. Lihat %(latest_version_link).

// ==UserScript==
// @name         Medium Member Bypass
// @author       UniverseDev
// @license      GPL-3.0-or-later
// @namespace    http://tampermonkey.net/
// @version      13.0
// @description  Modern Medium GUI with multiple bypass services.
// @match        *://*.medium.com/*
// @match        https://freedium.cfd/*
// @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/',
            archive: 'https://archive.is/newest/',
            archiveLi: 'https://archive.li/newest/',
            archiveVn: 'https://archive.vn/newest/',
            archivePh: 'https://archive.ph/newest/',
        },
        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', () => {
            const articleUrl = encodeURIComponent(window.location.href);
            const bypassService = config.currentBypass;
            const bypassUrl = config.bypassUrls[bypassService];

            if (bypassService.startsWith('archive')) {
                window.location.href = `${bypassUrl}?url=${articleUrl}`;
            } else {
                window.location.href = bypassUrl + 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(() => {
            const articleUrl = encodeURIComponent(window.location.href);
            const bypassService = config.currentBypass;

            if (bypassService.startsWith('archive')) {
                const bypassUrl = config.bypassUrls[bypassService];
                window.location.href = `${bypassUrl}${articleUrl}`;
            } else {
                const bypassUrl = config.bypassUrls[bypassService];
                window.location.href = bypassUrl + window.location.pathname;
            }
        }, config.autoRedirectDelay);
        stealthNotification('Redirecting to bypass service...');
    }
};

const cleanBypassFragment = () => {
    const archiveDomains = ['archive.is', 'archive.li', 'archive.vn', 'archive.ph'];
    const currentDomain = window.location.hostname;

    if (archiveDomains.includes(currentDomain) && window.location.hash === '#bypass') {
        const cleanUrl = window.location.href.replace('#bypass', '');
        window.location.replace(cleanUrl);
    }
};

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

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