Facebook Cleaner

Remove unnecessary and rarely used feature buttons and elements from Facebook to make the entire page look cleaner and more streamlined.

// ==UserScript==
// @name         Facebook Cleaner 
// @name:zh-TW   Facebook 清爽化
// @name:zh-CN   Facebook 清爽化
// @namespace    http://tampermonkey.net/
// @version      3.7
// @description  Remove unnecessary and rarely used feature buttons and elements from Facebook to make the entire page look cleaner and more streamlined.
// @description:zh-TW 刪除FaceBook多餘、不常使用的功能按鈕和要素,使整個頁面看起來更加簡潔
// @description:zh-CN 删除FaceBook多余、不常使用的功能按钮和要素,使整个页面看起来更加简洁
// @author       chatgpt
// @match        https://www.facebook.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 左側功能列關鍵字(中英文)
    const leftKeywords = [
        // 中文
        '動態回顧', '我的珍藏', 'Marketplace', '兒童版 Messenger', '玩遊戲',
        '近期廣告動態', '訂單和付款', '氣候科學中心', '募款活動', '廣告管理員', 'Meta Quest 3S',
        // 英文
        'Memories', 'Saved', 'Marketplace', 'Messenger Kids', 'Gaming', 'Play games',
        'Recent ad activity', 'Orders and payments', 'Climate Science Center',
        'Fundraisers', 'Ads Manager', 'Meta Quest 3S'
    ];
    // 「顯示更多」按鈕關鍵字(中英文)
    const moreKeywords = [
        '顯示更多', '更多', 'See more', 'More', 'Show more', 'See More', 'MORE', 'SHOW MORE'
    ];
    // 「顯示較少」按鈕關鍵字(中英文)
    const lessKeywords = [
        '顯示較少', 'Show less', 'Show Less', 'Less', 'LESS'
    ];

    // 只在主頁(有左側主選單的頁面)才執行展開與隱藏
    function isMainSidebarPage() {
        // 檢查是否有主選單的 nav
        return !!document.querySelector('nav[role="navigation"], [role=navigation]');
    }

    // 隱藏左側功能列指定按鈕
    function hideLeftSidebarByText() {
        document.querySelectorAll('nav a[role="link"], [role=navigation] a[role="link"]').forEach(a => {
            let match = false;
            a.querySelectorAll('span.x1lliihq').forEach(span => {
                if (
                    span.textContent &&
                    leftKeywords.includes(span.textContent.trim()) &&
                    span.children.length === 0
                ) {
                    match = true;
                }
            });
            if (match) {
                a.style.display = 'none';
            }
        });
    }

    // 隱藏右側欄指定區塊
    function hideRightSidebarByTitle() {
        const rightKeywords = ['贊助', '聯絡人', '群組聊天室', 'Sponsored', 'Contacts', 'Group conversations'];
        document.querySelectorAll('h3').forEach(h3 => {
            if (h3.textContent && rightKeywords.some(kw => h3.textContent.includes(kw))) {
                let parent = h3;
                // 向上找 6 層父元素,隱藏整個區塊
                for (let i = 0; i < 6; i++) {
                    if (parent.parentElement) parent = parent.parentElement;
                }
                if (parent && parent.offsetWidth > 200) {
                    parent.style.display = 'none';
                }
            }
        });
    }

    // 隱藏 Marketplace 按鈕(只移除 li)
    function removeMarketplaceButton() {
        document.querySelectorAll('a[aria-label="Marketplace"], a[href="/marketplace/?ref=app_tab"], a[href="/marketplace/"]').forEach(a => {
            let li = a;
            for (let i = 0; i < 5; i++) {
                if (li.parentElement && li.parentElement.tagName === 'LI') {
                    li = li.parentElement;
                    break;
                }
                if (li.parentElement) li = li.parentElement;
            }
            if (li.tagName === 'LI') {
                li.remove();
            }
        });
    }

    // 隱藏政策條款等連結
    function hidePolicyLinks() {
        const policyKeywords = [
            '隱私政策', '服務條款', '廣告', 'Ad Choices', 'Cookie', 'Meta © 2025',
            'Privacy Policy', 'Terms', 'Ad Choices', 'Cookie', 'Meta © 2025'
        ];
        document.querySelectorAll('footer, div[role="contentinfo"]').forEach(container => {
            policyKeywords.forEach(kw => {
                if (container.textContent.includes(kw)) {
                    container.style.display = 'none';
                }
            });
        });
    }

    // 其他要隱藏的精準選擇器
    const selectors = [
        'footer',
        'div[role="contentinfo"]',
        'div[aria-label="Facebook"] > div:last-child'
    ];

    // 移除「顯示更多」「顯示較少」等按鈕
    function removeMoreAndLessButtons() {
        document.querySelectorAll('[role="button"]').forEach(btn => {
            if (btn) {
                const spans = btn.querySelectorAll('span');
                for (const span of spans) {
                    const text = span.textContent.trim().toLowerCase();
                    if (moreKeywords.some(kw => text === kw.toLowerCase() || text.includes(kw.toLowerCase()))) {
                        btn.style.display = 'none';
                        break;
                    }
                }
            }
        });
        document.querySelectorAll('[role="button"]').forEach(btn => {
            if (btn) {
                const spans = btn.querySelectorAll('span');
                for (const span of spans) {
                    const text = span.textContent.trim().toLowerCase();
                    if (lessKeywords.some(kw => text === kw.toLowerCase() || text.includes(kw.toLowerCase()))) {
                        btn.style.display = 'none';
                        break;
                    }
                }
            }
        });
    }

    // 展開流程相關變數
    let expandTries = 0;
    const maxExpandTries = 60; // 最多嘗試 60 次(約 30 秒)
    let expandDone = false;
    let expandInterval = null;
    let observer = null;
    let debounceTimer = null;

    // 嘗試展開左側欄(每次呼叫只嘗試一次)
    function tryExpandOnce() {
        if (expandDone) return;
        // 只在主頁有主選單時才執行
        if (!isMainSidebarPage()) return;
        let found = false;
        const btns = Array.from(document.querySelectorAll('nav[role="navigation"] [role="button"], [role=navigation] [role="button"]'));
        for (const btn of btns) {
            if (btn.offsetParent === null) continue;
            const spans = btn.querySelectorAll('span');
            for (const span of spans) {
                const text = span.textContent.trim().toLowerCase();
                if (moreKeywords.some(kw => text === kw.toLowerCase() || text.includes(kw.toLowerCase()))) {
                    btn.click();
                    found = true;
                    setTimeout(removeMoreAndLessButtons, 800);
                    break;
                }
            }
            if (found) break;
        }
        // 判斷是否已經展開(按鈕消失)
        const stillHasMore = Array.from(document.querySelectorAll('nav[role="navigation"] [role="button"], [role=navigation] [role="button"]')).some(btn => {
            const spans = btn.querySelectorAll('span');
            return Array.from(spans).some(span => {
                const text = span.textContent.trim().toLowerCase();
                return moreKeywords.some(kw => text === kw.toLowerCase() || text.includes(kw.toLowerCase()));
            });
        });
        if (!stillHasMore && found) {
            expandDone = true;
            setTimeout(removeMoreAndLessButtons, 1000);
            // 展開完成後,關閉 MutationObserver
            if (observer) observer.disconnect();
            // 關閉 setInterval
            if (expandInterval) clearInterval(expandInterval);
        }
    }

    // 啟動展開輪詢
    function startExpandLoop() {
        expandTries = 0;
        expandDone = false;
        if (expandInterval) clearInterval(expandInterval);
        expandInterval = setInterval(() => {
            if (expandDone || expandTries >= maxExpandTries) {
                clearInterval(expandInterval);
                return;
            }
            expandTries++;
            tryExpandOnce();
        }, 500);
    }

    // 隱藏其他元素
    function hideOtherElements() {
        selectors.forEach(selector => {
            document.querySelectorAll(selector).forEach(el => {
                el.style.display = 'none';
            });
        });
        hideLeftSidebarByText();
        hideRightSidebarByTitle();
        removeMarketplaceButton();
        hidePolicyLinks();
    }

    // 頁面載入後啟動展開輪詢
    window.addEventListener('load', () => {
        if (isMainSidebarPage()) {
            startExpandLoop();
        }
    });

    // 防抖函數,避免高頻率觸發
    function debounceHideAndExpand() {
        if (debounceTimer) clearTimeout(debounceTimer);
        debounceTimer = setTimeout(() => {
            hideOtherElements();
            if (isMainSidebarPage() && !expandDone) tryExpandOnce();
        }, 300);
    }

    // MutationObserver 監控所有 DOM 變動,任何時候都再嘗試展開(防抖)
    observer = new MutationObserver(debounceHideAndExpand);
    observer.observe(document.body, { childList: true, subtree: true });

    // 首次執行(不移除「顯示更多」按鈕)
    hideOtherElements();
})();