Skip to content

Instantly share code, notes, and snippets.

@GrzegorzManiak
Created October 13, 2023 13:03
Show Gist options
  • Save GrzegorzManiak/b2d5b56ee1ecda74f62fec49e7d3efe0 to your computer and use it in GitHub Desktop.
Save GrzegorzManiak/b2d5b56ee1ecda74f62fec49e7d3efe0 to your computer and use it in GitHub Desktop.
Deletes all your replys on Twitter / X automatically
//
// ENSURE that you are on your own page eg https://twitter.com/x/with_replies
// Wait for the page to fully load, and than copy / paste this script
// into the console.
//
// There are two variables that you can change, SLEEP_FOR and CLICK_DELAY
// --> SLEEP_FOR: Min,Max timeout before scrolling down
// --> CLICK_DELAY: Min,Max timeout between clicking the element
//
(async() => {
const SLEEP_FOR = [1000, 2000];
const CLICK_DELAY = [350, 1000];
// -- Map to store the reply content
const posts_map = new Map();
// -- Dir='ltr' exits on some elements, we just need to find the
// one where theres 'posts' in the innerText
const elms = Array.from(document.querySelectorAll('[dir="ltr"]')),
posts = elms.filter((item) => item.innerText.includes('posts'));
// -- Skip the first element and get the second one
const posts_elm = posts[1];
if (!posts_elm) throw new Error('Could not find the posts element');
// -- We'll get the users name and tag from the page title as its
// easier than messing around with the DOM
// FORMAT: Page title: Posts with replies by x (@x) / X
const page_title = document.querySelector('title').innerText,
regex = /by (.+) \(@(.+)\)/;
// -- Get the users name and tag
const user_name = page_title.match(regex)[1],
user_tag = page_title.match(regex)[2];
console.log(`Deleting replys for ${user_name} (@${user_tag})`);
// -- Function used to return the total number of posts youve replied to
const get_total_posts = () => {
const total_posts = parseInt(posts_elm.innerText.split(' ')[0].replace(',', ''));
console.log(`Total replys remaining: ${total_posts}`);
return total_posts;
};
// -- Function used to return all the reply content on the page
// without returning duplicates
const get_replied = () => {
// -- Get all the replys on the page
const replied_raw = Array.from(document.querySelectorAll('article[data-testid="tweet"][role="article"]')),
replied = replied_raw.filter((item) => {
const name_elm = item.querySelector('[data-testid="User-Name"]');
if (!name_elm) return false;
// -- Ensure that the reply has a delete button, eg. its your reply
if (
name_elm.innerHTML.includes(user_name) &&
name_elm.innerHTML.includes(user_tag)
) return true;
// -- Not your reply
return false;
});
// -- Ensure that we arent returning duplicates
const unique = replied.filter((item) => !posts_map.has(item));
// -- Add the reply content to the map
unique.forEach((item) => posts_map.set(item, false));
// -- Return the unique reply content
return unique;
};
// -- Simple sleep function
const sleep = (min_max) => new Promise((resolve) => {
const min = min_max[0], max = min_max[1];
const time = Math.floor(Math.random() * (max - min + 1)) + min;
setTimeout(resolve, time);
});
// -- Progresses down the page and deletes all the content
const step = async() => {
// -- Get the liked content
const replied = get_replied();
// -- Unlikes all the content
for (const item of replied) {
// -- Click the '...' button: aria-label="More"
const more_btn = item.querySelector('[aria-label="More"]');
if (!more_btn) continue;
// -- Click the more button
more_btn.click();
await sleep(CLICK_DELAY);
// -- Click the 'Delete' button: first child of data-testid="Dropdown"
const delete_btn = document.querySelector('[data-testid="Dropdown"] > div');
if (!delete_btn) continue;
// -- Click the delete button
delete_btn.click();
await sleep(CLICK_DELAY);
// -- Popup confirmation: h1[role="heading"]
const confirm = document.querySelector('div[data-testid="confirmationSheetDialog"]').querySelector('[role="button"]')
if (!confirm) continue;
// -- Click the confirm button
confirm.click();
await sleep(CLICK_DELAY);
}
// -- Scrolls down the page
window.scrollTo(0, document.body.scrollHeight);
}
const started_with = get_total_posts();
// -- Run the step function every 2 seconds
while (true) {
await step();
await sleep(SLEEP_FOR);
// -- If there are no more post left, exit the loop
if (get_total_posts() === 0) break;
}
console.log(`Delted ${started_with} posts`);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment