// ==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);
})();