// @ts-check
'use strict';
// ==UserScript==
// @name Deepseek实时监控
// @version 1.1.0
// @description 实时监控并显示Deepseek的回答过程,自动保存被屏蔽的内容。支持历史记录、导出和深色模式。
// @match https://chat.deepseek.com/*
// @grant none
// @namespace https://gf.qytechs.cn/zh-CN/users/151723-cyborg-sexy
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 存储系统
let latestChatNum = 2;
let previousContent = '';
let longestContent = '';
let historyContent = [];
// UI组件创建
const pluginUI = document.createElement('div');
pluginUI.id = 'plugin-ui';
pluginUI.style.cssText = `
position: fixed;
top: 0;
right: 20px;
width: 300px;
height: 100%;
overflow-y: scroll;
background-color: #f9f9f9;
color: #333;
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
z-index: 9999;
transition: right 0.3s ease;
font-family: system-ui, -apple-system, sans-serif;
`;
// 创建按钮的通用函数
function createButton(id, top, text, title) {
const button = document.createElement('button');
button.id = id;
button.style.cssText = `
position: fixed;
top: ${top}px;
right: 330px;
width: 40px;
height: 40px;
background-color: #444;
color: #fff;
border: none;
border-radius: 50%;
font-size: 16px;
z-index: 10000;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
`;
button.textContent = text;
button.title = title;
return button;
}
// 创建所有按钮
const returnButton = createButton('return-button', 10, '❌', 'Clear Interface');
const toggleButton = createButton('toggle-button', 60, '➡️', 'Toggle Sidebar');
const copyButton = createButton('copy-button', 110, '📋', 'Copy Content');
const historyButton = createButton('history-button', 160, '🕒', 'View History');
const exportButton = createButton('export-button', 210, '💾', 'Export History');
// 按钮事件处理
returnButton.addEventListener('click', () => {
pluginUI.innerHTML = '';
});
toggleButton.addEventListener('click', () => {
const isVisible = pluginUI.style.right === '20px';
const newRight = isVisible ? '-300px' : '20px';
const buttonRight = isVisible ? '20px' : '330px';
[pluginUI.style.right, returnButton.style.right, toggleButton.style.right,
copyButton.style.right, historyButton.style.right, exportButton.style.right] =
[newRight, buttonRight, buttonRight, buttonRight, buttonRight, buttonRight];
toggleButton.textContent = isVisible ? '⬅️' : '➡️';
});
copyButton.addEventListener('click', async () => {
try {
await navigator.clipboard.writeText(pluginUI.innerText);
showNotification('内容已复制到剪贴板!', 'success');
} catch {
showNotification('复制失败,请重试', 'error');
}
});
historyButton.addEventListener('click', () => {
pluginUI.innerHTML = '';
updateHistoryUI();
});
exportButton.addEventListener('click', () => {
exportHistory();
});
// 通知系统
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
padding: 10px 20px;
border-radius: 5px;
color: white;
background-color: ${type === 'success' ? '#4caf50' : '#f44336'};
z-index: 10001;
animation: fadeInOut 2s ease forwards;
`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 2000);
}
// 内容格式化
function formatContent(content) {
content = content.replace(/<[^>]+>/g, '');
content = content.replace(/\s+/g, ' ').trim();
return `[${new Date().toLocaleString()}]\n${content}\n${'='.repeat(30)}\n`;
}
// 导出功能
function exportHistory() {
const exportData = {
timestamp: new Date().toISOString(),
history: historyContent
};
const blob = new Blob([JSON.stringify(exportData, null, 2)],
{type: 'application/json'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `deepseek-history-${new Date().toISOString().slice(0,10)}.json`;
a.click();
URL.revokeObjectURL(url);
showNotification('历史记录已导出', 'success');
}
// 改进的内容获取函数
function getLatestChatContent() {
try {
let retries = 1;
let element = null;
const getSelector = (num) => `#root > div > div.c3ecdb44 > div.f2eea526 > div > div.b83ee326 > div > div > div.dad65929 > div:nth-child(${num})`;
while (retries >= 0) {
while (true) {
const selector = getSelector(latestChatNum);
element = document.querySelector(selector);
if (!element) break;
latestChatNum += 2;
}
latestChatNum -= 2;
element = document.querySelector(getSelector(latestChatNum));
if (!element) {
console.log('Cannot find the latest chat');
latestChatNum = 2;
retries--;
if (retries < 0) return;
} else {
break;
}
}
// @ts-ignore
const chatContentElement = element.querySelector('div.ds-markdown.ds-markdown--block');
// @ts-ignore
const thinkingContentElement = element.querySelector('div.edb250b1 > div.e1675d8b');
let currentContent = '';
if (thinkingContentElement) {
const paragraphs = thinkingContentElement.querySelectorAll('p');
paragraphs.forEach(p => {
currentContent += p.innerText + '\n';
});
}
if (chatContentElement) {
currentContent += chatContentElement.innerHTML;
}
if (currentContent) {
// 检查是否包含中断文本
if (currentContent.includes("你好,这个问题我暂时无法回答")) {
if (longestContent) {
// 保存之前的内容到历史记录
historyContent.push(longestContent);
// 显示保存提示
showNotification('已保存之前的回答', 'success');
// 重置最长内容
longestContent = '';
}
return;
}
// 格式化当前内容
const formattedContent = formatContent(currentContent);
// 更新最长内容
if (currentContent.length > (longestContent?.length || 0)) {
longestContent = formattedContent;
}
// 实时显示当前内容
pluginUI.innerHTML = formattedContent;
// 更新前一次内容
previousContent = currentContent;
}
} catch (error) {
console.error('Error in getLatestChatContent:', error);
}
}
// 历史记录UI更新
function updateHistoryUI() {
historyContent.forEach((content, index) => {
const historyItem = document.createElement('div');
historyItem.style.cssText = `
border-bottom: 1px solid #ccc;
padding: 10px;
cursor: pointer;
transition: background-color 0.2s ease;
margin-bottom: 5px;
`;
historyItem.textContent = `[${index + 1}] ${content.length > 50 ? content.substring(0, 50) + '...' : content}`;
historyItem.addEventListener('click', () => {
pluginUI.innerHTML = content;
});
historyItem.addEventListener('mouseover', () => {
historyItem.style.backgroundColor = 'rgba(0,0,0,0.05)';
});
historyItem.addEventListener('mouseout', () => {
historyItem.style.backgroundColor = 'transparent';
});
pluginUI.appendChild(historyItem);
});
}
// 主题更新
function updateTheme() {
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const theme = {
bg: isDark ? '#333' : '#f9f9f9',
color: isDark ? '#fff' : '#333',
border: isDark ? '#555' : '#ccc',
buttonBg: isDark ? '#666' : '#888'
};
pluginUI.style.backgroundColor = theme.bg;
pluginUI.style.color = theme.color;
pluginUI.style.border = `1px solid ${theme.border}`;
[returnButton, toggleButton, copyButton, historyButton, exportButton].forEach(button => {
button.style.backgroundColor = theme.buttonBg;
button.style.color = '#fff';
});
}
// 初始化
document.body.append(pluginUI, returnButton, toggleButton, copyButton, historyButton, exportButton);
updateTheme();
// 设置初始收起状态
pluginUI.style.right = '-300px';
[returnButton, toggleButton, copyButton, historyButton, exportButton].forEach(button => {
button.style.right = '20px';
});
toggleButton.textContent = '⬅️';
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateTheme);
// 观察器设置
const observer = new MutationObserver(getLatestChatContent);
const config = { childList: true, subtree: true, characterData: true };
window.addEventListener('load', () => {
setTimeout(() => {
const targetNode = document.querySelector('#root');
if (targetNode) {
observer.observe(targetNode, config);
showNotification('DeepSeek监控已启动', 'success');
} else {
console.log('Cannot find the target node');
}
}, 500);
});
})();