Facebook Enhancer v3.1

Optimized Facebook enhancer with no freezing, better performance, localStorage settings, and full UI customization menu. Removes ads, reels, people suggestions, and more.

// ==UserScript==
// @name         Facebook Enhancer v3.1
// @namespace    https://github.com/TamperMonkeyDevelopment/TamperMonkeyScripts
// @version      3.1
// @description  Optimized Facebook enhancer with no freezing, better performance, localStorage settings, and full UI customization menu. Removes ads, reels, people suggestions, and more.
// @author       Eliminater74
// @match        *://www.facebook.com/*
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const storageKey = 'fb-enhancer-settings';
    const defaultSettings = {
        blockSponsored: true,
        blockSuggested: true,
        disableAutoplay: true,
        muteVideos: true,
        hideReels: true,
        autoExpandComments: true,
        hidePeopleYouMayKnow: true,
        unwrapLinks: true,
        keywordFilter: 'kardashian,tiktok,reaction',
        forceMostRecentFeed: true,
        forceDarkMode: false,
        customCSS: '',
        debugMode: false
    };

    let settings = loadSettings();

    function loadSettings() {
        try {
            const saved = JSON.parse(localStorage.getItem(storageKey));
            return Object.assign({}, defaultSettings, saved || {});
        } catch {
            return { ...defaultSettings };
        }
    }

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

    function applyCustomCSS() {
        const id = 'fb-enhancer-custom-style';
        document.getElementById(id)?.remove();
        if (settings.customCSS) {
            const style = document.createElement('style');
            style.id = id;
            style.textContent = settings.customCSS;
            document.head.appendChild(style);
        }
    }

    function createMenu() {
        const btn = document.createElement('div');
        btn.textContent = '⚙ Enhancer';
        btn.style.cssText = 'position:fixed;top:60px;right:10px;background:#4267B2;color:#fff;padding:5px 10px;border-radius:5px;z-index:99999;cursor:pointer;font-weight:bold;';
        btn.id = 'fb-enhancer-toggle';

        const panel = document.createElement('div');
        panel.id = 'fb-enhancer-panel';
        panel.style.cssText = 'position:fixed;top:100px;right:10px;z-index:99999;background:#fff;padding:10px;width:280px;max-height:70vh;overflow:auto;border:1px solid #ccc;border-radius:6px;font-size:14px;display:none;';

        const html = ['<h3>Facebook Enhancer</h3>'];
        for (let key in settings) {
            const value = settings[key];
            if (typeof value === 'boolean') {
                html.push(`<label><input type="checkbox" id="${key}" ${value ? 'checked' : ''}/> ${key}</label>`);
            } else {
                html.push(`<label>${key}<input type="text" id="${key}" value="${value}" style="width:100%"/></label>`);
            }
        }
        html.push('<button id="fb-save">Save</button><button id="fb-reset">Reset</button>');
        panel.innerHTML = html.join('<br>');

        btn.onclick = () => {
            panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
        };

        document.body.appendChild(btn);
        document.body.appendChild(panel);
        makeDraggable(btn);
        makeDraggable(panel);

        document.getElementById('fb-save').onclick = () => {
            for (let key in settings) {
                const input = document.getElementById(key);
                if (!input) continue;
                settings[key] = input.type === 'checkbox' ? input.checked : input.value.trim();
            }
            saveSettings();
            alert('Saved. Reloading...');
            location.reload();
        };

        document.getElementById('fb-reset').onclick = () => {
            localStorage.removeItem(storageKey);
            alert('Reset. Reloading...');
            location.reload();
        };
    }

    function makeDraggable(el) {
        let offsetX = 0, offsetY = 0, isDragging = false;

        el.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - el.getBoundingClientRect().left;
            offsetY = e.clientY - el.getBoundingClientRect().top;
        });

        document.addEventListener('mousemove', (e) => {
            if (isDragging) {
                el.style.left = `${e.clientX - offsetX}px`;
                el.style.top = `${e.clientY - offsetY}px`;
                el.style.right = 'auto';
                el.style.bottom = 'auto';
            }
        });

        document.addEventListener('mouseup', () => isDragging = false);
    }

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

    function muteAndPauseVisibleVideos() {
        const observer = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                const video = entry.target;
                if (entry.isIntersecting && !video.dataset.fbEnhanced) {
                    video.removeAttribute('autoplay');
                    if (settings.muteVideos) video.muted = true;
                    if (settings.disableAutoplay && !video.paused) video.pause();
                    video.dataset.fbEnhanced = 'true';
                    if (settings.debugMode) console.log('[FB Enhancer] Muted & paused video.');
                }
            });
        }, { threshold: 0.5 });

        document.querySelectorAll('video:not([data-fb-enhanced])').forEach(video => {
            observer.observe(video);
        });
    }

    function autoExpandComments(post) {
        post.querySelectorAll('div[role="button"]').forEach(btn => {
            const text = btn.textContent;
            if (/view (more )?comments|replies/i.test(text)) {
                btn.click();
            }
        });
    }

    function runEnhancer(post) {
        try {
            const text = post.innerText.toLowerCase();
            if (settings.blockSponsored && /sponsored/i.test(text)) return post.remove();
            if (settings.blockSuggested && /suggested for you/i.test(text)) return post.remove();
            if (settings.keywordFilter && settings.keywordFilter.split(',').some(k => text.includes(k.trim()))) return post.remove();
            if (settings.autoExpandComments) autoExpandComments(post);
        } catch (e) {
            if (settings.debugMode) console.warn('Enhancer error:', e);
        }
    }

    function observeFeed() {
        const observer = new MutationObserver(mutations => {
            mutations.forEach(m => {
                m.addedNodes.forEach(node => {
                    if (node.nodeType === 1 && node.getAttribute('role') === 'article') {
                        runEnhancer(node);
                    }
                });
            });
        });

        const feed = document.querySelector('[role="feed"]');
        if (feed) observer.observe(feed, { childList: true, subtree: true });

        document.querySelectorAll('[role="article"]').forEach(runEnhancer);
    }

    function hideReels() {
        document.querySelectorAll('a[href*="/reels/"], [aria-label*="Reels"], [class*="reel"]').forEach(el => el.remove());
    }

    function hideSuggestions() {
        document.querySelectorAll('[role="complementary"], section, aside').forEach(el => {
            const text = el.innerText?.toLowerCase();
            if (text?.includes('people you may know')) el.remove();
        });
    }

    function hidePeopleYouMayKnowCards() {
        document.querySelectorAll('div[role="dialog"], div[role="region"], div').forEach(card => {
            const text = card.innerText?.trim().toLowerCase();
            if (text?.startsWith("people you may know") &&
                card.querySelectorAll('button').length >= 2 &&
                [...card.querySelectorAll('button')].some(btn => btn.innerText.toLowerCase().includes('add friend'))) {
                card.remove();
            }
        });
    }

    function forceMostRecent() {
        const link = document.querySelector('a[href*="sk=h_chr"]');
        if (link) link.click();
    }

    function applyEnhancements() {
        if (settings.unwrapLinks) unwrapLinks();
        if (settings.hideReels) hideReels();
        if (settings.hidePeopleYouMayKnow) {
            hideSuggestions();
            hidePeopleYouMayKnowCards();
        }
        if (settings.forceMostRecentFeed) forceMostRecent();
        if (settings.forceDarkMode) document.documentElement.classList.add('fb-dark-mode');
        muteAndPauseVisibleVideos();
    }

    // === INIT ===
    applyCustomCSS();
    createMenu();
    applyEnhancements();
    observeFeed();
})();