您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Merges consecutive chat messages from the same user in Torn.com, with customizable background colors and options. Supports bubble and classic mode.
// ==UserScript== // @name Anti Bubble Spam // @namespace http://tampermonkey.net/ // @version 6.0 // @description Merges consecutive chat messages from the same user in Torn.com, with customizable background colors and options. Supports bubble and classic mode. // @author Elaine [2047176] // @match https://www.torn.com/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @license MIT // ==/UserScript== (function() { 'use strict'; // --- Konfiguration --- const SCRIPT_ID_PREFIX = 'antiBubbleSpam_'; const CHAT_ROOT_ID = 'chatRoot'; const MESSAGE_LIST_SELECTOR = 'div[class*="list___"]'; const MESSAGE_ITEM_SELECTOR = 'div[class*="item___"]'; const MESSAGE_ROOT_SELECTOR = `div[class*="list___"] > div[class^="root___"]`; const MESSAGE_BOX_SELECTOR = `div[class^="box___"]`; const MESSAGE_TEXT_CONTAINER_SELECTOR = `p[class*="message___"], span[class*="message___"]`; const SENDER_LINK_SELECTOR = `a[href*="/profiles.php?XID="][class*="sender___"]`; const SENDER_CONTAINER_SELECTOR_BUBBLE = `span[class*="senderContainer___"]`; const SELF_MESSAGE_CLASS_PART_BUBBLE = 'self___'; const TIMESTAMP_DIVIDER_SELECTOR = `div[class*="messageGroupTimestamp___"]`; const DATA_ORIGINAL_HTML_ATTR = 'data-original-html'; const SETTINGS_PANEL_SELECTOR = `#settings_panel div[class*="content___"]`; const CLASSIC_MODE_LIST_CLASS = 'classic___HVCmX'; const NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS = 'abs-no-newline-bubble-agg'; const NO_NEWLINE_FIRST_CLASSIC_AGGREGATOR_CLASS = 'abs-no-newline-classic-agg'; const DEFAULT_SETTINGS = { bgColor1_rgb: "0,0,0", bgColor1_alpha: 0.1, bgColor2_rgb: "255,255,255", bgColor2_alpha: 0.05, enabled: true, startFirstMessageOnNewLine: true, useAlternatingBackgrounds: true }; let currentSettings = { ...DEFAULT_SETTINGS }; let styleElement = null; let colorSetting1Div = null; let colorSetting2Div = null; function isClassicMode(messageElementOrList) { const listElement = messageElementOrList.matches(MESSAGE_LIST_SELECTOR) ? messageElementOrList : messageElementOrList.closest(MESSAGE_LIST_SELECTOR); return listElement ? listElement.classList.contains(CLASSIC_MODE_LIST_CLASS) : false; } function loadSettings() { currentSettings.bgColor1_rgb = GM_getValue(SCRIPT_ID_PREFIX + 'bgColor1_rgb', DEFAULT_SETTINGS.bgColor1_rgb); currentSettings.bgColor1_alpha = parseFloat(GM_getValue(SCRIPT_ID_PREFIX + 'bgColor1_alpha', DEFAULT_SETTINGS.bgColor1_alpha)); currentSettings.bgColor2_rgb = GM_getValue(SCRIPT_ID_PREFIX + 'bgColor2_rgb', DEFAULT_SETTINGS.bgColor2_rgb); currentSettings.bgColor2_alpha = parseFloat(GM_getValue(SCRIPT_ID_PREFIX + 'bgColor2_alpha', DEFAULT_SETTINGS.bgColor2_alpha)); currentSettings.enabled = GM_getValue(SCRIPT_ID_PREFIX + 'enabled', DEFAULT_SETTINGS.enabled); currentSettings.startFirstMessageOnNewLine = GM_getValue(SCRIPT_ID_PREFIX + 'startFirstMessageOnNewLine', DEFAULT_SETTINGS.startFirstMessageOnNewLine); currentSettings.useAlternatingBackgrounds = GM_getValue(SCRIPT_ID_PREFIX + 'useAlternatingBackgrounds', DEFAULT_SETTINGS.useAlternatingBackgrounds); } function saveSettings() { GM_setValue(SCRIPT_ID_PREFIX + 'bgColor1_rgb', currentSettings.bgColor1_rgb); GM_setValue(SCRIPT_ID_PREFIX + 'bgColor1_alpha', currentSettings.bgColor1_alpha); GM_setValue(SCRIPT_ID_PREFIX + 'bgColor2_rgb', currentSettings.bgColor2_rgb); GM_setValue(SCRIPT_ID_PREFIX + 'bgColor2_alpha', currentSettings.bgColor2_alpha); GM_setValue(SCRIPT_ID_PREFIX + 'enabled', currentSettings.enabled); GM_setValue(SCRIPT_ID_PREFIX + 'startFirstMessageOnNewLine', currentSettings.startFirstMessageOnNewLine); GM_setValue(SCRIPT_ID_PREFIX + 'useAlternatingBackgrounds', currentSettings.useAlternatingBackgrounds); } function hexToRgbString(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? `${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(result[3], 16)}` : null; } function rgbStringToHex(rgbString) { if (!rgbString) return "#000000"; const rgbArray = rgbString.split(',').map(Number); return "#" + rgbArray.map(x => { const hex = x.toString(16); return hex.length === 1 ? "0" + hex : hex; }).join(''); } function updateStyles() { if (!styleElement) { styleElement = document.createElement('style'); styleElement.id = SCRIPT_ID_PREFIX + 'dynamic_styles'; document.head.appendChild(styleElement); } if (!currentSettings.enabled) { styleElement.innerHTML = ''; // Clear styles if script is disabled return; } let css = ` .merged-message-wrapper .merged-message-content { display: block; padding: 1px 3px; margin: 0; border-radius: 3px; } .${CLASSIC_MODE_LIST_CLASS} .merged-message-wrapper > ${MESSAGE_BOX_SELECTOR} {} `; if (currentSettings.useAlternatingBackgrounds) { css += ` .merged-message-wrapper .merged-message-content:nth-child(odd) { background-color: rgba(${currentSettings.bgColor1_rgb}, ${currentSettings.bgColor1_alpha}); } .merged-message-wrapper .merged-message-content:nth-child(even) { background-color: rgba(${currentSettings.bgColor2_rgb}, ${currentSettings.bgColor2_alpha}); } `; } else { // Ensure no background is applied if option is off css += ` .merged-message-wrapper .merged-message-content:nth-child(odd), .merged-message-wrapper .merged-message-content:nth-child(even) { background-color: transparent !important; } `; } // Styles for newline option css += ` ${MESSAGE_BOX_SELECTOR} > span[class*="senderContainer___"] + .${NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS} { display: inline !important; margin-left: 0.3em; } .${NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS} > .merged-message-content:first-child { display: inline !important; } .${NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS} > .merged-message-content:not(:first-child) { display: block !important; } .${NO_NEWLINE_FIRST_CLASSIC_AGGREGATOR_CLASS} > .merged-message-content:first-child { display: inline !important; margin-left: 0.3em; } `; styleElement.innerHTML = css; } function toggleColorSettingsDisabledState(disabled) { const elementsToToggle = []; if (colorSetting1Div) elementsToToggle.push(colorSetting1Div); if (colorSetting2Div) elementsToToggle.push(colorSetting2Div); elementsToToggle.forEach(container => { container.style.opacity = disabled ? '0.5' : '1'; const inputs = container.querySelectorAll('input'); inputs.forEach(input => input.disabled = disabled); }); } function createSettingsUI() { const settingsPanelContent = document.querySelector(SETTINGS_PANEL_SELECTOR); if (!settingsPanelContent) return; const protoCheckboxLabel = settingsPanelContent.querySelector('label[class*="subtitle___"][class^="root___"]:has(input[type="checkbox"])'); const checkboxLabelClass = protoCheckboxLabel ? protoCheckboxLabel.className : 'abs-checkbox-label'; const protoSectionTitle = settingsPanelContent.querySelector(`span[class^="header___"]`); const sectionTitleClass = protoSectionTitle ? protoSectionTitle.className : 'abs-section-title'; const protoSettingsContainer = settingsPanelContent.querySelector(`div[class^="root___"]:has(span[class^="header___"])`); const settingsContainerClass = protoSettingsContainer ? protoSettingsContainer.className : 'abs-settings-block'; const generalSettingsSliderContainer = settingsPanelContent.querySelector('div[class*="panelSizeContainer___"] > div[class^="root___"]'); const sliderContainerClass = generalSettingsSliderContainer ? generalSettingsSliderContainer.className : 'abs-slider-container'; const protoSliderLabel = generalSettingsSliderContainer ? generalSettingsSliderContainer.querySelector(`label[class^="label___"]`) : null; const sliderLabelClass = protoSliderLabel ? protoSliderLabel.className : 'abs-slider-label'; const protoSliderInput = generalSettingsSliderContainer ? generalSettingsSliderContainer.querySelector(`input[type="range"][class^="range___"]`) : null; const sliderInputClass = protoSliderInput ? protoSliderInput.className : 'abs-slider-input'; const separator = document.createElement('div'); separator.style.height = '1px'; separator.style.backgroundColor = 'var(--chat-divider-color, #444)'; separator.style.margin = '15px 0'; const sectionTitleElement = document.createElement('span'); sectionTitleElement.className = sectionTitleClass; sectionTitleElement.textContent = 'Anti Bubble Spam Settings'; sectionTitleElement.style.display = 'block'; sectionTitleElement.style.marginBottom = '8px'; const settingsContainerElement = document.createElement('div'); settingsContainerElement.className = settingsContainerClass; settingsContainerElement.style.marginBottom = '15px'; const enableLabel = document.createElement('label'); enableLabel.className = checkboxLabelClass; enableLabel.style.display = 'flex'; enableLabel.style.alignItems = 'center'; enableLabel.style.marginBottom = '10px'; const enableCheckbox = document.createElement('input'); enableCheckbox.type = 'checkbox'; enableCheckbox.checked = currentSettings.enabled; enableCheckbox.id = SCRIPT_ID_PREFIX + 'enable_script'; enableCheckbox.style.marginRight = '8px'; enableCheckbox.addEventListener('change', (e) => { currentSettings.enabled = e.target.checked; saveSettings(); updateStyles(); // Update styles immediately processAllOpenChatLists(); // Re-process chats to apply/remove merging }); enableLabel.appendChild(enableCheckbox); enableLabel.append(' Enable Anti Bubble Spam'); settingsContainerElement.appendChild(enableLabel); const newLineLabel = document.createElement('label'); newLineLabel.className = checkboxLabelClass; newLineLabel.style.display = 'flex'; newLineLabel.style.alignItems = 'center'; newLineLabel.style.marginBottom = '10px'; const newLineCheckbox = document.createElement('input'); newLineCheckbox.type = 'checkbox'; newLineCheckbox.checked = currentSettings.startFirstMessageOnNewLine; newLineCheckbox.id = SCRIPT_ID_PREFIX + 'newLine_script'; newLineCheckbox.style.marginRight = '8px'; newLineCheckbox.addEventListener('change', (e) => { currentSettings.startFirstMessageOnNewLine = e.target.checked; saveSettings(); updateStyles(); processAllOpenChatLists(); }); newLineLabel.appendChild(newLineCheckbox); newLineLabel.append(' Start first message on new line'); settingsContainerElement.appendChild(newLineLabel); const altBgLabel = document.createElement('label'); altBgLabel.className = checkboxLabelClass; altBgLabel.style.display = 'flex'; altBgLabel.style.alignItems = 'center'; altBgLabel.style.marginBottom = '15px'; const altBgCheckbox = document.createElement('input'); altBgCheckbox.type = 'checkbox'; altBgCheckbox.checked = currentSettings.useAlternatingBackgrounds; altBgCheckbox.id = SCRIPT_ID_PREFIX + 'altBg_script'; altBgCheckbox.style.marginRight = '8px'; altBgCheckbox.addEventListener('change', (e) => { currentSettings.useAlternatingBackgrounds = e.target.checked; saveSettings(); updateStyles(); toggleColorSettingsDisabledState(!currentSettings.useAlternatingBackgrounds); }); altBgLabel.appendChild(altBgCheckbox); altBgLabel.append(' Use alternating background colors'); settingsContainerElement.appendChild(altBgLabel); function updateSliderBackground(slider) { const value = (slider.value - slider.min) / (slider.max - slider.min) * 100; slider.style.background = `linear-gradient(to right, var(--chat-range-progress-color-default) ${value}%, var(--chat-range-range-color) ${value}%, var(--chat-range-range-color) 100%)`; } function createColorSetting(idPrefix, labelText) { const mainSettingDiv = document.createElement('div'); mainSettingDiv.style.marginTop = '10px'; mainSettingDiv.style.display = 'flex'; mainSettingDiv.style.flexDirection = 'column'; mainSettingDiv.style.gap = '8px'; const colorRowDiv = document.createElement('div'); colorRowDiv.style.display = 'flex'; colorRowDiv.style.alignItems = 'center'; const colorLabel = document.createElement('label'); colorLabel.className = sliderLabelClass; colorLabel.textContent = labelText + ': '; colorLabel.style.minWidth = '160px'; colorLabel.style.marginRight = '5px'; const colorInput = document.createElement('input'); colorInput.type = 'color'; colorInput.value = rgbStringToHex(currentSettings[idPrefix + '_rgb']); colorInput.style.minWidth = '40px'; colorInput.style.height = '25px'; colorInput.style.padding = '0 2px'; colorInput.style.border = '1px solid #555'; colorInput.style.backgroundColor = '#333'; colorInput.addEventListener('input', (e) => { const rgb = hexToRgbString(e.target.value); if (rgb) { currentSettings[idPrefix + '_rgb'] = rgb; saveSettings(); updateStyles(); } }); colorRowDiv.appendChild(colorLabel); colorRowDiv.appendChild(colorInput); const alphaSliderDiv = document.createElement('div'); alphaSliderDiv.className = sliderContainerClass; const alphaLabelElement = document.createElement('label'); alphaLabelElement.className = sliderLabelClass; const updateAlphaLabelText = () => { alphaLabelElement.textContent = `Alpha (${(currentSettings[idPrefix + '_alpha'] * 100).toFixed(0)}%)`; }; updateAlphaLabelText(); const alphaSlider = document.createElement('input'); alphaSlider.type = 'range'; alphaSlider.min = '0'; alphaSlider.max = '1'; alphaSlider.step = '0.01'; alphaSlider.value = currentSettings[idPrefix + '_alpha']; alphaSlider.className = sliderInputClass; updateSliderBackground(alphaSlider); alphaSlider.addEventListener('input', (e) => { currentSettings[idPrefix + '_alpha'] = parseFloat(e.target.value); updateAlphaLabelText(); updateSliderBackground(e.target); saveSettings(); updateStyles(); }); alphaSliderDiv.appendChild(alphaLabelElement); alphaSliderDiv.appendChild(alphaSlider); mainSettingDiv.appendChild(colorRowDiv); mainSettingDiv.appendChild(alphaSliderDiv); return mainSettingDiv; } colorSetting1Div = createColorSetting('bgColor1', 'Background 1 (Odd)'); colorSetting2Div = createColorSetting('bgColor2', 'Background 2 (Even)'); settingsContainerElement.appendChild(colorSetting1Div); settingsContainerElement.appendChild(colorSetting2Div); toggleColorSettingsDisabledState(!currentSettings.useAlternatingBackgrounds); const messageStylingSection = Array.from(settingsPanelContent.children).find(child => child.querySelector('span[class*="header___"]')?.textContent.includes('Message Styling Settings') ); if (messageStylingSection) { settingsPanelContent.insertBefore(separator, messageStylingSection); settingsPanelContent.insertBefore(sectionTitleElement, messageStylingSection); settingsPanelContent.insertBefore(settingsContainerElement, messageStylingSection); } else { settingsPanelContent.appendChild(separator); settingsPanelContent.appendChild(sectionTitleElement); settingsContainerElement.appendChild(settingsContainerElement); } } function getSenderInfo(messageElement) { const classic = isClassicMode(messageElement); let isSelfMessage = false; if (classic) { if (messageElement.style.outlineColor === 'rgb(170, 0, 110)' || messageElement.style.outline.includes('rgb(170, 0, 110)')) { isSelfMessage = true; } } else { if (messageElement.className.includes(SELF_MESSAGE_CLASS_PART_BUBBLE)) { isSelfMessage = true; } } if (isSelfMessage) { return { id: 'self', nameElement: null, isSelf: true, classic: classic }; } let senderLinkElement; let nameElementContainer; const boxElement = messageElement.querySelector(MESSAGE_BOX_SELECTOR); if (!boxElement) return { id: 'other_unknown_nobox_' + Date.now() + Math.random(), nameElement: null, isSelf: false, classic: classic }; if (classic) { const senderSpan = boxElement.querySelector('span:first-child'); senderLinkElement = senderSpan ? senderSpan.querySelector('a[href*="profiles.php?XID="]') : null; nameElementContainer = senderSpan ? senderSpan.cloneNode(true) : null; } else { senderLinkElement = boxElement.querySelector(SENDER_LINK_SELECTOR); nameElementContainer = boxElement.querySelector(SENDER_CONTAINER_SELECTOR_BUBBLE)?.cloneNode(true); } if (senderLinkElement) { const href = senderLinkElement.getAttribute('href'); const match = href.match(/XID=(\d+)/); const senderId = match ? match[1] : senderLinkElement.textContent.trim().replace(':', ''); return { id: senderId, nameElement: nameElementContainer, isSelf: false, classic: classic }; } if (!classic) { const chatWindow = messageElement.closest('div[id^="private-"]'); if (chatWindow) { return { id: `other_private_${chatWindow.id}`, nameElement: null, isSelf: false, classic: classic }; } } return { id: 'other_unknown_' + Date.now() + Math.random(), nameElement: null, isSelf: false, classic: classic }; } function storeOriginalHTMLIfNotExists(messageElement) { if (!messageElement.hasAttribute(DATA_ORIGINAL_HTML_ATTR)) { const boxElement = messageElement.querySelector(MESSAGE_BOX_SELECTOR); if (!boxElement) { messageElement.setAttribute(DATA_ORIGINAL_HTML_ATTR, ''); return; } const messageTextParent = boxElement.querySelector(MESSAGE_TEXT_CONTAINER_SELECTOR); const rawHtml = messageTextParent ? messageTextParent.innerHTML : ''; messageElement.setAttribute(DATA_ORIGINAL_HTML_ATTR, rawHtml); } } function getMessageContents(messageElement) { const originalHtml = messageElement.getAttribute(DATA_ORIGINAL_HTML_ATTR); if (originalHtml === null || originalHtml.trim() === '') return null; const contentSpan = document.createElement('span'); contentSpan.className = 'merged-message-content'; contentSpan.innerHTML = originalHtml; return contentSpan; } function mergeGroup(group) { // Unmerging logic: Restore original HTML for each message in the group if (!currentSettings.enabled || !group || group.length < 2) { group.forEach(msgNode => { msgNode.style.display = ''; msgNode.classList.remove('merged-message-wrapper', 'self-merged', 'processed-by-antibubble'); const boxElement = msgNode.querySelector(MESSAGE_BOX_SELECTOR); if (boxElement) { const textAggregator = boxElement.querySelector(MESSAGE_TEXT_CONTAINER_SELECTOR); if (textAggregator) { textAggregator.classList.remove(NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS, NO_NEWLINE_FIRST_CLASSIC_AGGREGATOR_CLASS); const originalHtml = msgNode.getAttribute(DATA_ORIGINAL_HTML_ATTR); if (originalHtml !== null) { // Ensure attribute exists textAggregator.innerHTML = originalHtml; } } } }); return; } // Merging logic const firstMessageNode = group[0]; const senderInfo = getSenderInfo(firstMessageNode); firstMessageNode.classList.add('merged-message-wrapper'); if (senderInfo.isSelf) firstMessageNode.classList.add('self-merged'); let messageTextAggregator; const boxElement = firstMessageNode.querySelector(MESSAGE_BOX_SELECTOR); if (!boxElement) return; if (senderInfo.classic) { messageTextAggregator = boxElement.querySelector(MESSAGE_TEXT_CONTAINER_SELECTOR); if (!messageTextAggregator) { messageTextAggregator = document.createElement('span'); const bodySpan = boxElement.querySelector('span[class*="body___"]'); messageTextAggregator.className = bodySpan ? bodySpan.className.replace(/body___[^ ]+/, 'message___') : 'message___'; messageTextAggregator.classList.add('abs-classic-text-aggregator-fallback'); boxElement.appendChild(messageTextAggregator); } messageTextAggregator.classList.remove(NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS); if (!currentSettings.startFirstMessageOnNewLine) { messageTextAggregator.classList.add(NO_NEWLINE_FIRST_CLASSIC_AGGREGATOR_CLASS); } else { messageTextAggregator.classList.remove(NO_NEWLINE_FIRST_CLASSIC_AGGREGATOR_CLASS); } } else { if (!senderInfo.isSelf && senderInfo.nameElement) { const existingSenderContainer = boxElement.querySelector(SENDER_CONTAINER_SELECTOR_BUBBLE); if (existingSenderContainer) existingSenderContainer.classList.add('merged-sender-name'); } messageTextAggregator = boxElement.querySelector(MESSAGE_TEXT_CONTAINER_SELECTOR); if (!messageTextAggregator) { messageTextAggregator = document.createElement(senderInfo.isSelf ? 'p' : 'span'); const bodyElement = boxElement.querySelector('p[class*="body___"], span[class*="body___"]'); messageTextAggregator.className = bodyElement ? bodyElement.className.replace(/body___[^ ]+/, 'message___') : 'message___'; messageTextAggregator.classList.add('abs-bubble-text-aggregator-fallback'); boxElement.appendChild(messageTextAggregator); } messageTextAggregator.classList.remove(NO_NEWLINE_FIRST_CLASSIC_AGGREGATOR_CLASS); if (!currentSettings.startFirstMessageOnNewLine && !senderInfo.isSelf) { messageTextAggregator.classList.add(NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS); } else { messageTextAggregator.classList.remove(NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS); } } if (!messageTextAggregator) return; messageTextAggregator.innerHTML = ''; group.forEach((msgNodeInGroup) => { storeOriginalHTMLIfNotExists(msgNodeInGroup); const contentSpan = getMessageContents(msgNodeInGroup); if (contentSpan) { messageTextAggregator.appendChild(contentSpan); } }); for (let k = 0; k < group.length; k++) { if (k > 0) group[k].style.display = 'none'; group[k].classList.add('processed-by-antibubble'); } } function processMessagesInList(messageListElement) { // --- RESET PHASE --- Array.from(messageListElement.children).forEach(child => { if (child.matches(MESSAGE_ROOT_SELECTOR)) { child.style.display = ''; child.classList.remove('merged-message-wrapper', 'self-merged', 'processed-by-antibubble'); const boxElement = child.querySelector(MESSAGE_BOX_SELECTOR); if (boxElement) { const textContainer = boxElement.querySelector(MESSAGE_TEXT_CONTAINER_SELECTOR); if (textContainer) { textContainer.classList.remove(NO_NEWLINE_FIRST_BUBBLE_AGGREGATOR_CLASS, NO_NEWLINE_FIRST_CLASSIC_AGGREGATOR_CLASS); const originalHtml = child.getAttribute(DATA_ORIGINAL_HTML_ATTR); if (originalHtml !== null) { textContainer.innerHTML = originalHtml; } } } } }); if (!currentSettings.enabled) { updateStyles(); return; } // --- END RESET PHASE --- Array.from(messageListElement.children).forEach(child => { if (child.matches(MESSAGE_ROOT_SELECTOR)) storeOriginalHTMLIfNotExists(child); }); const children = Array.from(messageListElement.children); let lastSenderId = null; let currentMessageGroup = []; for (let i = 0; i < children.length; i++) { const currentElement = children[i]; if (currentElement.style.display === 'none' && currentElement.classList.contains('processed-by-antibubble')) continue; if (!currentElement.matches(MESSAGE_ROOT_SELECTOR) || currentElement.matches(TIMESTAMP_DIVIDER_SELECTOR)) { if (currentMessageGroup.length > 0) mergeGroup(currentMessageGroup); currentMessageGroup = []; lastSenderId = null; continue; } const senderInfo = getSenderInfo(currentElement); if (senderInfo.id && senderInfo.id === lastSenderId) { currentMessageGroup.push(currentElement); } else { if (currentMessageGroup.length > 0) mergeGroup(currentMessageGroup); currentMessageGroup = [currentElement]; lastSenderId = senderInfo.id; } } if (currentMessageGroup.length > 0) mergeGroup(currentMessageGroup); updateStyles(); } function processAllOpenChatLists() { const chatRootElement = document.getElementById(CHAT_ROOT_ID); if (chatRootElement) { const allLists = chatRootElement.querySelectorAll(MESSAGE_LIST_SELECTOR); allLists.forEach(list => processMessagesInList(list)); } } const observerCallback = (mutationsList) => { if (!currentSettings.enabled) return; let listsToReProcess = new Set(); for (const mutation of mutationsList) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { mutation.addedNodes.forEach(addedNode => { if (addedNode.nodeType === Node.ELEMENT_NODE) { if (addedNode.matches(MESSAGE_ITEM_SELECTOR) || addedNode.querySelector(MESSAGE_LIST_SELECTOR)) { const lists = addedNode.querySelectorAll(MESSAGE_LIST_SELECTOR); lists.forEach(list => listsToReProcess.add(list)); } else if (addedNode.matches(MESSAGE_ROOT_SELECTOR)) { const parentList = addedNode.closest(MESSAGE_LIST_SELECTOR); if (parentList) listsToReProcess.add(parentList); } } }); } } if (listsToReProcess.size > 0) { setTimeout(() => { listsToReProcess.forEach(list => { processMessagesInList(list); if (!list.dataset.antibubbleObserved) { observeMessageList(list); list.dataset.antibubbleObserved = 'true'; } }); }, 200); } }; function observeMessageList(listElement) { const listObserver = new MutationObserver(() => { if (!currentSettings.enabled) return; setTimeout(() => processMessagesInList(listElement), 200); }); listObserver.observe(listElement, { childList: true }); } function initialize() { loadSettings(); updateStyles(); const settingsPanelObserver = new MutationObserver(() => { const panel = document.querySelector(SETTINGS_PANEL_SELECTOR); if (panel) { if (!document.getElementById(SCRIPT_ID_PREFIX + 'enable_script')) { createSettingsUI(); } } }); const chatRootForPanel = document.getElementById(CHAT_ROOT_ID) || document.body; settingsPanelObserver.observe(chatRootForPanel, { childList: true, subtree: true }); const chatRootElement = document.getElementById(CHAT_ROOT_ID); if (!chatRootElement) { setTimeout(initialize, 1000); return; } processAllOpenChatLists(); const existingMessageLists = chatRootElement.querySelectorAll(MESSAGE_LIST_SELECTOR); existingMessageLists.forEach(list => { if (!list.dataset.antibubbleObserved) { observeMessageList(list); list.dataset.antibubbleObserved = 'true'; } }); const mainObserver = new MutationObserver(observerCallback); mainObserver.observe(chatRootElement, { childList: true, subtree: true }); } if (document.readyState === "complete" || document.readyState === "interactive") { initialize(); } else { window.addEventListener('DOMContentLoaded', initialize); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址