您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Blurs sensitive information to protect your privacy on grok.com.
// ==UserScript== // @name Grok Streamer Mode // @namespace http://tampermonkey.net/ // @version 1.0 // @description Blurs sensitive information to protect your privacy on grok.com. // @author Ported by Blanklspeaker, Adapted from original plugin by Prism (https://github.com/imjustprism/Grokness) // @match https://grok.com/* // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @license MIT // ==/UserScript== (function() { 'use strict'; const logger = { error: (...args) => console.error('[StreamerMode]', ...args) }; let styleElement = null; const baseStyles = ` .streamer-mode-active img.aspect-square.h-full.w-full[alt="pfp"] { filter: blur(8px) !important; } .streamer-mode-active .sidebar-user-info .display-name, .streamer-mode-active [data-sidebar="menu"] .group\\/conversation-item span.flex-1.select-none, .streamer-mode-active span.flex-1.select-none.text-nowrap.max-w-full.overflow-hidden.inline-block { filter: blur(5px) !important; padding: 0 4px !important; margin: 0 -4px !important; display: inline-block !important; width: calc(100% + 8px) !important; position: relative !important; } .streamer-mode-active .p-1.min-w-0.text-sm .text-sm.font-medium, .streamer-mode-active .p-1.min-w-0.text-sm .text-secondary.truncate { filter: blur(5px) !important; padding: 0 4px !important; margin: 0 -4px !important; display: inline-block !important; width: calc(100% + 8px) !important; position: relative !important; } .streamer-mode-active div.text-xs.flex.flex-row.gap-1.p-3.text-secondary.opacity-30 { filter: blur(5px) !important; padding: 0 4px !important; margin: 0 -4px !important; display: inline-block !important; width: calc(100% + 8px) !important; position: relative !important; } .streamer-mode-active #grok-feature-flags-menu-item { filter: blur(5px) !important; } `; function getDynamicStyles(emailOnly) { if (emailOnly) { return ` html.streamer-mode-active .p-1.min-w-0.text-sm .text-secondary.truncate { filter: blur(5px) !important; padding: 0 4px !important; margin: 0 -4px !important; display: inline-block !important; width: calc(100% + 8px) !important; position: relative !important; } html.streamer-mode-active div.text-xs.flex.flex-row.gap-1.p-3.text-secondary.opacity-30 { filter: blur(5px) !important; padding: 0 4px !important; margin: 0 -4px !important; display: inline-block !important; width: calc(100% + 8px) !important; position: relative !important; } `; } return baseStyles.replace(/\.streamer-mode-active/g, 'html.streamer-mode-active'); } function updateStylesheetAndClass() { try { const isEnabled = GM_getValue('enabled', true); const emailOnly = GM_getValue('emailOnly', false); if (styleElement) { styleElement.remove(); styleElement = null; } document.documentElement.classList.remove('streamer-mode-active'); let dynamicStyles = ''; if (emailOnly) { dynamicStyles = getDynamicStyles(true); document.documentElement.classList.add('streamer-mode-active'); } else if (isEnabled) { dynamicStyles = getDynamicStyles(false); document.documentElement.classList.add('streamer-mode-active'); } if (dynamicStyles) { styleElement = GM_addStyle(dynamicStyles); } } catch (err) { logger.error('Failed to update stylesheet or class:', err); } } function createToggle(initialChecked, labelId) { const button = document.createElement('button'); button.type = 'button'; button.role = 'switch'; button.className = 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-[1px] border-transparent transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background ring-card-border ring-1 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-dove dark:data-[state=checked]:bg-ivory dark:data-[state=unchecked]:bg-button-secondary-selected'; button.value = 'on'; if (labelId) { button.setAttribute('aria-labelledby', labelId); } const span = document.createElement('span'); span.className = 'pointer-events-none block h-4 w-4 rounded-full bg-white dark:bg-background shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0 ms-0.5 data-[state=checked]:translate-x-5 rtl:data-[state=checked]:-translate-x-5 dark:data-[state=unchecked]:bg-overlay'; button.appendChild(span); function setChecked(checked) { button.setAttribute('aria-checked', checked ? 'true' : 'false'); button.dataset.state = checked ? 'checked' : 'unchecked'; span.dataset.state = checked ? 'checked' : 'unchecked'; } setChecked(initialChecked); button.addEventListener('click', () => { const current = button.getAttribute('aria-checked') === 'true'; setChecked(!current); }); return button; } function injectSettings() { const targetLabelText = 'Show Conversation Previews in History'; const observer = new MutationObserver((mutations) => { const labels = document.querySelectorAll('div.text-sm.font-medium'); for (let label of labels) { if (label.innerText.trim() === targetLabelText) { const labelWrapper = label.parentElement; // max-w-sm min-w-0 const previewRow = labelWrapper.parentElement; // flex flex-row ... if (previewRow && !document.getElementById('streamer-mode-row')) { const container = previewRow.parentElement; // flex-col gap-6 // Create row for Streamer Mode const streamerRow = document.createElement('div'); streamerRow.className = previewRow.className; streamerRow.id = 'streamer-mode-row'; const streamerLabelWrapper = document.createElement('div'); streamerLabelWrapper.className = labelWrapper.className; const streamerLabelId = 'streamer-mode-label'; streamerLabelWrapper.id = streamerLabelId; const streamerLabel = document.createElement('div'); streamerLabel.className = 'text-sm font-medium'; streamerLabel.innerText = 'Streamer Mode'; streamerLabelWrapper.appendChild(streamerLabel); streamerRow.appendChild(streamerLabelWrapper); const streamerToggleWrapper = document.createElement('div'); streamerToggleWrapper.className = 'text-right min-w-24'; const streamerToggle = createToggle(GM_getValue('enabled', true), streamerLabelId); streamerToggle.addEventListener('click', () => { const checked = streamerToggle.getAttribute('aria-checked') === 'true'; GM_setValue('enabled', checked); updateStylesheetAndClass(); }); streamerToggleWrapper.appendChild(streamerToggle); streamerRow.appendChild(streamerToggleWrapper); container.insertBefore(streamerRow, previewRow.nextSibling); // Create row for Blur Email Only const emailRow = document.createElement('div'); emailRow.className = previewRow.className; emailRow.id = 'email-only-row'; const emailLabelWrapper = document.createElement('div'); emailLabelWrapper.className = labelWrapper.className; const emailLabelId = 'email-only-label'; emailLabelWrapper.id = emailLabelId; const emailLabel = document.createElement('div'); emailLabel.className = 'text-sm font-medium'; emailLabel.innerText = 'Blur Email Only'; emailLabelWrapper.appendChild(emailLabel); emailRow.appendChild(emailLabelWrapper); const emailToggleWrapper = document.createElement('div'); emailToggleWrapper.className = 'text-right min-w-24'; const emailToggle = createToggle(GM_getValue('emailOnly', false), emailLabelId); emailToggle.addEventListener('click', () => { const checked = emailToggle.getAttribute('aria-checked') === 'true'; GM_setValue('emailOnly', checked); updateStylesheetAndClass(); }); emailToggleWrapper.appendChild(emailToggle); emailRow.appendChild(emailToggleWrapper); container.insertBefore(emailRow, streamerRow.nextSibling); } } } }); observer.observe(document.body, { childList: true, subtree: true }); } // Run the update function and inject settings if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { updateStylesheetAndClass(); injectSettings(); }, { once: true }); } else { updateStylesheetAndClass(); injectSettings(); } // Expose functions to toggle and configure via console window.toggleStreamerMode = function() { const currentEnabled = GM_getValue('enabled', true); GM_setValue('enabled', !currentEnabled); updateStylesheetAndClass(); console.log('[StreamerMode] Enabled:', !currentEnabled); }; window.setStreamerModeEmailOnly = function(value) { GM_setValue('emailOnly', !!value); updateStylesheetAndClass(); console.log('[StreamerMode] Email Only:', !!value); }; console.log('[StreamerMode] Loaded. Use toggleStreamerMode() in console to toggle on/off. Use setStreamerModeEmailOnly(true/false) to toggle blurring only email.'); })();