حذف تغريداتك بالجملة، بلا أي إضافة
سكربت مجاني يُلصق في لوحة تحكم كروم لترتيب منشوراتك القديمة على X: محاكاة أولا، تغريداتك الحديثة محمية، وحذف على دفعات محدودة. لا إضافة، ولا خدمة خارجية، ولا شيء يغادر متصفحك.
DRY_RUN = true): فهو يسرد ما سيُحذف من دون أن يمس شيئا. نزّل أرشيف X مسبقا، تحقق من المحاكاة، وبعد ذلك فقط انتقل إلى الحذف الفعلي. أتمتة الواجهة ليست مما تنص عليه شروط استخدام X: تمهّل، وعلى مسؤوليتك.
الخطوات المتّبعة
- افتح ملفك الشخصي: اذهب إلى
x.com/اسم_المستخدم، تبويب المنشورات، وأنت مسجّل الدخول بحسابك. - افتح لوحة التحكم: اضغط
F12(أوCmd+Option+Jعلى ماك)، ثم انقر على تبويب Console. - اضبط السكربت: انسخ الكود أدناه، استبدل
اسم_المستخدمبمعرّفك على X (من دون @)، اضبطKEEP_RECENT(عدد التغريدات الحديثة التي تحتفظ بها)، وإن لزم الأمر أدرج فيKEEP_STATUS_IDSمعرّفات التغريدات التي لا تُحذف أبدا. - حاكِ: الصق السكربت في لوحة التحكم وأكّد بالضغط على Enter. مع
DRY_RUN = true(الإعداد الافتراضي)، يعرض قائمة التغريدات التي ستُحذف، من دون أن يحذف شيئا. - احذف: إذا كانت المحاكاة تناسبك، اضبط
DRY_RUNعلىfalseوأعد التشغيل. يحذف السكربت 40 تغريدة كحد أقصى في كل تشغيل، مع فترات توقف من 6 إلى 14 ثانية. - أعد الكرّة: أعد تشغيل السكربت بقدر ما يلزم لمعالجة الباقي، على دفعات.
السكربت
(() => {
// ============ CONFIG ============
const HANDLE = "اسم_المستخدم"; // معرّفك على X، من دون @
const KEEP_RECENT = 15; // لا يحذف أبدا آخر 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} (تبويب المنشورات) ثم أعد التشغيل.`,
"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، لا يُحذف شيء، فتحصل على قائمة التغريدات المعنية فقط. ثم حماية الأحدث: يبدأ السكربت بحفظ تغريداتك الأحدث (15 افتراضيا) ولن يمسها أبدا. ثم القائمة البيضاء: أي معرّف تضعه في KEEP_STATUS_IDS يبقى محميا، وهو مفيد لتغريداتك المثبَّتة أو إعلاناتك. وأخيرا الإيقاع الحذر: فترات توقف عشوائية من 6 إلى 14 ثانية بين كل عملية حذف، وتوقف تلقائي بعد 40، حتى لا تُطلق قيود X.
قبل الترتيب الكبير، فكّر في أرشفة ما يهمّك: يستعيد مستخرج البريد الإلكتروني والروابط كل روابط ملف تغريدات مصدَّر، ويخبرك عداد الكلمات بحجم سنوات منشوراتك، ويعيد منظف النصوص ترتيب نص منسوخ من الأرشيف. ولتغريداتك المقبلة، يبقى النص المزخرف يونيكود ومحول حالة الأحرف في خدمتك. جميع أدوات صندوق الأدوات تعمل داخل متصفحك، مثل هذا الدليل، بروح سياسة الخصوصية لدينا.
الأسئلة الشائعة
هل الحذف قابل للتراجع؟
لا. التغريدة المحذوفة تُحذف نهائيا، ولا توفر X أي سلة محذوفات. لهذا يُقدَّم السكربت في وضع المحاكاة (DRY_RUN = true): شغّله أولا كما هو للحصول على قائمة بما سيُحذف، تحقق منها، ثم انتقل إلى false فقط حين تكون متأكدا. فكّر أيضا في تنزيل أرشيف X الخاص بك قبل ذلك (الإعدادات، ثم حسابك، ثم تنزيل أرشيف بياناتك).
هل يمكن للسكربت حذف تغريدات شخص آخر؟
لا. لا تُظهر X زر الحذف إلا على منشوراتك أنت: لا يمكن للسكربت أن يعمل إلا على الحساب الذي سجّلت الدخول به، وعلى صفحة ملفك الشخصي. فهو لا يمس ردود الآخرين ولا أي محتوى خاص بطرف ثالث.
لماذا حد أقصى قدره 40 عملية حذف ومهل عشوائية؟
لكي يبقى لطيفا مع المنصة. عمليات الحذف السريعة جدا أو الكثيفة جدا قد تُطلق قيود X، بل وحظرا مؤقتا للحساب. ينتظر السكربت بين 6 و14 ثانية بين كل عملية حذف ويتوقف بعد 40: أعد تشغيله لتتابع على دفعات.
هل هذا مسموح به من X؟
أنت تحذف محتواك أنت، وهذا حقك. في المقابل، أتمتة الواجهة عبر الويب ليست مما تنص عليه شروط استخدام X: استخدم هذا السكربت باعتدال وعلى مسؤوليتك. البديل الرسمي هو الحذف اليدوي، أو الخدمات المخصصة التي تمر عبر واجهة برمجة التطبيقات (API).
كيف أحمي تغريدات محددة بعينها؟
تتراكم حمايتان: يحفظ KEEP_RECENT تلقائيا تغريداتك الأحدث (15 افتراضيا)، ويقبل KEEP_STATUS_IDS قائمة من المعرّفات التي لا تُحذف أبدا. معرّف التغريدة هو الرقم الكبير في نهاية عنوانها: x.com/اسم_المستخدم/status/1234567890123456789.