(async function autoReplyFlow() {
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function getElementByXPath(xpath, parent = document) {
const result = document.evaluate(xpath, parent, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
return result.singleNodeValue;
}
if (!localStorage.getItem('processed_items')) {
localStorage.setItem('processed_items', JSON.stringify([]));
}
if (!localStorage.getItem('skipped_items')) {
localStorage.setItem('skipped_items', JSON.stringify([]));
}
// Bật/tắt lại script sẽ tính lại thời gian bắt đầu từ đầu
localStorage.setItem('session_start_time', Date.now());
function getStorageCount(storageKey) {
const list = JSON.parse(localStorage.getItem(storageKey) || '[]');
return list.length;
}
function getCurrentPostId(url) {
const match = url.match(/\/status\/(\d+)/);
return match ? match[1] : null;
}
function storageHasId(storageKey, postId) {
const list = JSON.parse(localStorage.getItem(storageKey) || '[]');
return list.some(item => item.id === postId);
}
function addItemToStorage(storageKey, postId, postUrl, reason = "") {
let list = JSON.parse(localStorage.getItem(storageKey) || '[]');
const existingIndex = list.findIndex(item => item.id === postId);
if (existingIndex === -1) {
list.push({ id: postId, url: postUrl, reason: reason });
localStorage.setItem(storageKey, JSON.stringify(list));
} else if (reason && !list[existingIndex].reason) {
list[existingIndex].reason = reason;
localStorage.setItem(storageKey, JSON.stringify(list));
}
}
function getSessionTimeInfo() {
const startTime = parseInt(localStorage.getItem('session_start_time') || Date.now());
const startDate = new Date(startTime);
const hours = String(startDate.getHours()).padStart(2, '0');
const minutes = String(startDate.getMinutes()).padStart(2, '0');
const day = String(startDate.getDate()).padStart(2, '0');
const month = String(startDate.getMonth() + 1).padStart(2, '0');
const startFormatted = `${hours}:${minutes} ${day}/${month}`;
const diffMs = Date.now() - startTime;
const diffMins = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMins / 60);
const remMins = diffMins % 60;
let timeAgo = "";
if (diffMins < 1) {
timeAgo = "vừa bắt đầu";
} else if (diffMins < 60) {
timeAgo = `${diffMins} phút trước`;
} else {
timeAgo = remMins > 0 ? `${diffHours} giờ ${remMins} phút trước` : `${diffHours} giờ trước`;
}
return { startFormatted, timeAgo, diffMins };
}
let myHandle = null;
function initMyHandle() {
const avatarEl = document.querySelector('[data-testid^="UserAvatar-Container-"]');
if (avatarEl) {
const testId = avatarEl.getAttribute('data-testid');
const match = testId.match(/UserAvatar-Container-(.+)/);
if (match) {
myHandle = `@${match[1]}`;
}
}
}
function refreshConsoleView() {
console.clear();
const doneCount = getStorageCount('processed_items');
const skipCount = getStorageCount('skipped_items');
const processedList = JSON.parse(localStorage.getItem('processed_items') || '[]');
const skippedList = JSON.parse(localStorage.getItem('skipped_items') || '[]');
const { startFormatted, timeAgo, diffMins } = getSessionTimeInfo();
let avgPerMin = 0;
const activeMins = Math.max(diffMins, 1);
avgPerMin = parseFloat((doneCount / activeMins).toFixed(2));
const headerTitle = `[LIST] Processed: ${doneCount} | Skipped: ${skipCount} | Start: ${startFormatted} (${timeAgo}) | Trung bình: ${avgPerMin} trả lời/phút`;
console.groupCollapsed(`${headerTitle} (Click để xem chi tiết)`);
console.log("Processed List:");
console.table(processedList);
console.log("Skipped List:");
console.table(skippedList);
console.groupEnd();
console.log("-----------------------------------------");
}
initMyHandle();
refreshConsoleView();
const initialUrl = window.location.href;
if (!initialUrl.includes('/home') && initialUrl !== 'https://x.com/' && initialUrl !== 'https://twitter.com/') {
console.log("🔄 Đang ở trang khác -> Điều hướng về Home trước khi bắt đầu...");
const homeNavBtn = document.querySelector('a[data-testid="AppTabBar_Home_Link"]');
if (homeNavBtn) {
homeNavBtn.click();
} else {
window.location.href = 'url?id=1';
}
await sleep(4000);
}
let sessionStartTime = Date.now();
const REFRESH_INTERVAL = 5 * 60 * 1000;
while (true) {
const currentUrl = window.location.href;
if (currentUrl.includes('/compose/post')) {
const closeComposeXPath = '//*[@id="layers"]/div[2]/div/div/div/div/div/div[2]/div[2]/div/div/div/div[2]/div/div/div/div/div/div[1]/button';
const closeBtn = getElementByXPath(closeComposeXPath);
if (closeBtn) closeBtn.click();
await sleep(2000);
continue;
}
if (!myHandle) initMyHandle();
// --- BẢO VỆ 1: NẾU URL LÀ BÀI VIẾT CỦA CHÍNH MÌNH THÌ BỎ QUA NGAY ---
if (myHandle && currentUrl.includes(`/${myHandle.replace('@', '')}/status/`)) {
history.back();
await sleep(3000);
continue;
}
// --- HOME ---
if (currentUrl.includes('/home') || currentUrl === 'https://x.com/' || currentUrl === 'https://twitter.com/') {
if (Date.now() - sessionStartTime > REFRESH_INTERVAL) {
refreshConsoleView();
console.log("🔄 Refresh Home (5 phút)");
const homeNavBtn = document.querySelector('a[data-testid="AppTabBar_Home_Link"]');
if (homeNavBtn) {
homeNavBtn.click();
sessionStartTime = Date.now();
await sleep(4000);
continue;
}
}
await sleep(1500); // Tốc độ 0.5 (chậm rãi, an toàn)
const articles = Array.from(document.querySelectorAll('article[data-testid="tweet"]'));
let targetPostContainer = null;
for (const article of articles) {
if (article.querySelector('[data-testid="placementTracking"]') || article.getAttribute('data-testid') === 'placementTracking') continue;
let isMyPost = false;
if (myHandle) {
const userCell = article.querySelector('[data-testid="User-Name"]');
if (userCell && userCell.textContent.includes(myHandle)) {
isMyPost = true;
}
}
const statusLink = article.querySelector('a[href*="/status/"]');
if (statusLink) {
const href = statusLink.href;
const postId = getCurrentPostId(href);
if (postId) {
if (storageHasId('processed_items', postId) || storageHasId('skipped_items', postId)) {
continue;
}
if (isMyPost || (myHandle && href.includes(`/${myHandle.replace('@','')}/status/`))) {
continue;
}
const tweetTextContent = article.querySelector('[data-testid="tweetText"]');
if (tweetTextContent) {
targetPostContainer = tweetTextContent;
break;
}
}
}
}
if (targetPostContainer) {
targetPostContainer.click();
await sleep(5000);
} else {
const randomScroll = Math.floor(Math.random() * 700) + 500;
const randomSleep = Math.floor(Math.random() * 1600) + 1600;
window.scrollBy({ top: randomScroll, behavior: 'smooth' });
await sleep(randomSleep);
}
continue;
}
// --- STATUS ---
if (currentUrl.includes('/status/')) {
const postId = getCurrentPostId(currentUrl);
if (postId && (storageHasId('processed_items', postId) || storageHasId('skipped_items', postId))) {
history.back();
await sleep(3000);
window.scrollBy({ top: Math.floor(Math.random() * 400) + 300, behavior: 'smooth' });
await sleep(1500);
continue;
}
await sleep(1000);
let authorHandle = "unknown";
const firstTweet = document.querySelector('article[data-testid="tweet"]');
if (firstTweet) {
const nameEl = firstTweet.querySelector('[data-testid="User-Name"]');
if (nameEl) {
const spans = Array.from(nameEl.querySelectorAll('span'));
for (const text of spans.map(s => s.textContent.trim())) {
if (text.startsWith('@')) {
authorHandle = text;
break;
}
}
}
}
// --- BẢO VỆ 2: TÁC GIẢ BÀI GỐC LÀ CHÍNH MÌNH ---
if (myHandle && authorHandle.toLowerCase() === myHandle.toLowerCase()) {
history.back();
await sleep(2000);
continue;
}
// --- BẢO VỆ 3: QUÉT DOM XEM CÓ DÍNH CHUỖI TRẢ LỜI CHO CHÍNH MÌNH KHÔNG ---
let isReplyingToSelf = false;
if (myHandle) {
const allButtonsAndTexts = document.querySelectorAll('button, div, span');
for (const el of allButtonsAndTexts) {
const text = el.textContent || "";
if (text.includes("Đang trả lời") && text.toLowerCase().includes(myHandle.toLowerCase())) {
isReplyingToSelf = true;
break;
}
}
}
if (isReplyingToSelf) {
history.back();
await sleep(2000);
continue;
}
// --- QUÉT DOM KIỂM TRA XEM MÌNH ĐÃ TỪNG COMMENT BÀI NÀY CHƯA ---
let alreadyCommented = false;
if (myHandle) {
const allArticles = document.querySelectorAll('article[data-testid="tweet"]');
for (const art of allArticles) {
const userCell = art.querySelector('[data-testid="User-Name"]');
if (userCell && userCell.textContent.toLowerCase().includes(myHandle.toLowerCase())) {
alreadyCommented = true;
break;
}
}
}
if (alreadyCommented) {
if (postId) {
addItemToStorage('processed_items', postId, currentUrl, "Đã comment trước đó (quét từ DOM)");
}
refreshConsoleView();
history.back();
await sleep(2000);
continue;
}
const syncOrGenBtn = document.querySelector('.xra-button.xra-sync') || document.querySelector('.xra-button.xra-generate');
if (syncOrGenBtn) {
syncOrGenBtn.scrollIntoView({ behavior: 'smooth', block: 'center' });
await sleep(1000);
} else {
window.scrollBy({ top: 450, behavior: 'smooth' });
await sleep(1000);
}
let timeoutCounter = 0;
let actionCompleted = false;
let isUndefined = false;
let lastStatusLogged = "";
console.log(`${authorHandle}`);
while (!actionCompleted && timeoutCounter < 20) {
timeoutCounter++;
const genBtn = document.querySelector('.xra-button.xra-generate');
const syncBtn = document.querySelector('.xra-button.xra-sync');
if (!genBtn && !syncBtn) {
if (timeoutCounter >= 20) {
isUndefined = true;
}
await sleep(1000);
continue;
}
const isGenDisabled = genBtn && (genBtn.getAttribute('aria-disabled') === 'true' || genBtn.disabled);
const isSyncDisabled = syncBtn && (syncBtn.getAttribute('aria-disabled') === 'true' || syncBtn.disabled);
const isSyncing = syncBtn && (syncBtn.querySelector('svg.ui-icon-refresh') && syncBtn.querySelector('svg').classList.contains('rotating') || syncBtn.classList.contains('loading'));
let status = "NORMAL";
if (isGenDisabled || isSyncDisabled) {
status = "LOCK";
} else if (isSyncing) {
status = "LOADING";
} else {
status = "NORMAL";
}
if (status !== lastStatusLogged) {
console.log(`- Status: ${status}`);
lastStatusLogged = status;
}
if (status === "NORMAL") {
// --- KIỂM TRA LẠI LẦN CUỐI CỰC KỲ GẮT GAO NGAY TRƯỚC KHI CLICK ---
if (myHandle) {
let finalCheckSelf = false;
const checkElements = document.querySelectorAll('button, div, span');
for (const el of checkElements) {
const text = el.textContent || "";
if (
(text.includes("Đang trả lời") && text.toLowerCase().includes(myHandle.toLowerCase())) ||
window.location.href.includes(`/${myHandle.replace('@', '')}/status/`)
) {
finalCheckSelf = true;
break;
}
}
if (finalCheckSelf) {
console.log("🛑 Phát hiện bài của chính mình phút chót -> Hủy click!");
actionCompleted = true;
break;
}
}
const suggestions = document.querySelectorAll('.xra-results .xra-suggestion-wrap');
const count = suggestions.length;
if (count > 0) {
console.log(`- Suggested: ${count}`);
const randomIndex = Math.floor(Math.random() * count);
console.log(`=> [${randomIndex + 1}]`);
const mainChipText = suggestions[randomIndex].querySelector('.xra-chip-main');
if (mainChipText) {
mainChipText.click();
if (postId) {
addItemToStorage('processed_items', postId, currentUrl);
}
const totalDone = getStorageCount('processed_items');
const totalSkip = getStorageCount('skipped_items');
console.log(`=> Done [Total done: ${totalDone} | Total skip: ${totalSkip}]`);
await sleep(1500);
refreshConsoleView();
}
actionCompleted = true;
break;
} else {
console.log("- 0 result (Retry)");
const xpathTarget = '//*[@id="react-root"]/div/div/div[2]/main/div/div/div/div/div/section/div/div/div[1]/div/div/div/div/div/div[2]/div[2]/div/div/div/div[2]/div[1]/div/div/div/div/div/div/div/div/div[2]/div[1]/div[1]/button[2]';
const targetBtn = getElementByXPath(xpathTarget) || document.querySelector('.xra-button.xra-sync');
if (targetBtn) {
targetBtn.click();
await sleep(2000);
let waitRetry = 0;
let retrySuccess = false;
while (waitRetry < 15) {
waitRetry++;
await sleep(1000);
const gBtn = document.querySelector('.xra-button.xra-generate');
const sBtn = document.querySelector('.xra-button.xra-sync');
const gDis = gBtn && (gBtn.getAttribute('aria-disabled') === 'true' || gBtn.disabled);
const sDis = sBtn && (sBtn.getAttribute('aria-disabled') === 'true' || sBtn.disabled);
const sSync = sBtn && (sBtn.querySelector('svg.ui-icon-refresh') && sBtn.querySelector('svg').classList.contains('rotating') || sBtn.classList.contains('loading'));
let currStatus = (gDis || sDis) ? "LOCK" : (sSync ? "LOADING" : "NORMAL");
if (currStatus === "NORMAL") {
await sleep(600);
const finalSuggestions = document.querySelectorAll('.xra-results .xra-suggestion-wrap');
const finalCount = finalSuggestions.length;
if (finalCount > 0) {
console.log(`- Suggested: ${finalCount}`);
const randomIndex = Math.floor(Math.random() * finalCount);
console.log(`=> [${randomIndex + 1}]`);
const mainChipText = finalSuggestions[randomIndex].querySelector('.xra-chip-main');
if (mainChipText) {
mainChipText.click();
if (postId) {
addItemToStorage('processed_items', postId, currentUrl);
}
const totalDone = getStorageCount('processed_items');
const totalSkip = getStorageCount('skipped_items');
console.log(`=> Done [Total done: ${totalDone} | Total skip: ${totalSkip}]`);
}
retrySuccess = true;
}
break;
}
}
if (!retrySuccess) {
if (postId) {
addItemToStorage('skipped_items', postId, currentUrl, "Retry không thành công (0 result)");
}
const totalDone = getStorageCount('processed_items');
const totalSkip = getStorageCount('skipped_items');
console.log(`=> Skip [Total done: ${totalDone} | Total skip: ${totalSkip}]`);
}
refreshConsoleView();
actionCompleted = true;
break;
} else {
if (postId) {
addItemToStorage('skipped_items', postId, currentUrl, "Không tìm thấy nút sync/generate");
}
const totalDone = getStorageCount('processed_items');
const totalSkip = getStorageCount('skipped_items');
console.log(`=> Button not found -> Skip [Total done: ${totalDone} | Total skip: ${totalSkip}]`);
refreshConsoleView();
actionCompleted = true;
break;
}
}
}
await sleep(1000);
}
if (isUndefined) {
refreshConsoleView();
console.log(`${authorHandle} -> Status: UNDEFINED -> Click Home to refresh.`);
const homeNavBtn = document.querySelector('a[data-testid="AppTabBar_Home_Link"]');
if (homeNavBtn) {
homeNavBtn.click();
sessionStartTime = Date.now();
await sleep(4000);
continue;
}
}
history.back();
await sleep(3000);
window.scrollBy({ top: Math.floor(Math.random() * 400) + 300, behavior: 'smooth' });
await sleep(2000);
continue;
}
history.back();
await sleep(3000);
}
})();3 views