DeepSeek Auto-Retry with Text & SVG Detection

Auto retry when server busy detected by text or SVG icon, with toggle UI and cooldown.

As of 2025-06-01. See the latest version.

// ==UserScript==
// @name         DeepSeek Auto-Retry with Text & SVG Detection
// @version      1.4
// @description  Auto retry when server busy detected by text or SVG icon, with toggle UI and cooldown.
// @author       Blakken
// @match        https://chat.deepseek.com/*
// @grant        none
// @license      MIT
// @namespace https://greatest.deepsurf.us/users/1477546
// ==/UserScript==

(function() {
  "use strict";

  // Config
  const config = {
    autoRetryEnabled: true,
    cooldown: 15000, // 15 secondes entre retries
    interval: 1000, // vérification toutes les 1 seconde
    errorTextToDetect: "Server busy, please try again later.",
    // Le SVG path exact pour la détection du bouton retry (tu peux adapter)
    retrySvgPath: "M12 .5C18.351.5 23.5 5.649 23.5 12S18.351 23.5 12 23.5.5 18.351.5 12 5.649.5 12 .5zm-.225 4.8a.7.7 0 0 0-.528.224.703.703 0 0 0-.213.517.84.84 0 0 0 .056.304c.037.09.087.168.146.235l.809.831a.782.782 0 0 0-.147-.01 1.112 1.112 0 0 0-.157-.012 4.69 4.69 0 0 0-2.436.673 5.26 5.26 0 0 0-1.82 1.832c-.456.763-.685 1.617-.685 2.56 0 .966.232 1.845.696 2.639A5.33 5.33 0 0 0 9.36 16.99c.779.464 1.648.697 2.606.697.95 0 1.816-.233 2.595-.697a5.326 5.326 0 0 0 1.875-1.886 5.03 5.03 0 0 0 .696-2.606.716.716 0 0 0-.247-.55.754.754 0 0 0-.55-.236.78.78 0 0 0-.573.235.731.731 0 0 0-.236.551 3.46 3.46 0 0 1-.483 1.808c-.314.539-.741.97-1.28 1.292a3.44 3.44 0 0 1-1.797.482 3.44 3.44 0 0 1-1.797-.482 3.679 3.679 0 0 1-1.291-1.292 3.521 3.521 0 0 1-.472-1.808c0-.659.158-1.258.472-1.797a3.588 3.588 0 0 1 1.29-1.28 3.44 3.44 0 0 1 1.798-.484c.164 0 .3.008.404.023l-1.111 1.112a.722.722 0 0 0-.225.528c0 .21.07.386.213.528a.718.718 0 0 0 1.033-.012l2.246-2.246a.66.66 0 0 0 .203-.527.753.753 0 0 0-.203-.54l-2.223-2.268a.847.847 0 0 0-.247-.169.62.62 0 0 0-.28-.067z",
  };

  let lastRetryTime = 0;
  let retryCount = 0;

  // Affiche le compteur visible sur la page
  function createCounterUI() {
    let ui = document.getElementById("autoRetryCounterUI");
    if (ui) return ui;

    ui = document.createElement("div");
    ui.id = "autoRetryCounterUI";
    ui.style.position = "fixed";
    ui.style.bottom = "40px";
    ui.style.right = "20px";
    ui.style.padding = "8px 12px";
    ui.style.backgroundColor = "rgba(0,0,0,0.7)";
    ui.style.color = "#fff";
    ui.style.fontSize = "14px";
    ui.style.borderRadius = "6px";
    ui.style.zIndex = "999999";
    ui.style.fontFamily = "Arial, sans-serif";
    ui.style.userSelect = "none";
    ui.style.cursor = "default";
    document.body.appendChild(ui);
    return ui;
  }

  // Met à jour le texte du compteur
  function updateCounterUI() {
    const ui = createCounterUI();
    ui.textContent = `Auto-Retry Count: ${retryCount} (Status: ${config.autoRetryEnabled ? "ON" : "OFF"})`;
  }

  // Création du toggle pour activer/désactiver l’auto retry
  function createToggleUI() {
    let toggle = document.getElementById("autoRetryToggleUI");
    if (toggle) return toggle;

    toggle = document.createElement("div");
    toggle.id = "autoRetryToggleUI";
    toggle.style.position = "fixed";
    toggle.style.bottom = "10px";
    toggle.style.right = "20px";
    toggle.style.backgroundColor = "rgba(0,0,0,0.7)";
    toggle.style.color = "#fff";
    toggle.style.padding = "6px 12px";
    toggle.style.borderRadius = "6px";
    toggle.style.zIndex = "999999";
    toggle.style.fontFamily = "Arial, sans-serif";
    toggle.style.userSelect = "none";

    const label = document.createElement("label");
    label.style.cursor = "pointer";
    label.style.userSelect = "none";

    const checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.checked = config.autoRetryEnabled;
    checkbox.style.marginRight = "6px";
    checkbox.addEventListener("change", () => {
      config.autoRetryEnabled = checkbox.checked;
      updateCounterUI();
      console.log(`[AutoRetry] Auto-Retry turned ${config.autoRetryEnabled ? "ON" : "OFF"}`);
    });

    label.appendChild(checkbox);
    label.appendChild(document.createTextNode("Auto-Retry"));
    toggle.appendChild(label);
    document.body.appendChild(toggle);

    return toggle;
  }

  // Trouve le bouton retry en détectant la présence du SVG spécifique (path)
  function findRetryButton() {
    // On cherche tous les boutons svg avec un path
    const buttons = document.querySelectorAll("button, div.ds-icon-button, div");
    for (const btn of buttons) {
      const svg = btn.querySelector("svg path");
      if (!svg) continue;
      const d = svg.getAttribute("d");
      if (!d) continue;
      if (d.trim() === config.retrySvgPath.trim()) {
        return btn;
      }
    }
    return null;
  }

  // Vérifie si le message d’erreur "Server busy" est visible dans la page
  function isServerBusyDetected() {
    // Détecte la présence du texte d’erreur dans les spans ou divs
    const elementsWithError = Array.from(document.querySelectorAll("span, div"))
      .filter(el => el.textContent.trim() === config.errorTextToDetect);

    if (elementsWithError.length > 0) {
      return true;
    }

    // Ou détecte la présence du SVG d'icône serveur busy visible
    // (cette fonction est ici si tu veux la double détection)
    const svgPaths = document.querySelectorAll("svg path");
    for (const path of svgPaths) {
      if (path.getAttribute("d")?.trim() === config.retrySvgPath.trim()) {
        return true;
      }
    }

    return false;
  }

  // Tente le retry si conditions OK (cooldown, autoRetryEnabled, erreur détectée)
  function tryAutoRetry() {
    if (!config.autoRetryEnabled) return;

    if (!isServerBusyDetected()) return;

    const now = Date.now();
    if (now - lastRetryTime < config.cooldown) return;

    const btn = findRetryButton();
    if (!btn) {
      console.log("[AutoRetry] Retry button not found.");
      return;
    }

    btn.click();
    retryCount++;
    lastRetryTime = now;
    updateCounterUI();
    console.log("[AutoRetry] Retry clicked. Count:", retryCount);
  }

  // Initialisation
  function initialize() {
    createCounterUI();
    createToggleUI();
    updateCounterUI();
    setInterval(tryAutoRetry, config.interval);
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initialize);
  } else {
    initialize();
  }

})();