Greasy Fork

Greasy Fork is available in English.

Facebook Activity Auto Deleter (2025) - Optimized

Fast and efficient Facebook activity log cleaner with improved item detection and progressive skipping.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Facebook Activity Auto Deleter (2025) - Optimized
// @namespace    http://greasyfork.icu/en/users/1454546-shawnfrost13
// @version      5.03
// @description  Fast and efficient Facebook activity log cleaner with improved item detection and progressive skipping.
// @author       shawnfrost13 (optimized by Claude)
// @license      MIT
// @match        https://www.facebook.com/*/allactivity*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    // ===== CONFIGURATION =====
    const CONFIG = {
        // Delays (in ms)
        menuClickDelay: 300,      // Time to wait after clicking menu button
        deleteClickDelay: 300,    // Time to wait after clicking delete option
        betweenItemsDelay: 800,   // Random base delay between deletion attempts
        randomDelayMax: 400,      // Additional random delay to avoid detection
        errorCheckDelay: 800,     // How long to wait to check for errors (increased)
        scrollDelay: 1500,        // How long to wait after scrolling
        
        // UI
        uiUpdateInterval: 500,    // How often to update stats display
        
        // Error handling
        maxRetries: 3,            // Maximum retries before skipping item permanently (increased)
        skipIncrement: 1,         // How many items to skip when encountering problems (NEW)
        maxSkipAhead: 5,          // Maximum items to skip ahead at once (NEW)
        
        errorTexts: [             // Text patterns that indicate errors
            "Something went wrong",
            "Please try again",
            "An error occurred",
            "We couldn't process",
            "Action blocked",
            "You're temporarily restricted" // Added this common error
        ],
        
        // Progressive operation (NEW)
        resetSkipCountAfterSuccess: 3, // Reset skip counter after this many successful operations
    };

    // ===== STATE =====
    const STATE = {
        isRunning: false,
        deletionCount: 0,
        skipCount: 0,
        currentItem: null,
        problemItems: new Map(),  // Map of signatures to retry counts
        lastActionTime: 0,        // For monitoring performance
        processingTime: [],       // Track how long each deletion takes
        
        // Progressive operation (NEW)
        consecutiveSuccesses: 0,  // Count consecutive successful deletions
        currentSkipAhead: 1,      // How many items to skip if problems persist
        lastSuccessTimestamp: 0,  // When was the last successful deletion
    };

    // ===== DOM ELEMENT REFERENCES =====
    const DOM = {
        statusDisplay: null,
        statsDisplay: null,
        toggleButton: null,
        resetButton: null,
        speedSlider: null
    };

    // ===== UTILITY FUNCTIONS =====
    function log(message, type = 'info') {
        const prefix = {
            'info': '📋',
            'success': '✅',
            'error': '❌',
            'warn': '⚠️',
            'skip': '⏭️',
            'scroll': '🔄'
        }[type] || '🔹';
        
        console.log(`${prefix} ${message}`);
    }

    function getRandomDelay() {
        return CONFIG.betweenItemsDelay + Math.floor(Math.random() * CONFIG.randomDelayMax);
    }

    function updateStatus(text, type = 'normal') {
        if (!DOM.statusDisplay) return;
        
        // Set color based on type
        const colors = {
            'normal': 'lime',
            'error': '#ff5555',
            'warning': '#ffaa00',
            'success': '#55ff55'
        };
        
        DOM.statusDisplay.textContent = text;
        DOM.statusDisplay.style.color = colors[type] || colors.normal;
    }

    function updateStats() {
        if (!DOM.statsDisplay) return;
        
        // Calculate average processing time
        let avgTime = 0;
        if (STATE.processingTime.length > 0) {
            avgTime = STATE.processingTime.reduce((sum, time) => sum + time, 0) / STATE.processingTime.length;
        }
        
        DOM.statsDisplay.innerHTML = `
            <div style="font-weight:bold;margin-bottom:5px;border-bottom:1px solid #444;padding-bottom:3px;">FB CLEANER STATS</div>
            <div>Deleted: <span style="color:#55ff55">${STATE.deletionCount}</span></div>
            <div>Skipped: <span style="color:#ffaa00">${STATE.skipCount}</span></div>
            <div>Skip Ahead: <span style="color:#55aaff">${STATE.currentSkipAhead}</span></div>
            <div>Avg Time: <span style="color:#55aaff">${Math.round(avgTime)}ms</span></div>
        `;
    }

    // ===== UI CREATION =====
    function createUI() {
        const css = `
            .fb-cleaner-ui {
                position: fixed;
                bottom: 20px;
                right: 20px;
                background: rgba(10, 10, 10, 0.85);
                border: 1px solid #444;
                border-radius: 10px;
                color: white;
                font-family: 'Segoe UI', Tahoma, Geneva, sans-serif;
                z-index: 999999;
                backdrop-filter: blur(5px);
                box-shadow: 0 4px 12px rgba(0,0,0,0.2);
                overflow: hidden;
                transition: all 0.3s ease;
                width: 180px;
            }
            
            .fb-cleaner-header {
                background: #222;
                padding: 8px 12px;
                font-weight: bold;
                border-bottom: 1px solid #444;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            
            .fb-cleaner-title {
                font-size: 14px;
                color: #fff;
            }
            
            .fb-cleaner-version {
                font-size: 10px;
                color: #aaa;
                background: #333;
                padding: 2px 6px;
                border-radius: 10px;
            }
            
            .fb-cleaner-body {
                padding: 10px;
            }
            
            .fb-cleaner-status {
                margin-bottom: 10px;
                padding: 5px;
                background: rgba(0,0,0,0.2);
                border-radius: 5px;
                font-size: 13px;
                color: lime;
                min-height: 20px;
            }
            
            .fb-cleaner-stats {
                font-size: 12px;
                margin: 10px 0;
                line-height: 1.5;
            }
            
            .fb-cleaner-button {
                padding: 8px;
                border: none;
                border-radius: 5px;
                cursor: pointer;
                font-weight: bold;
                font-size: 12px;
                transition: all 0.2s;
                width: 100%;
                margin-bottom: 8px;
            }
            
            .fb-cleaner-button:hover {
                transform: translateY(-2px);
                box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            }
            
            .fb-cleaner-button.start {
                background: #4CAF50;
                color: white;
            }
            
            .fb-cleaner-button.pause {
                background: #FF9800;
                color: black;
            }
            
            .fb-cleaner-button.reset {
                background: #f44336;
                color: white;
            }
            
            .fb-cleaner-speed {
                margin-top: 5px;
                display: flex;
                flex-direction: column;
                font-size: 12px;
            }
            
            .fb-cleaner-speed-label {
                display: flex;
                justify-content: space-between;
                margin-bottom: 5px;
            }
            
            .fb-cleaner-slider {
                width: 100%;
                cursor: pointer;
            }
        `;
        
        // Add CSS
        const styleEl = document.createElement('style');
        styleEl.textContent = css;
        document.head.appendChild(styleEl);
        
        // Create main container
        const container = document.createElement('div');
        container.className = 'fb-cleaner-ui';
        
        // Create header
        const header = document.createElement('div');
        header.className = 'fb-cleaner-header';
        
        const title = document.createElement('div');
        title.className = 'fb-cleaner-title';
        title.textContent = 'FB Cleaner';
        
        const version = document.createElement('div');
        version.className = 'fb-cleaner-version';
        version.textContent = 'v5.03';
        
        header.appendChild(title);
        header.appendChild(version);
        
        // Create body
        const body = document.createElement('div');
        body.className = 'fb-cleaner-body';
        
        // Status display
        const status = document.createElement('div');
        status.className = 'fb-cleaner-status';
        status.textContent = 'Ready to start';
        DOM.statusDisplay = status;
        
        // Stats display
        const stats = document.createElement('div');
        stats.className = 'fb-cleaner-stats';
        DOM.statsDisplay = stats;
        
        // Toggle button
        const toggleBtn = document.createElement('button');
        toggleBtn.className = 'fb-cleaner-button start';
        toggleBtn.textContent = '▶️ Start Cleaning';
        toggleBtn.addEventListener('click', toggleRunning);
        DOM.toggleButton = toggleBtn;
        
        // Reset button
        const resetBtn = document.createElement('button');
        resetBtn.className = 'fb-cleaner-button reset';
        resetBtn.textContent = '🔄 Reset Skip List';
        resetBtn.addEventListener('click', () => {
            STATE.problemItems.clear();
            STATE.skipCount = 0;
            STATE.currentSkipAhead = 1;
            updateStatus('Skip list cleared', 'success');
            updateStats();
        });
        DOM.resetButton = resetBtn;
        
        // Speed control
        const speedControl = document.createElement('div');
        speedControl.className = 'fb-cleaner-speed';
        
        const speedLabel = document.createElement('div');
        speedLabel.className = 'fb-cleaner-speed-label';
        
        const speedText = document.createElement('span');
        speedText.textContent = 'Speed:';
        
        const speedValue = document.createElement('span');
        speedValue.textContent = 'Normal';
        
        speedLabel.appendChild(speedText);
        speedLabel.appendChild(speedValue);
        
        const speedSlider = document.createElement('input');
        speedSlider.type = 'range';
        speedSlider.min = '1';
        speedSlider.max = '3';
        speedSlider.value = '2';
        speedSlider.className = 'fb-cleaner-slider';
        
        speedSlider.addEventListener('input', () => {
            const value = parseInt(speedSlider.value);
            const labels = ['Careful', 'Normal', 'Speedy'];
            speedValue.textContent = labels[value - 1];
            
            // Adjust delays based on speed setting
            const multiplier = value === 1 ? 1.5 : value === 2 ? 1 : 0.6;
            CONFIG.menuClickDelay = 300 * multiplier;
            CONFIG.deleteClickDelay = 300 * multiplier;
            CONFIG.betweenItemsDelay = 800 * multiplier;
            CONFIG.errorCheckDelay = 600 * multiplier;
        });
        
        DOM.speedSlider = speedSlider;
        
        speedControl.appendChild(speedLabel);
        speedControl.appendChild(speedSlider);
        
        // Assemble UI
        body.appendChild(status);
        body.appendChild(stats);
        body.appendChild(toggleBtn);
        body.appendChild(resetBtn);
        body.appendChild(speedControl);
        
        container.appendChild(header);
        container.appendChild(body);
        document.body.appendChild(container);
        
        // Initialize stats display
        updateStats();
        
        // Make the UI draggable (simple implementation)
        let isDragging = false;
        let offsetX, offsetY;
        
        header.addEventListener('mousedown', (e) => {
            isDragging = true;
            offsetX = e.clientX - container.getBoundingClientRect().left;
            offsetY = e.clientY - container.getBoundingClientRect().top;
        });
        
        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            
            container.style.left = (e.clientX - offsetX) + 'px';
            container.style.top = (e.clientY - offsetY) + 'px';
            container.style.right = 'auto';
            container.style.bottom = 'auto';
        });
        
        document.addEventListener('mouseup', () => {
            isDragging = false;
        });
    }

    // ===== CORE FUNCTIONALITY =====
    function toggleRunning() {
        STATE.isRunning = !STATE.isRunning;
        
        if (STATE.isRunning) {
            DOM.toggleButton.textContent = '⏸️ Pause Cleaning';
            DOM.toggleButton.className = 'fb-cleaner-button pause';
            updateStatus('Running...', 'normal');
            deleteNext();
        } else {
            DOM.toggleButton.textContent = '▶️ Start Cleaning';
            DOM.toggleButton.className = 'fb-cleaner-button start';
            updateStatus('Paused', 'warning');
        }
    }

    // IMPROVED: More reliable item signature generation
    function getItemSignature(element) {
        if (!element) return null;
        
        // Find the containing item - search wider for containers
        let container = element.closest('[data-visualcompletion="ignore-dynamic"]') || 
                       element.closest('div[role="article"]') ||
                       element.closest('div[data-pagelet*="Feed"]') ||
                       element.closest('[data-testid]') ||  // Added support for more Facebook selectors
                       element.parentElement?.parentElement?.parentElement;
        
        if (!container) {
            container = element.parentElement;
            if (!container) return null;
        }
        
        // Get text content - use less text for the signature to reduce false uniqueness
        let textContent = '';
        try {
            // Try to get first 30 chars of cleaned text content (was 50 before)
            textContent = container.innerText.replace(/\s+/g, ' ').trim().substring(0, 30);
        } catch (e) {
            // Fallback if innerText fails
            textContent = (container.textContent || '').replace(/\s+/g, ' ').trim().substring(0, 30);
        }
        
        // Look for timestamps but don't make them a critical part of the signature
        const timestamp = container.querySelector('abbr[data-utime]');
        const timeValue = timestamp ? timestamp.getAttribute('data-utime').slice(-5) : ''; // Only use last 5 digits
        
        // Use rough position info 
        const rect = container.getBoundingClientRect();
        const posInfo = `${Math.round(rect.width/10)*10}`; // Round to nearest 10px for less sensitivity
        
        return `${textContent}:${posInfo}:${timeValue}`;
    }

    // IMPROVED: Better menu button detection
    function findMenuButtons() {
        // Start with standard buttons
        const standardButtons = Array.from(document.querySelectorAll('[role="button"]')).filter(btn => {
            const label = btn.getAttribute('aria-label') || '';
            return (
                btn.offsetParent !== null &&
                (label.toLowerCase().includes("activity options") ||
                 label.toLowerCase().includes("action options") ||
                 label.toLowerCase().includes("more options") ||  // Added more option keywords
                 label.toLowerCase().includes("menu"))
            );
        });
        
        // If we found standard buttons, return them
        if (standardButtons.length > 0) return standardButtons;
        
        // Fallback to visual detection
        return Array.from(document.querySelectorAll('*')).filter(el => {
            if (!el.offsetParent) return false; // Must be visible
            
            // Look for elements that resemble menu buttons
            const rect = el.getBoundingClientRect();
            const isSquarish = Math.abs(rect.width - rect.height) < 5;
            const isReasonableSize = rect.width >= 20 && rect.width <= 40;
            
            // Check if it's in a reasonable place in the document
            const isInViewport = rect.top >= 0 && rect.top <= window.innerHeight;
            
            // Has some content that might indicate a button
            const hasIconContent = el.innerHTML.includes('svg') || 
                                  el.innerHTML.includes('img') || 
                                  el.textContent.includes('...') ||
                                  el.textContent.includes('⋮');
            
            return isSquarish && isReasonableSize && isInViewport && hasIconContent;
        });
    }

    function checkForErrorPopups() {
        // Check for any error popups or notifications
        for (const errorText of CONFIG.errorTexts) {
            const containsError = Array.from(document.querySelectorAll('body *')).some(
                el => el.offsetParent !== null && // is visible
                      el.innerText && 
                      el.innerText.includes(errorText)
            );
            
            if (containsError) return true;
        }
        
        // Additional check for specific Facebook error elements
        const errorElements = document.querySelectorAll('[role="alert"], [role="status"]');
        for (const el of errorElements) {
            if (el.offsetParent !== null && CONFIG.errorTexts.some(txt => el.innerText.includes(txt))) {
                return true;
            }
        }
        
        return false;
    }

    function closeAllErrorPopups() {
        // Find all close buttons in error popups
        const errorPopups = Array.from(document.querySelectorAll('[role="alert"], [role="dialog"], [role="status"]')).filter(
            popup => CONFIG.errorTexts.some(txt => popup.innerText && popup.innerText.includes(txt))
        );
        
        let closed = false;
        
        errorPopups.forEach(popup => {
            // Look for close buttons
            const closeBtn = popup.querySelector('[aria-label="Close"], [aria-label="Dismiss"], [aria-label="OK"]') || 
                           popup.querySelector('div[role="button"]') ||
                           popup.querySelector('button');
            
            if (closeBtn) {
                closeBtn.click();
                closed = true;
                log("Closed error popup", "info");
            }
        });
        
        return closed;
    }

    // IMPROVED: Smarter handling of problem items
    function markCurrentItemAsProblem() {
        if (!STATE.currentItem) return;
        
        const signature = getItemSignature(STATE.currentItem);
        if (!signature) return;
        
        // Get current count or default to 0
        const currentCount = STATE.problemItems.get(signature) || 0;
        STATE.problemItems.set(signature, currentCount + 1);
        
        // If this is a permanent skip, increment skip counter
        if (currentCount + 1 >= CONFIG.maxRetries) {
            STATE.skipCount++;
            log(`Permanently skipping item: "${signature.substring(0, 30)}..."`, "skip");
            
            // Increase the skip ahead count for progressive skipping
            STATE.currentSkipAhead = Math.min(
                STATE.currentSkipAhead + CONFIG.skipIncrement, 
                CONFIG.maxSkipAhead
            );
            
            // Reset consecutive successes
            STATE.consecutiveSuccesses = 0;
        } else {
            log(`Marking item for retry: "${signature.substring(0, 30)}..."`, "warn");
        }
    }

    function shouldSkipItem(btn) {
        const signature = getItemSignature(btn);
        if (!signature) return false;
        
        const failCount = STATE.problemItems.get(signature) || 0;
        return failCount >= CONFIG.maxRetries;
    }

    function autoConfirmPopups() {
        const dialogs = Array.from(document.querySelectorAll('[role="dialog"], [role="alertdialog"]'));
        
        dialogs.forEach(dialog => {
            // Find the delete button
            const deleteBtn = Array.from(dialog.querySelectorAll('div[role="button"], button'))
                .find(btn => 
                    btn.offsetParent !== null && 
                    (btn.innerText.trim().toLowerCase() === "delete" || 
                     btn.innerText.trim().toLowerCase() === "delete post" ||
                     btn.innerText.trim().toLowerCase() === "delete activity" ||  // Added variants
                     btn.innerText.trim().toLowerCase() === "remove" ||
                     btn.innerText.trim().toLowerCase() === "confirm" ||
                     btn.innerText.trim().toLowerCase() === "ok")
                );
            
            if (deleteBtn) {
                deleteBtn.click();
                log("Auto-confirmed deletion dialog", "success");
            }
        });
    }

    function autoScrollAndRetry() {
        log("Scrolling to load more content", "scroll");
        updateStatus("Scrolling to find more items...", "normal");
        
        // Scroll down
        window.scrollTo({
            top: document.body.scrollHeight,
            behavior: 'smooth'
        });
        
        // Wait and then try again
        setTimeout(deleteNext, CONFIG.scrollDelay);
    }

    function deleteNext() {
        if (!STATE.isRunning) return;
        
        const startTime = performance.now();
        STATE.lastActionTime = startTime;
        
        // Reset current item
        STATE.currentItem = null;
        
        // Clean up any dialogs and popups
        closeAllErrorPopups();
        autoConfirmPopups();
        
        // Find menu buttons
        const buttons = findMenuButtons();
        
        if (buttons.length === 0) {
            updateStatus("No items found, scrolling...", "warning");
            autoScrollAndRetry();
            return;
        }
        
        // Filter out buttons we should skip
        const validButtons = buttons.filter(btn => !shouldSkipItem(btn));
        
        if (validButtons.length === 0) {
            updateStatus("Only skippable items found, scrolling...", "warning");
            autoScrollAndRetry();
            return;
        }
        
        // NEW: Get a button based on the current skip-ahead setting
        let buttonIndex = 0;
        if (STATE.currentSkipAhead > 1 && validButtons.length >= STATE.currentSkipAhead) {
            buttonIndex = STATE.currentSkipAhead - 1; // -1 because array is 0-indexed
            log(`Skipping ahead ${STATE.currentSkipAhead} items due to previous errors`, "skip");
        }
        
        const btn = validButtons[buttonIndex];
        STATE.currentItem = btn;
        
        // Scroll to the button and click it
        btn.scrollIntoView({ block: "center", behavior: "instant" });
        
        setTimeout(() => {
            // Click the menu button
            btn.click();
            log(`Opened menu for item`, "info");
            updateStatus("Opened menu...", "normal");
            
            setTimeout(() => {
                // Find and click the delete option
                const menuItems = Array.from(document.querySelectorAll('[role="menuitem"], [role="button"]'));
                const deleteOption = menuItems.find(el =>
                    el.offsetParent !== null &&  // Must be visible
                    (
                        el.innerText.includes("Move to Recycle bin") ||
                        el.innerText.includes("Delete") ||
                        el.innerText.includes("Remove") ||
                        el.innerText.includes("Unlike") ||
                        el.innerText.includes("Remove reaction") ||
                        el.innerText.includes("Remove tag") ||
                        el.innerText.includes("Hide") ||  // Added more options
                        el.innerText.includes("Remove from profile")
                    )
                );
                
                if (deleteOption) {
                    deleteOption.click();
                    log(`Clicked delete option: "${deleteOption.innerText}"`, "info");
                    updateStatus("Deleting...", "normal");
                    
                    // Check for errors after a short delay
                    setTimeout(() => {
                        if (checkForErrorPopups()) {
                            // Error detected
                            log("Error detected during deletion", "error");
                            updateStatus("Error detected, skipping item", "error");
                            markCurrentItemAsProblem();
                            closeAllErrorPopups();
                            
                            // Record processing time
                            const endTime = performance.now();
                            STATE.processingTime.push(endTime - startTime);
                            
                            // Reset consecutive successes
                            STATE.consecutiveSuccesses = 0;
                            
                            // Move to next item
                            setTimeout(deleteNext, getRandomDelay());
                        } else {
                            // Success!
                            STATE.deletionCount++;
                            STATE.consecutiveSuccesses++;
                            STATE.lastSuccessTimestamp = Date.now();
                            
                            log(`Successfully deleted item #${STATE.deletionCount}`, "success");
                            updateStatus(`Deleted item #${STATE.deletionCount}`, "success");
                            
                            // NEW: Reduce skip-ahead after consecutive successes
                            if (STATE.consecutiveSuccesses >= CONFIG.resetSkipCountAfterSuccess && STATE.currentSkipAhead > 1) {
                                STATE.currentSkipAhead = Math.max(1, STATE.currentSkipAhead - 1);
                                log(`Reduced skip-ahead to ${STATE.currentSkipAhead} after ${STATE.consecutiveSuccesses} successes`, "info");
                                STATE.consecutiveSuccesses = 0; // Reset the counter
                            }
                            
                            // Record processing time
                            const endTime = performance.now();
                            STATE.processingTime.push(endTime - startTime);
                            
                            // Keep only the last 10 times for the average
                            if (STATE.processingTime.length > 10) {
                                STATE.processingTime.shift();
                            }
                            
                            // Move to next item
                            setTimeout(deleteNext, getRandomDelay());
                        }
                    }, CONFIG.errorCheckDelay);
                    
                } else {
                    // No delete option found - click elsewhere to close the menu
                    document.body.click();
                    
                    // Wait a bit and look for confirmation dialogs that might have appeared
                    setTimeout(() => {
                        autoConfirmPopups();
                        
                        // Still no success, mark as problem
                        log("No delete option found", "warn");
                        updateStatus("No delete option found, trying next", "warning");
                        markCurrentItemAsProblem();
                        
                        // Record processing time
                        const endTime = performance.now();
                        STATE.processingTime.push(endTime - startTime);
                        
                        // Move to next item
                        setTimeout(deleteNext, getRandomDelay());
                    }, 300);
                }
            }, CONFIG.menuClickDelay);
        }, 100); // Very short delay after scrolling
    }

    // ===== INITIALIZATION =====
    function initialize() {
        log("Facebook Activity Auto Deleter v5.03 loaded", "info");
        createUI();
        
        // Start periodic update of the UI
        setInterval(updateStats, CONFIG.uiUpdateInterval);
        
        // Set up periodic error popup checker
        setInterval(() => {
            if (STATE.isRunning) {
                closeAllErrorPopups();
                autoConfirmPopups();
            }
        }, 1000);
        
        // NEW: Add occasional complete page refresh to fix stuck states
        setInterval(() => {
            // If running and no successful deletion in 2 minutes, refresh
            if (STATE.isRunning && 
                STATE.lastSuccessTimestamp > 0 && 
                Date.now() - STATE.lastSuccessTimestamp > 120000) {
                
                log("No successful deletions for 2 minutes, refreshing page", "warn");
                updateStatus("Stuck detected, refreshing page...", "warning");
                
                // Save state data to sessionStorage
                sessionStorage.setItem('fbCleanerState', JSON.stringify({
                    deletionCount: STATE.deletionCount,
                    skipCount: STATE.skipCount,
                    problemItems: Array.from(STATE.problemItems.entries())
                }));
                
                // Reload page
                setTimeout(() => {
                    window.location.reload();
                }, 1000);
            }
        }, 30000); // Check every 30 seconds
        
        // Try to restore state from previous session
        try {
            const savedState = sessionStorage.getItem('fbCleanerState');
            if (savedState) {
                const parsedState = JSON.parse(savedState);
                STATE.deletionCount = parsedState.deletionCount || 0;
                STATE.skipCount = parsedState.skipCount || 0;
                
                if (parsedState.problemItems && Array.isArray(parsedState.problemItems)) {
                    STATE.problemItems = new Map(parsedState.problemItems);
                }
                
                log(`Restored state: ${STATE.deletionCount} deleted, ${STATE.skipCount} skipped`, "info");
                updateStats();
                
                // Clear the saved state
                sessionStorage.removeItem('fbCleanerState');
            }
        } catch (err) {
            console.error("Error restoring state:", err);
        }
    }
    
    // Start the script
    initialize();
})();