// ==UserScript==
// @name LMArena Purifier
// @namespace http://tampermonkey.net/
// @version 004
// @description 优化UI,主要是为了大家在LMARENA和匿名模型玩的时候被另外一个弱智模型影响,作者discord skuhrasr0plus1
// @author skuhrasr0plus1
// @match https://lmarena.ai/*
// @grant GM_addStyle
// @license MIT// @license MIT
// ==/UserScript==
(function() {
'use strict';
let purifiedContainer = null;
let purifiedChatArea = null;
let observer = null;
let selectedMode = null; // 'A' or 'B'
GM_addStyle(`
/* --- Variables & Theme (Elegant Dark) --- */
:root {
--purify-bg-primary: #121212; /* Deep Black for background */
--purify-bg-secondary: #1e1e1e; /* Slightly lighter for panels/AI bubbles */
--purify-accent: #007acc; /* Sophisticated Blue Accent (for User bubble/buttons) */
--purify-accent-hover: #005f99;
--purify-text-primary: #f0f0f0;
--purify-text-secondary: #b0b0b0;
--purify-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
--purify-radius: 12px; /* Softer corners */
}
/* --- Button Styling (Floating Selector) --- */
#purify-selector-buttons {
position: fixed;
bottom: 20px;
left: 20px;
z-index: 1000;
display: flex;
gap: 15px;
}
.purify-btn {
background-color: var(--purify-bg-secondary);
color: var(--purify-text-primary);
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 10px 20px;
cursor: pointer;
border-radius: var(--purify-radius);
font-weight: 600;
box-shadow: var(--purify-shadow);
transition: transform 0.2s ease, background-color 0.2s ease;
}
.purify-btn:hover {
background-color: var(--purify-accent);
transform: translateY(-2px); /* Slight lift effect */
}
/* --- Main Purified Container --- */
#purified-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: var(--purify-bg-primary);
color: var(--purify-text-primary);
z-index: 2000;
display: flex;
font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
}
/* --- Top Control Panel (Sleek) --- */
#purified-control-panel {
padding: 15px 30px;
background-color: var(--purify-bg-secondary);
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
display: flex;
justify-content: space-between; /* Space out elements */
align-items: center;
}
.control-group {
display: flex;
gap: 10px;
}
/* --- Chat Area (Readability Focused) --- */
#purified-chat-area {
flex-grow: 1;
overflow-y: auto;
padding: 30px 15px;
display: flex;
flex-direction: column-reverse;
max-width: 800px;
margin: 0 auto;
width: 100%;
}
/* --- Custom Scrollbar (Thin and subtle) --- */
#purified-chat-area::-webkit-scrollbar {
width: 6px;
}
#purified-chat-area::-webkit-scrollbar-track {
background: var(--purify-bg-primary);
}
#purified-chat-area::-webkit-scrollbar-thumb {
background-color: var(--purify-bg-secondary);
border-radius: 3px;
}
/* --- Input Area (Integrated) --- */
#purified-input-area {
padding: 20px 15px;
background-color: var(--purify-bg-primary);
/* Subtle border instead of heavy background change */
border-top: 1px solid rgba(255, 255, 255, 0.05);
z-index: 2001;
max-width: 800px;
margin: 0 auto;
width: 100%;
}
#purified-input-area textarea {
background-color: var(--purify-bg-secondary) !important;
color: var(--purify-text-primary) !important;
border-radius: var(--purify-radius) !important;
border: 1px solid rgba(255, 255, 255, 0.1) !important;
}
/* --- Message Bubbles (Modern Chat UI) --- */
.cloned-message {
margin-bottom: 20px;
padding: 12px 18px;
border-radius: 18px; /* Highly rounded */
line-height: 1.5;
display: block !important;
flex: none !important;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
/* User Message Bubble (Accent Color) */
.cloned-user {
background-color: var(--purify-bg-secondary);
color: var(--purify-text-primary);
align-self: flex-end;
max-width: 80%;
border-bottom-right-radius: 4px;
}
/* AI Message Bubble (Secondary Color) */
.cloned-ai {
background-color: var(--purify-bg-secondary);
color: var(--purify-text-primary);
align-self: flex-start;
max-width: 80%;
border-bottom-left-radius: 4px;
}
/* Ensure links inside messages are visible */
.cloned-message a {
color: #63b3ed !important;
text-decoration: none !important;
}
.cloned-message a:hover {
text-decoration: underline !important;
}
.cloned-message p, .cloned-message ol, .cloned-message ul {
margin-top: 0.5em !important;
margin-bottom: 0.5em !important;
}
/* --- Control Panel Buttons --- */
.control-btn {
background-color: transparent;
color: var(--purify-text-secondary);
border: 1px solid var(--purify-text-secondary);
padding: 6px 15px;
cursor: pointer;
border-radius: 50px; /* Pill shape */
font-size: 13px;
font-weight: 500;
transition: all 0.2s ease;
}
.control-btn:hover {
background-color: var(--purify-text-secondary);
color: var(--purify-bg-primary);
}
.control-btn.exit {
/* No specific color needed, keep it subtle */
}
.control-btn.end-chat {
border-color: #e53e3e;
color: #e53e3e;
}
.control-btn.end-chat:hover {
background-color: #e53e3e;
color: white;
}
/* --- Retry Button Styling (Subtle integration) --- */
.retry-btn {
background-color: rgba(255, 255, 255, 0.1);
color: var(--purify-text-secondary);
border: none;
padding: 5px 10px;
cursor: pointer;
border-radius: var(--purify-radius);
font-size: 12px;
font-weight: bold;
margin-top: 8px;
transition: background-color 0.2s;
}
.retry-btn:hover {
background-color: var(--purify-accent);
color: white;
}
`);
function findChatList() {
return document.querySelector('main ol[class*="flex-col-reverse"]');
}
function findChatInputBar() {
const main = document.querySelector('main');
if (!main) return null;
const textarea = main.querySelector('textarea');
if (textarea) {
return textarea.closest('main > div:last-child > div:last-child');
}
return document.querySelector('main > div:nth-child(2) > div:nth-child(3)');
}
function exitPurifiedMode() {
if (purifiedContainer) {
purifiedContainer.remove();
purifiedContainer = null;
purifiedChatArea = null;
}
if (observer) {
observer.disconnect();
observer = null;
}
if (window.purifyInputWatchdog) {
clearInterval(window.purifyInputWatchdog);
window.purifyInputWatchdog = null;
}
selectedMode = null;
const buttons = document.getElementById('purify-selector-buttons');
if (buttons) {
buttons.style.display = 'flex';
}
console.log('Exited purified mode');
}
function ensureInputBarPosition() {
if (!purifiedContainer || !purifiedChatArea) return;
const purifiedInputArea = document.getElementById('purified-input-area');
if (!purifiedInputArea) return;
if (purifiedInputArea.children.length === 0 || !document.body.contains(purifiedInputArea.children[0])) {
const chatInputBar = findChatInputBar();
if (chatInputBar) {
console.log("Purifier: 输入框丢失,重新捕获。");
purifiedInputArea.innerHTML = '';
purifiedInputArea.appendChild(chatInputBar);
}
}
}
function findEndChatButton() {
let xpathPath;
if (selectedMode === 'A') {
xpathPath = '/html/body/div[1]/div[2]/div[2]/div/div[2]/main/div[2]/div[1]/div[2]/button[1]';
} else if (selectedMode === 'B') {
xpathPath = '/html/body/div[1]/div[2]/div[2]/div/div[2]/main/div[2]/div[1]/div[2]/button[4]';
} else {
console.error('No mode selected');
return null;
}
const endChatButton = document.evaluate(
xpathPath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
return endChatButton;
}
function createControlPanel() {
const controlPanel = document.createElement('div');
controlPanel.id = 'purified-control-panel';
const modeLabel = document.createElement('span');
modeLabel.textContent = `Model: ${selectedMode}`;
modeLabel.style.color = '#e2e8f0';
modeLabel.style.fontWeight = 'bold';
const exitBtn = document.createElement('button');
exitBtn.textContent = 'Exit Purified Mode';
exitBtn.className = 'control-btn exit';
exitBtn.onclick = exitPurifiedMode;
const endChatBtn = document.createElement('button');
endChatBtn.textContent = 'openBox';
endChatBtn.className = 'control-btn end-chat';
endChatBtn.onclick = function() {
const originalEndChatButton = findEndChatButton();
if (originalEndChatButton) {
originalEndChatButton.click();
console.log(`End chat button clicked for mode ${selectedMode}`);
} else {
console.error(`Could not find end chat button for mode ${selectedMode}`);
}
};
controlPanel.appendChild(modeLabel);
controlPanel.appendChild(exitBtn);
controlPanel.appendChild(endChatBtn);
return controlPanel;
}
function setupPurifiedInterface() {
if (!purifiedContainer) {
purifiedContainer = document.createElement('div');
purifiedContainer.id = 'purified-container';
const controlPanel = createControlPanel();
purifiedContainer.appendChild(controlPanel);
purifiedChatArea = document.createElement('div');
purifiedChatArea.id = 'purified-chat-area';
const purifiedInputArea = document.createElement('div');
purifiedInputArea.id = 'purified-input-area';
purifiedContainer.appendChild(purifiedChatArea);
purifiedContainer.appendChild(purifiedInputArea);
document.body.appendChild(purifiedContainer);
ensureInputBarPosition();
if (!window.purifyInputWatchdog) {
window.purifyInputWatchdog = setInterval(ensureInputBarPosition, 500);
}
const chatInputBar = findChatInputBar();
if (chatInputBar) {
purifiedInputArea.appendChild(chatInputBar);
} else {
console.warn("Purifier: Could not find the chat input bar.");
}
}
}
function findRetryButton() {
let xpathPath;
if (selectedMode === 'A') {
xpathPath = '/html/body/div[1]/div[2]/div[2]/div/div[2]/main/div[1]/div/div/ol/div[2]/div[1]/div[1]/div[1]/div[2]/div[3]/button[1]';
} else if (selectedMode === 'B') {
xpathPath = '/html/body/div[1]/div[2]/div[2]/div/div[2]/main/div[1]/div/div/ol/div[2]/div[2]/div[1]/div[1]/div[2]/div[3]/button[1]';
} else {
console.error('No mode selected');
return null;
}
const retryButton = document.evaluate(
xpathPath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
if (retryButton) {
return retryButton;
}
const chatList = findChatList();
if (!chatList) return null;
const lastAIMessageBlock = chatList.querySelector('div[data-sentry-component="AIMessage"]:last-of-type');
if (lastAIMessageBlock) {
const abChildren = lastAIMessageBlock.querySelectorAll('div[class*="relative flex-1"]');
if (abChildren.length >= 2) {
const targetChild = selectedMode === 'A' ? abChildren[0] : abChildren[1];
return targetChild.querySelector('button[aria-label*="retry"], button[title*="retry"], button:has(svg)');
}
}
return null;
}
function createRetryButton() {
const retryBtn = document.createElement('button');
retryBtn.textContent = `Retry ${selectedMode}`;
retryBtn.className = 'retry-btn';
retryBtn.onclick = function() {
const originalRetryButton = findRetryButton();
if (originalRetryButton) {
originalRetryButton.click();
console.log(`Retry button ${selectedMode} clicked`);
} else {
console.error(`Could not find original retry button for mode ${selectedMode}`);
}
};
return retryBtn;
}
function syncChatContent() {
const chatList = findChatList();
if (!chatList || !purifiedChatArea) return;
purifiedChatArea.innerHTML = '';
const messages = Array.from(chatList.children);
messages.forEach((message, index) => {
if (message.className.includes('h-[')) {
return;
}
let elementToClone = null;
let cloneType = 'cloned-history';
const isUserMessage = message.getAttribute('data-sentry-component') === 'UserMessage';
const potentialABChildren = message.querySelectorAll('div[class*="relative flex-1"]');
const isABBlock = potentialABChildren.length === 2;
if (isUserMessage) {
elementToClone = message;
cloneType = 'cloned-user';
} else if (isABBlock) {
if (selectedMode === 'A') {
elementToClone = potentialABChildren[0];
} else if (selectedMode === 'B') {
elementToClone = potentialABChildren[1];
}
cloneType = 'cloned-ai';
} else if (potentialABChildren.length >= 1 || message.querySelector('div[class*="flex-col w-full"]')) {
elementToClone = message;
cloneType = 'cloned-ai';
}
if (elementToClone) {
const clonedElement = elementToClone.cloneNode(true);
clonedElement.classList.remove('flex-1', 'min-w-0', 'w-full', 'flex', 'flex-col', 'relative');
clonedElement.style.width = 'auto';
clonedElement.classList.add('cloned-message', cloneType);
if (cloneType === 'cloned-ai') {
const retryBtn = createRetryButton();
clonedElement.appendChild(retryBtn);
}
purifiedChatArea.appendChild(clonedElement);
}
});
}
function startPurification(mode) {
selectedMode = mode;
console.log(`Starting purification mode: ${mode}`);
const buttons = document.getElementById('purify-selector-buttons');
if (buttons) buttons.style.display = 'none';
setupPurifiedInterface();
const chatList = findChatList();
if (!chatList) {
console.error("Purifier: Could not find the main chat list (<ol>).");
return;
}
syncChatContent();
if (observer) observer.disconnect();
observer = new MutationObserver((mutations) => {
if (window.syncTimeout) clearTimeout(window.syncTimeout);
window.syncTimeout = setTimeout(syncChatContent, 50);
});
observer.observe(chatList, {
childList: true,
subtree: true,
characterData: true,
attributes: false
});
}
function createButtons() {
if (document.getElementById('purify-selector-buttons')) return;
const buttonContainer = document.createElement('div');
buttonContainer.id = 'purify-selector-buttons';
const buttonA = document.createElement('button');
buttonA.textContent = 'Purify A (Left)';
buttonA.className = 'purify-btn';
buttonA.onclick = () => startPurification('A');
const buttonB = document.createElement('button');
buttonB.textContent = 'Purify B (Right)';
buttonB.className = 'purify-btn';
buttonB.onclick = () => startPurification('B');
buttonContainer.appendChild(buttonA);
buttonContainer.appendChild(buttonB);
document.body.appendChild(buttonContainer);
}
const waitForLoad = setInterval(() => {
if (findChatList() && findChatInputBar()) {
if (!document.getElementById('purify-selector-buttons')){
createButtons();
}
if (purifiedContainer && purifiedContainer.style.display !== 'none') {
} else {
const buttons = document.getElementById('purify-selector-buttons');
if (buttons) buttons.style.display = 'flex';
}
}
}, 1000);
})();