// ==UserScript== // @name Facebook Activity Auto Deleter (2025) - Fixed // @namespace https://greasyfork.org/en/users/1454546-shawnfrost13 // @version 5.01 // @description Automatically deletes Facebook activity log entries with improved error handling and permanent skipping of problematic items. // @author shawnfrost13 (fixed by Claude) // @license MIT // @match https://www.facebook.com/*/allactivity* // @grant none // @run-at document-end // @downloadURL none // ==/UserScript== (function () { 'use strict'; console.log("πŸ”₯ FB Auto Deleter 4.04 loaded"); let isRunning = false; let deletionCount = 0; let failureCount = 0; let currentlyProcessingItem = null; // Use a map to store problem items and their failure count const problemItems = new Map(); function getRandomDelay(min = 1200, max = 2300) { return Math.floor(Math.random() * (max - min + 1)) + min; } function logStatus(text) { let el = document.getElementById('fb-auto-delete-status'); if (!el) { el = document.createElement('div'); el.id = 'fb-auto-delete-status'; el.style.position = 'fixed'; el.style.bottom = '50px'; el.style.right = '10px'; el.style.background = '#111'; el.style.color = 'lime'; el.style.padding = '10px'; el.style.borderRadius = '10px'; el.style.fontFamily = 'monospace'; el.style.zIndex = '9999'; document.body.appendChild(el); } el.textContent = `🧹 ${text}`; } function createToggleButton() { const toggle = document.createElement('button'); toggle.textContent = '▢️ Start Deleter'; toggle.style.position = 'fixed'; toggle.style.bottom = '95px'; toggle.style.right = '10px'; toggle.style.zIndex = '10000'; toggle.style.padding = '8px 12px'; toggle.style.background = '#222'; toggle.style.color = '#fff'; toggle.style.border = '1px solid lime'; toggle.style.borderRadius = '8px'; toggle.style.cursor = 'pointer'; toggle.style.fontFamily = 'monospace'; toggle.addEventListener('click', () => { isRunning = !isRunning; toggle.textContent = isRunning ? '⏸️ Pause Deleter' : '▢️ Start Deleter'; if (isRunning) deleteNext(); logStatus(isRunning ? 'Script running...' : 'Script paused'); }); document.body.appendChild(toggle); const reset = document.createElement('button'); reset.textContent = 'πŸ”„ Reset Skip List'; reset.style.position = 'fixed'; reset.style.bottom = '140px'; reset.style.right = '10px'; reset.style.zIndex = '10000'; reset.style.padding = '8px 12px'; reset.style.background = '#222'; reset.style.color = '#fff'; reset.style.border = '1px solid orange'; reset.style.borderRadius = '8px'; reset.style.cursor = 'pointer'; reset.style.fontFamily = 'monospace'; reset.addEventListener('click', () => { problemItems.clear(); logStatus('Skip list reset. Will try all items again.'); console.log("πŸ”„ Skip list reset"); }); document.body.appendChild(reset); // Add statistics display const stats = document.createElement('div'); stats.id = 'fb-auto-delete-stats'; stats.style.position = 'fixed'; stats.style.bottom = '185px'; stats.style.right = '10px'; stats.style.background = '#111'; stats.style.color = 'white'; stats.style.padding = '8px'; stats.style.borderRadius = '8px'; stats.style.fontFamily = 'monospace'; stats.style.zIndex = '10000'; stats.style.fontSize = '12px'; stats.style.textAlign = 'right'; document.body.appendChild(stats); // Update stats every second setInterval(() => { if (stats) { stats.innerHTML = `
Items Deleted: ${deletionCount}
Skipped Items: ${problemItems.size}
`; } }, 1000); } function getItemSignature(element) { if (!element) return null; // Find the parent container of the menu button let container = element.closest('[data-visualcompletion="ignore-dynamic"]'); if (!container) { // Try to find the closest parent that might be a post or activity item container = element.closest('div[role="article"]') || element.closest('div[role="row"]') || element.closest('div[data-pagelet*="FeedUnit"]'); if (!container) { // Fallback to parent element container = element.parentElement; if (!container) return null; } } // Get inner text content const textContent = container.innerText.slice(0, 100).replace(/\s+/g, ' ').trim(); // Try to find timestamps or other identifiers const timestamp = container.querySelector('abbr[data-utime]'); const timeValue = timestamp ? timestamp.getAttribute('data-utime') : ''; // Use position as part of signature const parentElement = container.parentElement; const position = parentElement && parentElement.children ? Array.from(parentElement.children).indexOf(container) : -1; // Create a signature that combines content and structure info return `${timeValue}-${textContent}-${position}`; } function checkForErrorPopups() { // Look for error popups of various types const errorTexts = [ "Something went wrong", "Please try again", "An error occurred", "We couldn't process", "Action blocked" ]; // Check dialog alerts const alertPopups = Array.from(document.querySelectorAll('[role="alert"], [role="dialog"], [role="alertdialog"]')); for (const popup of alertPopups) { if (errorTexts.some(text => popup.innerText.includes(text))) { console.log("⚠️ Found error popup: " + popup.innerText.slice(0, 50)); return true; } } // Check status notifications (bottom popups) const statusNotifications = Array.from(document.querySelectorAll('[role="status"]')); for (const notification of statusNotifications) { if (errorTexts.some(text => notification.innerText.includes(text))) { console.log("⚠️ Found error notification: " + notification.innerText.slice(0, 50)); return true; } } // Look for generic red-colored error messages const errorMessages = Array.from(document.querySelectorAll('div[style*="color: rgb(244, 33, 46)"], div[style*="color:#f4212e"], div[style*="color:red"]')); if (errorMessages.length > 0) { console.log("⚠️ Found error message with red text"); return true; } return false; } function closeAllErrorPopups() { let anyClosed = false; // Close dialog alerts const alertPopups = Array.from(document.querySelectorAll('[role="alert"], [role="dialog"], [role="alertdialog"]')); for (const popup of alertPopups) { if (popup.innerText.includes("Something went wrong") || popup.innerText.includes("try again")) { const closeBtn = popup.querySelector('[aria-label="Close"], [aria-label="Dismiss"], button, div[role="button"]'); if (closeBtn) { closeBtn.click(); anyClosed = true; console.log("🚫 Closed error popup"); } } } // Close status notifications const statusNotifications = Array.from(document.querySelectorAll('[role="status"]')); for (const notification of statusNotifications) { if (notification.innerText.includes("Something went wrong") || notification.innerText.includes("try again")) { const closeBtn = notification.querySelector('div[role="button"], button'); if (closeBtn) { closeBtn.click(); anyClosed = true; console.log("🚫 Closed notification popup"); } } } // As a last resort, try to click on any X button in visible dialogs if (!anyClosed) { const anyDialogs = document.querySelectorAll('[role="dialog"], [role="alertdialog"]'); for (const dialog of anyDialogs) { if (dialog.offsetParent !== null) { // is visible const closeButtons = dialog.querySelectorAll('svg[aria-label="Close"]'); for (const btn of closeButtons) { const clickableParent = btn.closest('div[role="button"]') || btn.closest('button'); if (clickableParent) { clickableParent.click(); anyClosed = true; console.log("🚫 Closed dialog using SVG close button"); } } } } } return anyClosed; } function findMenuButtons() { return 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")) ); }); } function autoConfirmPopups() { const dialogs = Array.from(document.querySelectorAll('[role="dialog"], [role="alertdialog"]')); dialogs.forEach(dialog => { const deleteBtn = Array.from(dialog.querySelectorAll('div[role="button"], button')) .find(btn => btn.offsetParent !== null && btn.innerText.trim().toLowerCase() === "delete" ); if (deleteBtn) { console.log("βœ… Auto-confirming DELETE dialog"); deleteBtn.click(); logStatus("Auto-confirmed delete popup"); } }); } function autoScrollAndRetry() { console.log("πŸ”„ Scrolling to load more activity..."); logStatus("Scrolling to load more items..."); window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); setTimeout(() => deleteNext(), 2500); } function markCurrentItemAsProblem() { if (currentlyProcessingItem) { const signature = getItemSignature(currentlyProcessingItem); if (signature) { // Add to problematic items or increment failure count const currentCount = problemItems.get(signature) || 0; problemItems.set(signature, currentCount + 1); console.log(`🚫 Marking item as problematic: "${signature.substring(0, 30)}..." (attempt ${currentCount + 1})`); // If we've tried this item 2 times, log it permanently if (currentCount + 1 >= 2) { console.log(`πŸ”’ PERMANENTLY skipping problematic item: "${signature.substring(0, 30)}..."`); } } } } function shouldSkipItem(btn) { const signature = getItemSignature(btn); if (!signature) return false; const failCount = problemItems.get(signature) || 0; return failCount >= 2; // Skip if we've failed 2 or more times } function deleteNext() { if (!isRunning) return; // Reset tracking of current item currentlyProcessingItem = null; // First check for errors from previous operations if (checkForErrorPopups()) { console.log("❌ Error popup detected from previous operation"); markCurrentItemAsProblem(); closeAllErrorPopups(); // Wait a bit before continuing setTimeout(deleteNext, getRandomDelay()); return; } // Clean up any dialogs autoConfirmPopups(); const buttons = findMenuButtons(); if (buttons.length === 0) { logStatus('No deletable buttons found. Trying to scroll...'); autoScrollAndRetry(); return; } // Filter out items we should skip const validButtons = buttons.filter(btn => !shouldSkipItem(btn)); if (validButtons.length === 0) { logStatus('Only skippable items found. Scrolling for more...'); autoScrollAndRetry(); return; } const btn = validButtons[0]; currentlyProcessingItem = btn; btn.scrollIntoView({ behavior: 'smooth', block: 'center' }); // Wait a bit after scrolling before clicking setTimeout(() => { btn.click(); logStatus(`Opened menu for item #${deletionCount + 1}`); console.log(`πŸ“‚ Opened menu for item #${deletionCount + 1}`); setTimeout(() => { const menuItems = Array.from(document.querySelectorAll('[role="menuitem"]')); const deleteOption = menuItems.find(el => 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") ); if (deleteOption) { deleteOption.click(); logStatus(`Clicked delete on item #${deletionCount + 1}`); console.log(`πŸ—‘οΈ Attempted delete on item #${deletionCount + 1}`); // Start checking for errors with a series of checks // We'll check multiple times to catch errors that might appear with a delay const errorCheckIntervals = [800, 1600, 2400]; let checkIndex = 0; function performErrorCheck() { if (checkIndex >= errorCheckIntervals.length) { // If we've checked multiple times and found no errors, consider it successful deletionCount++; logStatus(`βœ… Deleted item #${deletionCount}`); // Move to next item after a delay setTimeout(deleteNext, getRandomDelay()); return; } // Check for errors if (checkForErrorPopups()) { console.log("❌ Error detected during deletion"); markCurrentItemAsProblem(); closeAllErrorPopups(); // Move to next item after a delay setTimeout(deleteNext, getRandomDelay()); return; } // Schedule next check checkIndex++; setTimeout(performErrorCheck, errorCheckIntervals[checkIndex-1]); } // Start the first error check setTimeout(performErrorCheck, errorCheckIntervals[0]); } else { // If no delete option found, mark as problematic and move on console.log("⚠️ No delete option found"); markCurrentItemAsProblem(); // Click elsewhere to close the menu document.body.click(); // Move to next item setTimeout(deleteNext, getRandomDelay()); } }, 1300); }, 500); } // Initial setup createToggleButton(); // Regular maintenance tasks setInterval(autoConfirmPopups, 1000); setInterval(() => { // Periodically check for and close error popups that might be blocking progress if (isRunning) { closeAllErrorPopups(); } }, 2000); })();