এক্সটেনশন ছাড়াই টুইট একসাথে মুছে ফেলুন
আপনার পুরনো X পোস্টে ঝাড়ু চালাতে ক্রোমের কনসোলে বসানোর মতো একটি বিনামূল্যের স্ক্রিপ্ট: আগে সিমুলেশন, সাম্প্রতিক টুইট সুরক্ষিত, সীমা বেঁধে দলে দলে মুছে ফেলা। কোনো এক্সটেনশন নেই, কোনো তৃতীয় পক্ষের সেবা নেই, কিছুই আপনার ব্রাউজার ছেড়ে যায় না।
DRY_RUN = true) দেওয়া হয়েছে: কোনো কিছুতে হাত না দিয়েই এটি কী কী মুছে ফেলা হতো তার তালিকা দেখায়। আগে থেকে আপনার X আর্কাইভ ডাউনলোড করুন, সিমুলেশন যাচাই করুন, আর কেবল তারপরই সত্যিকারের মুছে ফেলায় যান। ওয়েব ইন্টারফেসের স্বয়ংক্রিয়করণ X এর ব্যবহারের শর্তাবলীতে ধরা নেই: ধীরে এগোন, নিজ দায়িত্বে।
যেভাবে করবেন
- আপনার প্রোফাইল খুলুন: নিজের অ্যাকাউন্টে লগ ইন করা অবস্থায়
x.com/apnar_usernameএ যান, Posts ট্যাবে। - কনসোল খুলুন:
F12চাপুন (অথবা Mac এCmd+Option+J), তারপর Console ট্যাবে ক্লিক করুন। - স্ক্রিপ্টটি সাজান: নিচের কোডটি কপি করুন,
apnar_usernameএর জায়গায় আপনার X আইডি বসান (@ ছাড়া),KEEP_RECENTঠিক করুন (কতগুলো সাম্প্রতিক টুইট রাখবেন) আর প্রয়োজন হলেKEEP_STATUS_IDSএ কখনো না মুছে ফেলার মতো টুইটগুলোর আইডি তালিকাভুক্ত করুন। - সিমুলেশন চালান: স্ক্রিপ্টটি কনসোলে বসিয়ে Enter চাপুন।
DRY_RUN = trueথাকলে (ডিফল্ট সেটিং), এটি কোনো কিছু না মুছেই কোন টুইটগুলো মুছে ফেলা হতো তার তালিকা দেখায়। - মুছে ফেলুন: সিমুলেশন পছন্দ হলে
DRY_RUNকেfalseএ বদলে আবার চালান। স্ক্রিপ্টটি প্রতি চালানোয় সর্বোচ্চ ৪০টি টুইট মোছে, প্রতিবার ৬ থেকে ১৪ সেকেন্ড বিরতিসহ। - আবার চালান: বাকিগুলো দলে দলে সামলাতে যতবার দরকার ততবার স্ক্রিপ্টটি আবার চালান।
স্ক্রিপ্টটি
(() => {
// ============ CONFIG ============
const HANDLE = "apnar_username"; // আপনার X আইডি, @ ছাড়া
const KEEP_RECENT = 15; // সবচেয়ে সাম্প্রতিক ১৫টি টুইট (উপরের দিকে) কখনো মুছবে না
const KEEP_STATUS_IDS = [ // বাড়তি সুরক্ষা (ঐচ্ছিক): কখনো না মুছে ফেলার মতো আইডি
"1234567890123456789",
];
let DRY_RUN = true; // true = সিমুলেশন (শুধু তালিকা)। false = সত্যিকারের মুছে ফেলা।
const MIN_DELAY_MS = 6000;
const MAX_DELAY_MS = 14000;
const MAX_DELETIONS = 40; // প্রতি চালানোর সীমা (চালিয়ে যেতে আবার চালান)
// ================================
const me = HANDLE.toLowerCase();
const KEEP = new Set(KEEP_STATUS_IDS.map(String));
const protectedRecent = new Set();
const RX_DELETE = /(মুছ|delete|supprimer)/i;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const rand = (a, b) => Math.floor(a + Math.random() * (b - a));
const skipped = new Set();
if (!location.pathname.toLowerCase().startsWith("/" + me)) {
console.warn(`%c[STOP] https://x.com/${HANDLE} এ যান (Posts ট্যাব) তারপর আবার চালান।`,
"color:#e0245e;font-weight:bold");
return;
}
const articles = () => [...document.querySelectorAll('article[data-testid="tweet"]')];
const idOf = (art) => {
const href = [...art.querySelectorAll('a[href*="/status/"]')]
.map((x) => x.getAttribute("href"))
.find((h) => new RegExp(`^/${HANDLE}/status/\\d+`, "i").test(h));
if (!href) return null;
const m = href.match(/status\/(\d+)/);
return m ? m[1] : null;
};
// সবচেয়ে সাম্প্রতিক KEEP_RECENT টুইট (উপরের দিকের) লোড করে সুরক্ষিত রাখে।
async function protectRecent() {
const order = [], seen = new Set();
let noNew = 0;
window.scrollTo(0, 0);
await sleep(1200);
while (order.length < KEEP_RECENT && noNew < 6) {
let added = 0;
for (const art of articles()) {
const id = idOf(art);
if (id && !seen.has(id)) { seen.add(id); order.push(id); added++; }
}
noNew = added ? 0 : noNew + 1;
if (order.length >= KEEP_RECENT) break;
const cs = articles();
(cs[cs.length - 1] || document.body).scrollIntoView({ block: "end" });
await sleep(1400);
}
for (const id of order.slice(0, KEEP_RECENT)) protectedRecent.add(id);
return order.slice(0, KEEP_RECENT);
}
const eligible = (art) => {
const id = idOf(art);
if (!id) return null;
if (protectedRecent.has(id)) return null; // সাম্প্রতিকগুলোর একটি
if (KEEP.has(id)) return null; // বাড়তি সুরক্ষিত আইডি
if (skipped.has(id)) return null;
return id;
};
async function deleteOne(art, id) {
const caret = art.querySelector('[data-testid="caret"]');
if (!caret) { skipped.add(id); return false; }
caret.click();
await sleep(700);
const del = [...document.querySelectorAll('[role="menuitem"]')]
.find((i) => RX_DELETE.test((i.innerText || "").trim()));
if (!del) { document.body.click(); skipped.add(id); return false; }
del.click();
await sleep(700);
const confirmBtn = document.querySelector('[data-testid="confirmationSheetConfirm"]');
if (!confirmBtn) { skipped.add(id); return false; }
confirmBtn.click();
await sleep(1500);
return true;
}
async function dryScan() {
const seen = new Set();
let noNew = 0;
console.log("%c[সিমুলেশন] কিছুই মুছে ফেলা হবে না। গণনা চলছে...", "color:#1d9bf0;font-weight:bold");
while (noNew < 4) {
let added = 0;
for (const art of articles()) {
const id = eligible(art);
if (id && !seen.has(id)) { seen.add(id); added++; }
}
noNew = added ? 0 : noNew + 1;
const cs = articles();
(cs[cs.length - 1] || document.body).scrollIntoView({ block: "end" });
await sleep(1200);
}
console.log(`%c[সিমুলেশন] ${seen.size} টি টুইট মুছে ফেলা হতো (সাম্প্রতিকগুলো সুরক্ষিত)।`,
"color:#1d9bf0;font-weight:bold");
console.log([...seen].slice(0, 60));
}
async function run() {
let count = 0, guard = 0, noHit = 0, started = false;
while (count < MAX_DELETIONS && guard++ < 1500) {
const pair = articles().map((a) => [a, eligible(a)]).find(([, id]) => id);
if (!pair) {
if ((started && noHit >= 6) || noHit >= 40) break;
const cs = articles();
(cs[cs.length - 1] || document.body).scrollIntoView({ block: "end" });
await sleep(1500);
noHit++;
continue;
}
started = true; noHit = 0;
const [node, id] = pair;
node.scrollIntoView({ block: "center" });
await sleep(600);
const ok = await deleteOne(node, id);
if (ok) count++;
console.log(`${ok ? "মুছে ফেলা হয়েছে" : "বাদ দেওয়া হয়েছে"} ${id} (মোট: ${count}/${MAX_DELETIONS})`);
await sleep(rand(MIN_DELAY_MS, MAX_DELAY_MS));
}
console.log(`%c[শেষ] এই দফায় ${count} টি মুছে ফেলা হয়েছে। আরও থাকলে স্ক্রিপ্টটি আবার চালান।`,
"color:#00ba7c;font-weight:bold");
}
(async () => {
console.log(`সবচেয়ে সাম্প্রতিক ${KEEP_RECENT} টি টুইট লোড ও সুরক্ষিত করা হচ্ছে...`);
const recent = await protectRecent();
if (recent.length < KEEP_RECENT) {
console.warn(`%c[STOP] শুধু ${recent.length} টি টুইট লোড হয়েছে (X গতি কমিয়ে দিয়েছে)। পাতাটি রিলোড করুন (F5) এবং আবার চেষ্টা করুন।`,
"color:#e0245e;font-weight:bold");
return;
}
console.log("%cসুরক্ষিত (সবচেয়ে সাম্প্রতিক):", "color:#00ba7c;font-weight:bold", recent);
if (DRY_RUN) { await dryScan(); return; }
await run();
})();
})();
স্ক্রিপ্টটি যেভাবে আপনাকে সুরক্ষা দেয়
চারটি নিরাপত্তা-বেষ্টনী এতে গাঁথা আছে। প্রথমত ডিফল্ট সিমুলেশন: যতক্ষণ DRY_RUN এর মান true, কিছুই মুছে ফেলা হয় না, আপনি শুধু সংশ্লিষ্ট টুইটগুলোর তালিকা পান। এরপর সাম্প্রতিকগুলোর সুরক্ষা: স্ক্রিপ্টটি প্রথমেই আপনার সবচেয়ে সাম্প্রতিক টুইটগুলো (ডিফল্টে ১৫টি) মনে রাখে এবং কখনো সেগুলোতে হাত দেয় না। তারপর শ্বেততালিকা: KEEP_STATUS_IDS এ রাখা যেকোনো আইডি অস্পর্শনীয়, আপনার পিন করা টুইট বা ঘোষণার জন্য কাজে দেয়। শেষে সতর্ক গতি: প্রতিটি মুছে ফেলার মাঝে ৬ থেকে ১৪ সেকেন্ডের এলোমেলো বিরতি আর ৪০টির পর স্বয়ংক্রিয় থেমে যাওয়া, যাতে X এর সীমাবদ্ধতা চালু না হয়।
বড় ঝাড়ু চালানোর আগে যা গুরুত্বপূর্ণ তা সংরক্ষণ করে নেওয়ার কথা ভাবুন: ইমেইল ও URL এক্সট্র্যাক্টর একটি টুইট এক্সপোর্টের সব লিংক তুলে আনে, শব্দ গণনাকারী বলে দেয় আপনার বছরের পর বছরের পোস্টের ওজন কত ছিল, আর টেক্সট পরিষ্কারক আর্কাইভ থেকে কপি করা লেখা পরিপাটি করে দেয়। আর আপনার ভবিষ্যতের টুইটের জন্য ইউনিকোড স্টাইলিশ টেক্সট ও কেস কনভার্টার তো আছেই। এই গাইডের মতোই টুলবক্সের সব টুল আপনার ব্রাউজারেই চলে, আমাদের গোপনীয়তা নীতির চেতনায়।
সাধারণ প্রশ্ন
মুছে ফেলা কি ফিরিয়ে আনা যায়?
না। মুছে ফেলা টুইট স্থায়ীভাবেই মুছে যায়, X কোনো রিসাইকেল বিন দেয় না। এ কারণেই স্ক্রিপ্টটি সিমুলেশন মোডে (DRY_RUN = true) দেওয়া হয়েছে: প্রথমে এটিকে যেমন আছে তেমনভাবেই চালিয়ে দেখুন কোনগুলো মুছে ফেলা হতো তার তালিকা পান, সেটি যাচাই করুন, আর নিশ্চিত হলে তবেই false এ বদলান। আগে থেকে আপনার X আর্কাইভ ডাউনলোড করে রাখার কথাও ভাবুন (সেটিংস, তারপর আপনার অ্যাকাউন্ট, তারপর আপনার ডেটার একটি আর্কাইভ ডাউনলোড করুন)।
স্ক্রিপ্টটি কি অন্য কারও টুইট মুছে ফেলতে পারে?
না। X শুধু আপনার নিজের পোস্টেই মুছে ফেলার বোতাম দেখায়: স্ক্রিপ্টটি কেবল সেই অ্যাকাউন্টেই কাজ করতে পারে যেটিতে আপনি লগ ইন করা আছেন, আপনার নিজের প্রোফাইল পাতায়। এটি অন্যদের উত্তর বা কোনো তৃতীয় পক্ষের কনটেন্টে হাত দেয় না।
কেন ৪০টি মুছে ফেলার সীমা আর এলোমেলো বিরতি?
প্ল্যাটফর্মের সাথে নরম আচরণ করার জন্য। খুব দ্রুত বা খুব বেশি পরিমাণে মুছে ফেললে X এর সীমাবদ্ধতা চালু হতে পারে, এমনকি অ্যাকাউন্ট সাময়িকভাবে ব্লকও হতে পারে। স্ক্রিপ্টটি প্রতিটি মুছে ফেলার মাঝে ৬ থেকে ১৪ সেকেন্ড অপেক্ষা করে আর ৪০টির পর থেমে যায়: বাকিগুলো দলে দলে চালিয়ে যেতে আবার চালান।
এটি কি X অনুমোদন করে?
আপনি আপনার নিজের কনটেন্ট মুছছেন, যা আপনার অধিকার। তবে ওয়েব ইন্টারফেসের স্বয়ংক্রিয়করণ X এর ব্যবহারের শর্তাবলীতে ধরা নেই: এই স্ক্রিপ্ট পরিমিতভাবে ও নিজ দায়িত্বে ব্যবহার করুন। অফিসিয়াল বিকল্প হলো হাতে হাতে মুছে ফেলা, অথবা API দিয়ে চলা নির্দিষ্ট সেবাগুলো।
কিছু নির্দিষ্ট টুইট কীভাবে সুরক্ষিত রাখব?
দুটি সুরক্ষা একসাথে কাজ করে: KEEP_RECENT আপনার সবচেয়ে সাম্প্রতিক টুইটগুলো নিজে থেকেই রেখে দেয় (ডিফল্টে ১৫টি), আর KEEP_STATUS_IDS কখনো না মুছে ফেলার মতো আইডির একটি তালিকা গ্রহণ করে। একটি টুইটের আইডি হলো তার ঠিকানার শেষে থাকা বড় সংখ্যাটি: x.com/apnar_username/status/1234567890123456789।