Facebook Enhancer with Smart Menu

Enhance Facebook: block ads, stop autoplay (now Reels-safe), mute videos, unwrap links, auto-expand comments, remove suggestions, classic theme, mobile support, and debug mode. Save/load settings supported.

// ==UserScript==
// @name         Facebook Enhancer with Smart Menu
// @namespace    https://github.com/TamperMonkeyDevelopment/TamperMonkeyScripts
// @version      2.4
// @description  Enhance Facebook: block ads, stop autoplay (now Reels-safe), mute videos, unwrap links, auto-expand comments, remove suggestions, classic theme, mobile support, and debug mode. Save/load settings supported.
// @author       Eliminater74
// @match        *://www.facebook.com/*
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const settings = {
        blockSponsored: true,
        blockSuggested: true,
        disableAutoplay: true,
        muteVideos: true,
        removeBubbles: true,
        unwrapLinks: true,
        moveMessengerDock: false,
        forceDarkMode: false,
        forceMostRecentFeed: true,
        hidePeopleYouMayKnow: true,
        autoExpandComments: true,
        autoClosePopups: true,
        classicBlueTheme: false,
        debugMode: false
    };

    const storageKey = 'fb-enhancer-settings';
    let menuVisible = false;

    function loadSettings() {
        const saved = localStorage.getItem(storageKey);
        if (saved) Object.assign(settings, JSON.parse(saved));
    }

    function saveSettings() {
        localStorage.setItem(storageKey, JSON.stringify(settings));
    }

    function downloadSettings() {
        const blob = new Blob([JSON.stringify(settings, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'fb-enhancer-settings.json';
        a.click();
        URL.revokeObjectURL(url);
    }

    function uploadSettings() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = 'application/json';
        input.addEventListener('change', e => {
            const file = e.target.files[0];
            if (!file) return;
            const reader = new FileReader();
            reader.onload = event => {
                try {
                    const imported = JSON.parse(event.target.result);
                    Object.assign(settings, imported);
                    saveSettings();
                    alert('Settings loaded. Reloading...');
                    location.reload();
                } catch (err) {
                    alert('Failed to load settings file.');
                }
            };
            reader.readAsText(file);
        });
        input.click();
    }

    GM_addStyle(`
        #fb-enhancer-toggle {
            position: fixed;
            top: 60px;
            right: 10px;
            background: #4267B2;
            color: #fff;
            font-weight: bold;
            padding: 6px 10px;
            border-radius: 6px;
            cursor: pointer;
            z-index: 99999;
            font-size: 14px;
            box-shadow: 0 0 5px #000;
        }
        #fb-enhancer-menu {
            position: fixed;
            top: 100px;
            right: 10px;
            background: #fff;
            color: #000;
            font-size: 14px;
            padding: 10px;
            border: 1px solid #ccc;
            z-index: 99998;
            width: 240px;
            max-height: 80vh;
            overflow-y: auto;
            border-radius: 6px;
            box-shadow: 0 0 5px rgba(0,0,0,0.5);
            font-family: sans-serif;
            display: none;
        }
        #fb-enhancer-menu h4 {
            margin-top: 0;
            margin-bottom: 8px;
            font-size: 15px;
        }
        #fb-enhancer-menu label {
            display: block;
            margin-bottom: 4px;
        }
        #fb-enhancer-menu button {
            margin-top: 10px;
            margin-right: 5px;
            font-size: 13px;
        }
        .fb-dark-mode {
            filter: invert(1) hue-rotate(180deg);
        }
        .fb-dark-mode img {
            filter: invert(1) hue-rotate(180deg);
        }
        .classic-blue-theme {
            background-color: #e9ebee !important;
            color: #1c1e21 !important;
        }
        @media (max-width: 768px) {
            #fb-enhancer-toggle {
                top: auto;
                bottom: 20px;
                right: 20px;
                font-size: 16px;
                padding: 10px;
            }
            #fb-enhancer-menu {
                top: auto;
                bottom: 70px;
                right: 10px;
            }
        }
    `);

    function createToggleButton() {
        const toggle = document.createElement('div');
        toggle.id = 'fb-enhancer-toggle';
        toggle.textContent = '⚙ FB Enhancer';
        toggle.addEventListener('click', () => {
            const panel = document.getElementById('fb-enhancer-menu');
            menuVisible = !menuVisible;
            panel.style.display = menuVisible ? 'block' : 'none';
        });
        document.body.appendChild(toggle);
    }

    function createSettingsMenu() {
        const menu = document.createElement('div');
        menu.id = 'fb-enhancer-menu';
        menu.innerHTML = `<h4>Facebook Enhancer Settings</h4>
            ${Object.keys(settings).map(key => `
                <label>
                    <input type="checkbox" id="toggle-${key}" ${settings[key] ? 'checked' : ''}> ${key}
                </label>
            `).join('')}
            <button id="btn-save-settings">Save to File</button>
            <button id="btn-load-settings">Load from File</button>
        `;
        document.body.appendChild(menu);

        Object.keys(settings).forEach(key => {
            const checkbox = document.getElementById(`toggle-${key}`);
            checkbox.addEventListener('change', () => {
                settings[key] = checkbox.checked;
                saveSettings();
                location.reload();
            });
        });

        document.getElementById('btn-save-settings').addEventListener('click', downloadSettings);
        document.getElementById('btn-load-settings').addEventListener('click', uploadSettings);
    }

    function stopVisibleVideoAutoplay() {
        const observer = new IntersectionObserver((entries) => {
            for (const entry of entries) {
                const video = entry.target;

                // Exclude Reels, Modals, and Short Player elements
                if (
                    video.closest('[role="dialog"]') ||
                    video.closest('[data-pagelet^="VideoHome"]') ||
                    video.closest('[aria-label*="Reels"]') ||
                    video.closest('[class*="reel"]')
                ) {
                    continue;
                }

                if (entry.isIntersecting && !video.paused) {
                    video.pause();
                    video.removeAttribute('autoplay');
                    if (settings.muteVideos) video.muted = true;
                }
            }
        }, { threshold: 0.5 });

        document.querySelectorAll('video').forEach(video => {
            if (
                video.closest('[role="dialog"]') ||
                video.closest('[data-pagelet^="VideoHome"]') ||
                video.closest('[aria-label*="Reels"]') ||
                video.closest('[class*="reel"]')
            ) {
                return;
            }

            observer.observe(video);
            video.removeAttribute('autoplay');
            if (settings.muteVideos) video.muted = true;
            video.pause();
        });
    }

    function runEnhancements() {
        const posts = document.querySelectorAll('[role="feed"] [role="article"]');
        posts.forEach(post => {
            if (settings.blockSponsored && /Sponsored/i.test(post.innerText)) post.remove();
            if (settings.blockSuggested && /Suggested for you/i.test(post.innerText)) post.remove();
            if (settings.autoExpandComments) {
                post.querySelectorAll('[role="button"]').forEach(btn => {
                    if (btn.innerText.includes('View more comments') || btn.innerText.includes('replies')) {
                        btn.click();
                    }
                });
            }
        });

        if (settings.hidePeopleYouMayKnow) {
            document.querySelectorAll('div, section, aside').forEach(el => {
                const text = el.querySelector('strong, span, h3, h2')?.textContent?.trim();
                const hasFriendButtons = el.querySelector('button')?.textContent?.toLowerCase().includes('add friend');
                if (text && text.match(/^People you may know$/i) && hasFriendButtons) {
                    if (settings.debugMode) {
                        console.log('[FB Enhancer] Would remove:', el);
                    } else {
                        el.remove();
                    }
                }
            });
        }

        if (settings.removeBubbles) {
            document.querySelectorAll('span').forEach(el => {
                if (/^\d+$/.test(el.textContent) && el.closest('[aria-label]')) el.textContent = '';
            });
        }

        if (settings.unwrapLinks) {
            document.querySelectorAll('a[href*="l.facebook.com/l.php"]').forEach(link => {
                const url = new URL(link.href);
                const real = decodeURIComponent(url.searchParams.get('u') || '');
                if (real.startsWith('http')) link.href = real;
            });
        }

        if (settings.disableAutoplay) stopVisibleVideoAutoplay();

        if (settings.autoClosePopups) {
            document.querySelectorAll('[role="dialog"]').forEach(d => {
                const text = d.innerText.toLowerCase();
                if (text.includes('log in') || text.includes('feedback') || text.includes('report')) d.remove();
            });
        }

        if (settings.forceMostRecentFeed) {
            const feedSwitch = document.querySelector('a[href*="sk=h_chr"]');
            if (feedSwitch) feedSwitch.click();
        }

        if (settings.classicBlueTheme) document.body.classList.add('classic-blue-theme');

        if (settings.moveMessengerDock) {
            const dock = document.querySelector('[aria-label="Chat tab bar"]');
            if (dock) {
                dock.style.bottom = '0';
                dock.style.top = 'auto';
            }
        }

        document.documentElement.classList.toggle('fb-dark-mode', settings.forceDarkMode);
    }

    function init() {
        loadSettings();
        createToggleButton();
        createSettingsMenu();
        setInterval(runEnhancements, 2500);
        window.addEventListener('load', runEnhancements);
    }

    init();
})();