Reference Script : https://gist.github.com/aymericbeaumet/d1d6799a1b765c3c8bc0b675b1a1547d
Make sure check and support his work in link above!
Don't forget follow me on twitter : https://twitter.com/astin_rai
Thank You
Warning!
If the image or video media is no longer visible and the number of images and videos are still visible under your X(Twitter) name after using this script you must wait at least 1 week or more to continue using this script. I don't know why the rest of media disappear forever from Media List but the total of media still showing below X(Twitter) Username. So, Do With Your Own Risk! (Update: Weird the Media appear again in list after 4 Week/1 Month)
//Make sure open your twitter Profile and go to Media
//Only Work On Desktop Mode!
(() => {
const scrollToTheBottom = () => window.scrollTo(0, document.body.scrollHeight);
const retry = {
count: 0,
limit: 3,
};
const addNewRetry = () => retry.count++;
const retryLimitReached = () => retry.count === retry.limit;
const getTwitterXUsername = document.querySelectorAll('div h2[role="heading"]')[2].innerText;
let getTotalMedia = parseInt(document.querySelectorAll('div h2[role="heading"]')[2].offsetParent.querySelectorAll('div')[4].innerText.split(" ")[0]);
//Time For Sleep To Next Batch
const minSleepToNextBatch = 20; //Minimal Sleep Shouldn't Less Than 20 To Avoid Delete Limit
const maxSleepToNextBatch = 60; //Maximal Sleep Value More Greater More Better
//Language
//Change The Variable Value By Your Language And Must Be In Sentence Case
//You Can Find It By Using Inspect Tool In Chrome/Firefox Or You Can Change Your X/Twitter Display Langauge To English
const moreLanguage = 'More';
const deleteLanguage = 'Delete';
const viewMoreLanguage = 'View post';
const closeLanguage = 'Close';
//Example For Indonesian Language
//const moreLanguage = 'Lainnya';
//const deleteLanguage = 'Hapus';
//const viewMoreLanguage = 'Lihat postingan';
//const closeLanguage = 'Tutup';
console.log(`Hello ${getTwitterXUsername}, Total Media In Your X/Twitter Is ${getTotalMedia} Photos & Videos!`);
const sleep = ({ proggress,seconds }) =>
new Promise((proceed) => {
console.log(`${proggress}`);
console.log(`WAITING FOR ${seconds} SECONDS...`);
setTimeout(proceed, seconds * 1000);
});
const getRandomNumber = (min, max) => {
const minCeiled = Math.ceil(min);
const maxFloored = Math.floor(max);
const resultRandom = Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled);
return resultRandom;
}
const deleteImage = async () => {
await sleep({ proggress: "Click Media" ,seconds: getRandomNumber(5,10) });
await document.querySelectorAll("li[role='listitem']")[0].querySelector("a[role='link']").click();
await sleep({ proggress: "Check If Sidebar Available" ,seconds: getRandomNumber(5,10) });
if(document.querySelector(`button[aria-label='${viewMoreLanguage}'`)) {
document.querySelector(`button[aria-label='${viewMoreLanguage}'`).click();
}
await sleep({ proggress: "Click Button More" ,seconds: getRandomNumber(5,10) });
const moreMenu = document.querySelectorAll(`button[aria-label='${moreLanguage}']`);
for (const menu of moreMenu) {
menu.click();
}
await sleep({ proggress: "Click Delete" ,seconds: getRandomNumber(5,10) });
Array.prototype.slice.call(document.querySelectorAll("div[role='menuitem']"))
.filter(function (el) {
return el.textContent === `${deleteLanguage}`
})[0].click();
await sleep({ proggress: "Confirm Delete" ,seconds: getRandomNumber(5,10) });
await document.querySelectorAll('button[data-testid="confirmationSheetConfirm"]')[0].click();
await sleep({ proggress: "Force Close Media Dialog" ,seconds: getRandomNumber(5,10) });
if(document.querySelector("div[role='dialog'")) {
await document.querySelector("div[role='dialog'").querySelector(`button[aria-label='${closeLanguage}']`).click();
}
await sleep({ proggress: "Remove Deleted Media In List Item" ,seconds: getRandomNumber(5,10) });
document.querySelector("li[role='listitem']").remove();
}
const nextBatch = async () => {
await sleep({ proggress: "Sleeping.....", seconds: getRandomNumber(minSleepToNextBatch,maxSleepToNextBatch) });
await sleep({ proggress: "Checking Media...", seconds: getRandomNumber(5,10) });
const itemImageList = document.querySelectorAll("section[role='region']")[0].querySelectorAll("li[role='listitem']");
const itemImageFound = itemImageList.length > 0;
if (itemImageFound) {
if(!itemImageList[0].innerHTML || !document.querySelector("li[role='listitem']").querySelector("a[role='link']")) {
await sleep({ proggress: "Found Media Item With Problem!, Deleting Item From List......", seconds: 1 });
document.querySelector("li[role='listitem']").remove()
}
await sleep({ proggress: "Media Found!", seconds: 1 });
await deleteImage();
getTotalMedia = getTotalMedia-1;
console.log(`Total Media Left In Your X/Twitter Is ${getTotalMedia} Photos & Videos!`);
await sleep({ proggress: "Proggress to next batch", seconds: getRandomNumber(5,10) });
return nextBatch();
} else {
scrollToTheBottom();
addNewRetry();
}
if (retryLimitReached()) {
console.log(`NO MEDIA FOUND, SO I THINK WE'RE DONE`);
console.log(`RELOAD PAGE AND RE-RUN SCRIPT IF ANY WERE MISSED`);
} else {
await sleep({ proggress: "Proggress to next batch", seconds: getRandomNumber(5,10) });
return nextBatch();
}
};
nextBatch();
})();
Yeah, I encountered this too - I wonder if Twitter engineers did that to try to stymie this kind of scripting