JustPaste
HomeCategoriesAboutDonateContactTerms of UsePrivacy Policy
JustPaste

Free online notepad — write and share instantly

Navigate

  • Home
  • Timeline
  • Categories

Info

  • About
  • Donate
  • Contact

Legal

  • Terms of Use
  • Privacy Policy

© 2026 JustPaste.app. All rights reserved.

Made with ♥ by JustPaste

Untitled Page | JustPaste.app
about 1 hour ago3 views
👨‍💻Programming

Untitled Page

(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);
  }
})();
← Back to timeline