// ==UserScript==
// @name DeepSeek繁忙自动点击重试
// @namespace http://tampermonkey.net/
// @version 2025-02-15
// @license MIT
// @description DeepSeek提示繁忙,自动点击重试,并显示操作状态通知
// @author Dingning
// @include *://chat.deepseek.com/*
// @icon https://registry.npmmirror.com/@lobehub/icons-static-png/latest/files/dark/deepseek-color.png
// @grant none
// ==/UserScript==
(function () {
"use strict";
// 配置参数
let CHECK_INTERVAL = 1;
let retryDelay = 1;
let maxRetryDelay = 60;
let retryCount = 0;
let threshold = 5;
let normalDelayIncrement = 2;
let fastFrequencyDelayIncrement = 30;
let retryTimeoutId = null;
let configPanel;
let countdownTimer = null;
let remainingTime = 0;
let isMonitoring = true;
let isPanelExpanded = true;
// 添加全局样式
const addGlobalStyles = () => {
const style = document.createElement('style');
style.textContent = `
input::placeholder { color: #999!important; opacity: 1!important; }
input { color: #333!important; }
.toggle-btn.paused { background: #ff3b30!important; }
.collapse-btn {
padding: 6px 10px;
border: none;
border-radius: 4px;
background: #007aff;
color: white;
cursor: pointer;
font-size: 12px;
transition: background 0.2s ease;
}
.collapse-btn:hover {
background: #0063cc;
}
`;
document.head.appendChild(style);
};
const checkAndRetry = () => {
if (!isMonitoring) return;
const loadingElements = document.querySelectorAll(".ds-loading");
const hasLoading = loadingElements.length > 0;
const contentList = document.querySelectorAll(".ds-markdown");
let hasBusyMessage = false;
const busyMessages = [
"<p>服务器繁忙,请稍后再试。</p>",
"<p>The server is busy. Please try again later.</p>",
];
const lastContent = contentList.length > 0? contentList[contentList.length - 1].innerHTML : "";
if (busyMessages.includes(lastContent)) hasBusyMessage = true;
if (!hasLoading &&!hasBusyMessage) {
if (retryCount > 0) createNotification("已重置重试次数和重试延迟", "success");
retryCount = 0;
retryDelay = 1;
if (configPanel) configPanel.style.display = "none";
} else if (hasBusyMessage) {
if (configPanel) {
configPanel.style.display = "block";
updateStatusDisplay();
}
}
if (hasBusyMessage &&!retryTimeoutId) {
startCountdown(retryDelay);
retryTimeoutId = setTimeout(() => {
const retryBtn = Array.from(document.querySelectorAll(".ds-icon-button"))
.reverse()
.find(btn => btn.querySelector("svg #重新生成"));
if (retryBtn) {
retryBtn.click();
retryCount++;
createNotification(`已点击重试,重试次数: ${retryCount}`, "success");
const toastContents = document.querySelectorAll(".ds-toast__content");
for (const toast of toastContents) {
if (toast.textContent === "你发送消息的频率过快,请稍后再发") {
retryDelay = Math.min(retryDelay + fastFrequencyDelayIncrement, maxRetryDelay);
createNotification(`检测到频率过快,延迟调整为 ${retryDelay} 秒`, "warning");
break;
}
}
if (retryCount >= threshold) {
retryDelay = Math.min(retryDelay + normalDelayIncrement, maxRetryDelay);
createNotification(`重试次数过多,延迟调整为 ${retryDelay} 秒`, "warning");
}
}
clearTimeout(retryTimeoutId);
retryTimeoutId = null;
}, retryDelay * 1000);
}
};
// 通知系统
const createNotificationContainer = () => {
const container = document.createElement("div");
container.id = "retry-notifications";
container.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
display: flex;
flex-direction: column;
gap: 10px;
max-width: 300px;
`;
document.body.appendChild(container);
return container;
};
const createNotification = (message, type = "info") => {
const notification = document.createElement("div");
notification.className = `retry-notification ${type}`;
notification.style.cssText = `
padding: 12px 16px;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
font-size: 14px;
color: #333;
opacity: 0;
transform: translateX(100%);
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
border-left: 4px solid ${{
success: "#52c41a",
warning: "#faad14",
info: "#1890ff"
}[type]};
`;
const icon = document.createElement("span");
icon.textContent = { success: "✅", warning: "⚠️", info: "ℹ️" }[type];
notification.appendChild(icon);
const text = document.createElement("span");
text.textContent = message;
notification.appendChild(text);
const container = document.getElementById("retry-notifications") || createNotificationContainer();
container.appendChild(notification);
setTimeout(() => {
notification.style.opacity = "1";
notification.style.transform = "translateX(0)";
}, 50);
setTimeout(() => {
notification.style.opacity = "0";
setTimeout(() => notification.remove(), 300);
}, 3000);
};
// 配置面板
const createConfigPanel = () => {
const panel = document.createElement("div");
panel.id = "config-panel";
panel.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
z-index: 10000;
background: rgba(255, 255, 255, 0.95);
color: #414158;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
padding: 20px;
display: flex;
flex-direction: column;
gap: 16px;
max-width: 300px;
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
display: none;
`;
// 折叠按钮
const collapseBtn = document.createElement("button");
collapseBtn.textContent = isPanelExpanded? "折叠" : "展开";
collapseBtn.className = "collapse-btn";
collapseBtn.addEventListener("click", () => {
isPanelExpanded =!isPanelExpanded;
collapseBtn.textContent = isPanelExpanded? "折叠" : "展开";
if (isPanelExpanded) {
panel.style.height = "auto";
panel.style.padding = "20px";
buttonContainer.style.marginTop = "10px";
saveButton.style.display = "block";
panel.querySelectorAll('.config-item').forEach(item => item.style.display = "flex");
} else {
panel.style.height = "auto";
panel.style.padding = "10px";
buttonContainer.style.marginTop = "0px";
saveButton.style.display = "none";
panel.querySelectorAll('.config-item').forEach(item => item.style.display = "none");
}
});
panel.appendChild(collapseBtn);
// 状态显示
const statusContainer = document.createElement("div");
statusContainer.style.cssText = `
background: rgba(245, 245, 247, 0.8);
border-radius: 8px;
padding: 12px;
min-width: 100px;
`;
const createStatusRow = (title, value, id) => {
const row = document.createElement("div");
row.style.cssText = `
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
font-size: 13px;
`;
const titleSpan = document.createElement("span");
titleSpan.textContent = title;
titleSpan.style.color = "#666";
const valueSpan = document.createElement("span");
valueSpan.id = id;
valueSpan.textContent = value;
valueSpan.style.cssText = `
font-weight: 500;
color: #1a1a1a;
`;
row.append(titleSpan, valueSpan);
return row;
};
statusContainer.append(
createStatusRow("检测状态", isMonitoring? "运行中" : "已暂停", "monitor-status"),
createStatusRow("当前重试次数", retryCount, "retry-count"),
createStatusRow("下次尝试", "等待中", "countdown")
);
panel.appendChild(statusContainer);
// 配置项
const createInputRow = (label, value) => {
const row = document.createElement("div");
row.style.cssText = `
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
`;
const labelEl = document.createElement("label");
labelEl.textContent = label;
labelEl.style.cssText = `
font-size: 13px;
color: #666;
flex: 1;
`;
const input = document.createElement("input");
input.type = "number";
input.value = value;
input.placeholder = "输入数值";
input.style.cssText = `
width: 80px;
padding: 6px 8px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 13px;
background: rgba(255, 255, 255, 0.8);
`;
row.append(labelEl, input);
return { row, input };
};
const configs = [
{ label: "检查间隔 (秒)", value: CHECK_INTERVAL, action: v => CHECK_INTERVAL = v },
{ label: "初始延迟 (秒)", value: retryDelay, action: v => retryDelay = v },
{ label: "最大延迟 (秒)", value: maxRetryDelay, action: v => maxRetryDelay = v },
{ label: "重试阈值", value: threshold, action: v => threshold = v },
{ label: "正常增量 (秒)", value: normalDelayIncrement, action: v => normalDelayIncrement = v },
{ label: "过快增量 (秒)", value: fastFrequencyDelayIncrement, action: v => fastFrequencyDelayIncrement = v }
];
configs.forEach(({ label, value, action }, index) => {
const { row, input } = createInputRow(label, value);
row.classList.add('config-item');
if (!isPanelExpanded) {
row.style.display = "none";
}
input.addEventListener("input", () => {
action(parseInt(input.value) || 1);
clearInterval(checkIntervalId);
checkIntervalId = setInterval(checkAndRetry, CHECK_INTERVAL * 1000);
});
panel.appendChild(row);
});
// 控制按钮和保存按钮容器
const buttonContainer = document.createElement("div");
buttonContainer.style.cssText = `
margin-top: 10px;
display: flex;
gap: 10px;
`;
const toggleBtn = document.createElement("button");
toggleBtn.textContent = "暂停检测";
toggleBtn.className = "toggle-btn";
toggleBtn.style.cssText = `
flex: 1;
padding: 10px;
border: none;
border-radius: 8px;
background: #007aff;
color: white;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
`;
toggleBtn.addEventListener("click", () => {
isMonitoring =!isMonitoring;
toggleBtn.textContent = isMonitoring? "暂停检测" : "继续检测";
toggleBtn.classList.toggle("paused",!isMonitoring);
createNotification(isMonitoring? "已恢复自动检测" : "已暂停自动检测", isMonitoring? "success" : "warning");
if (isMonitoring) {
clearInterval(checkIntervalId);
checkIntervalId = setInterval(checkAndRetry, CHECK_INTERVAL * 1000);
} else {
clearInterval(checkIntervalId);
clearTimeout(retryTimeoutId);
retryTimeoutId = null;
remainingTime = 0;
}
updateStatusDisplay();
});
buttonContainer.appendChild(toggleBtn);
// 打开配置按钮(在折叠状态下显示)
const openConfigBtn = document.createElement("button");
openConfigBtn.textContent = "打开配置";
openConfigBtn.style.cssText = `
padding: 10px 18px;
border: none;
border-radius: 8px;
background: #007aff;
color: white;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background 0.2s ease;
`;
openConfigBtn.addEventListener("click", () => {
isPanelExpanded = true;
collapseBtn.textContent = "折叠";
panel.style.height = "auto";
panel.style.padding = "20px";
panel.querySelectorAll('.config-item').forEach(item => item.style.display = "block");
});
// 保存按钮
const saveButton = document.createElement("button");
saveButton.textContent = "保存配置";
saveButton.style.cssText = `
padding: 10px 18px;
border: none;
border-radius: 8px;
background: #007aff;
color: white;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background 0.2s ease;
`;
saveButton.addEventListener("mouseenter", () => saveButton.style.background = "#0063cc");
saveButton.addEventListener("mouseleave", () => saveButton.style.background = "#007aff");
saveButton.addEventListener("click", () => createNotification("配置已保存", "success"));
if (isPanelExpanded) {
buttonContainer.appendChild(saveButton);
} else {
buttonContainer.appendChild(openConfigBtn);
}
panel.appendChild(buttonContainer);
document.body.appendChild(panel);
return panel;
};
// 倒计时管理
const startCountdown = (seconds) => {
clearInterval(countdownTimer);
remainingTime = seconds;
countdownTimer = setInterval(() => {
remainingTime = Math.max(0, remainingTime - 1);
updateStatusDisplay();
if (remainingTime <= 0) clearInterval(countdownTimer);
}, 1000);
};
const updateStatusDisplay = () => {
document.getElementById("countdown").textContent =
remainingTime > 0? `${remainingTime}秒` : "等待中";
document.getElementById("retry-count").textContent = retryCount;
document.getElementById("monitor-status").textContent =
isMonitoring? "运行中" : "已暂停";
};
// 初始化
addGlobalStyles();
let checkIntervalId = setInterval(checkAndRetry, CHECK_INTERVAL * 1000);
configPanel = createConfigPanel();
window.addEventListener("beforeunload", () => {
clearInterval(checkIntervalId);
clearInterval(countdownTimer);
});
})();